FIX: sửa lỗi khi quét chọn duration để loop và khi bật nút loop thì tự động giãn ra bar 18

This commit is contained in:
2026-08-03 19:41:42 +07:00
parent 8c1a8ead56
commit ec5fedec33
4 changed files with 48 additions and 21 deletions
+27 -17
View File
@@ -17610,6 +17610,9 @@ const App = () => {
setSelectedTrackId(trackId); setSelectedTrackId(trackId);
captureSelectionUndo(); captureSelectionUndo();
clearLocalSelection(); clearLocalSelection();
// A fresh region selection re-enables selection-looping (a previous
// Ctrl+click "clear selection" must not keep blocking the new region).
setSelectionCleared(false);
localSelectionAnchorRef.current = time; localSelectionAnchorRef.current = time;
setSelectionMode('local'); setSelectionMode('local');
setLocalSelectionTrackId(trackId); setLocalSelectionTrackId(trackId);
@@ -22525,24 +22528,31 @@ const App = () => {
setSubTabs(prev => prev.map(s => s.id === activeTab ? { ...s, selectionStart: 0, selectionEnd: loopEndTime } : s)); setSubTabs(prev => prev.map(s => s.id === activeTab ? { ...s, selectionStart: 0, selectionEnd: loopEndTime } : s));
} }
} else { } else {
// Main timeline: auto-derive loop end from tracks // Main timeline / section tab: if the user already selected a loop
const bpmVal = parseInt(bpm) || 120; // region, KEEP it only auto-derive (0 content end) when no
const secPerBar = (60.0 / bpmVal) * 4; // selection exists yet. Previously this always overwrote the
let maxEnd = 0; // selection with 0 (contentEnd + 2 bars).
activeTracks.forEach(t => { const hasSel = (selectionMode === 'local' && selLeft !== null && selRight !== null && selRight > selLeft)
(t.clips || []).forEach(c => { || (selectionStart !== null && selectionEnd !== null && selectionEnd > selectionStart);
const end = (c.startTime || 0) + (c.duration || 0); if (!hasSel) {
if (end > maxEnd) maxEnd = end; const bpmVal = parseInt(bpm) || 120;
const secPerBar = (60.0 / bpmVal) * 4;
let maxEnd = 0;
activeTracks.forEach(t => {
(t.clips || []).forEach(c => {
const end = (c.startTime || 0) + (c.duration || 0);
if (end > maxEnd) maxEnd = end;
});
(t.items || []).forEach(it => {
const end = (it.start || 0) + (it.duration || 4);
if (end > maxEnd) maxEnd = end;
});
}); });
(t.items || []).forEach(it => { if (maxEnd > 0) {
const end = (it.start || 0) + (it.duration || 4); const loopEnd = maxEnd + secPerBar * 2;
if (end > maxEnd) maxEnd = end; setSelectionStart(0);
}); setSelectionEnd(loopEnd);
}); }
if (maxEnd > 0) {
const loopEnd = maxEnd + secPerBar * 2;
setSelectionStart(0);
setSelectionEnd(loopEnd);
} }
} }
}, },
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -24,7 +24,7 @@
<script src="/static/js/services/midiExtractor.js?v=202607281052"></script> <script src="/static/js/services/midiExtractor.js?v=202607281052"></script>
<script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script> <script src="/static/js/services/promptTemplateManager.js?v=202607281039"></script>
<script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script> <script src="/static/js/services/undoRedoEngine.js?v=202607290941"></script>
<script src="/static/js/app.precompiled.js?v=202608033000" defer></script> <script src="/static/js/app.precompiled.js?v=202608033200" defer></script>
<link rel="stylesheet" href="/static/css/styles.css?v=202607271016"> <link rel="stylesheet" href="/static/css/styles.css?v=202607271016">
<style> <style>
:root { :root {
+12
View File
@@ -1,3 +1,15 @@
### [2026-08-03] Task: Loop vẫn giãn selection tới bar 18 — mở rộng hasSel + verify bundle serve
- **Tóm tắt thay đổi:** User báo vẫn lỗi sau fix trước. Kiểm tra toàn diện: (1) Không có path nào khác giãn selection khi loop bật (SubTabToolbar/onLoop là code chết; toggleLoop là Media Explorer preview; useEffect BPM chỉ chạy khi đổi tempo). (2) Mở rộng điều kiện `hasSel` trong handler nút loop: ngoài `selectionMode==='local'`, còn nhận selection qua `selectionStart/selectionEnd` hợp lệ (phòng trường hợp sweep không set 'local'). (3) **Verify bằng server thật** (uvicorn 9131): file `app.precompiled.js?v=202608033200` được serve có chứa `hasSel=selectionMode===` + comment fix — chứng minh bundle workspace đã đúng. Nếu user vẫn thấy lỗi → trình duyệt cache hoặc đang chạy deployment khác (không phải workspace).
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608033200; sửa double `</script>` phát sinh khi bump)
- **Ghi chú/Test (nếu có):** `pytest` 86 passed (chưa chạy lại lần này — chỉ đổi frontend).
---
### [2026-08-03] Task: Fix loop button ghi đè vùng chọn thành 0→18 bar (MAIN SESSION/SECTION-TAB)
- **Tóm tắt thay đổi:** Khi quét chọn vùng duration rồi bấm nút loop, vùng chọn bị tự đổi thành 0→18 bar. Nguyên nhân: handler nút loop (nhánh main timeline, không có sub-tab active) LUÔN tự derive loop end từ content tracks (`maxEnd + 2 bar` — content 16 bar → 18) rồi `setSelectionStart(0); setSelectionEnd(loopEnd)` — ghi đè vùng chọn của user. Fix: **tôn trọng selection có sẵn** (`hasSel = selectionMode==='local' && selLeft/selRight hợp lệ`) — chỉ auto-derive khi CHƯA có vùng chọn nào. Áp dụng cho cả MAIN SESSION lẫn SECTION-TAB (cả 2 đều đi qua nhánh main timeline khi không có sub-tab; section-tab dùng chung selection handler nên sweep cũng set `selectionMode='local'`). Kèm theo: `handleTrackLaneMouseDown` giờ `setSelectionCleared(false)` khi bắt đầu chọn vùng mới — nếu user từng Ctrl+click xoá chọn thì vùng mới vẫn loop được.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608033100)
- **Ghi chú/Test (nếu có):** `node build.mjs` OK, syntax OK, `pytest` 86 passed.
---
### [2026-08-03] Task: Fix React error #310 khi mở Mixer modal (hooks sau early return) ### [2026-08-03] Task: Fix React error #310 khi mở Mixer modal (hooks sau early return)
- **Tóm tắt thay đổi:** Sau fix `isFxActive`, mở Mixer modal vẫn lỗi `Minified React error #310` ("Rendered more hooks than during the previous render"). Nguyên nhân: khi thêm dynamic module chain, 2 hooks `dragChainIndexRef` (useRef) + `addModuleOpen` (useState) được khai báo SAU dòng `if (!isOpen) return null;` trong MasteringModal → số hooks giữa các render thay đổi khi modal đóng/mở (return null sớm bỏ qua 2 hooks) → React #310. Fix: di chuyển 2 hooks lên TRƯỚC early return (cạnh useEffect [isOpen]). - **Tóm tắt thay đổi:** Sau fix `isFxActive`, mở Mixer modal vẫn lỗi `Minified React error #310` ("Rendered more hooks than during the previous render"). Nguyên nhân: khi thêm dynamic module chain, 2 hooks `dragChainIndexRef` (useRef) + `addModuleOpen` (useState) được khai báo SAU dòng `if (!isOpen) return null;` trong MasteringModal → số hooks giữa các render thay đổi khi modal đóng/mở (return null sớm bỏ qua 2 hooks) → React #310. Fix: di chuyển 2 hooks lên TRƯỚC early return (cạnh useEffect [isOpen]).
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608032900) - **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608032900)