fix(reorder): save layer list AND preview layout immediately at drop; recording save dialog +10% (276→304)
Reorder: OnSceneElementsReordered now calls SaveLayoutNow() (was debounced ScheduleSave) so a drag-drop persists instantly — one write stores the new layer list (Source.SortOrder) and each layer's preview geometry (X/Y/W/H) in the same rows. Reference: WPF ListBox drag-reorder requires an explicit persist at drop; a debounce window lets a crash lose the drop. Recording save dialog (RenameRecordingDialog.xaml): height 276→304 so the Cancel/Save button row is no longer obscured; Save button named SaveRecordingButton so the sizing test can assert it sits inside the client area. Tests: deterministic seam test now asserts the dragged layer's geometry (preview layout) is persisted with the new order; sizing test asserts 304 + textbox and button-row bottoms within client area. 308/308 green.
This commit is contained in:
+22
-13
@@ -55,31 +55,40 @@ the availability layer. TASK 26's app-wide gate is **superseded** by creator dir
|
||||
|
||||
## ✅ Committed — layer-list drag-to-reorder persists (creator-reported, 2026-09-18)
|
||||
|
||||
The drag code in `Controls/LeftPanel.xaml.cs` reordered `StagedScene.Elements` directly
|
||||
(`RemoveAt`/`Insert` in `List_PreviewMouseMove`), bypassing `SceneGraph`'s mutation surface — the
|
||||
collection changed visually but nothing ever scheduled a save, so the new z-order was lost on
|
||||
restart. Fix: the drag sets `_dragReordered` and `EndListDrag` funnels the drop through the new
|
||||
`MainViewModel.OnSceneElementsReordered()` (Sources.cs) = `SceneGraph.InvalidateBake(staged) +
|
||||
ScheduleSave()`, i.e. the same background-save path every other mutation uses. **Good Dog test**
|
||||
`LayerReorderPersistenceTests` (real App + temp DB): reproduces the exact code-behind mutation,
|
||||
calls the trap, pumps the dispatcher until the debounced save lands, asserts the DB `Source`
|
||||
`StagedScene.Elements` order (RemoveAt/Insert), bypassing SceneGraph's mutation surface, so the
|
||||
drop must be trapped and persisted. Fix (c117885): the drag sets `_dragReordered` and, on mouse
|
||||
release, `EndListDrag` funnels the drop through `MainViewModel.OnSceneElementsReordered()`
|
||||
(Sources.cs) = `SceneGraph.InvalidateBake(staged) + SaveLayoutNow()` — an IMMEDIATE save at drop
|
||||
(no debounce window, added 2026-09-18 after the creator re-reported it "doesn't save"; the single
|
||||
write stores BOTH the **layer list** = Source `SortOrder` AND the **preview layout** = each layer's
|
||||
`X`/`Y`/`Width`/`Height` in the same Source rows; `LayoutStore.Save` deletes+reinserts Source rows
|
||||
in `scene.Elements` order, `LayoutStore.Load` reads them back `ORDER BY SortOrder`).
|
||||
**Good Dog tests** `LayerReorderPersistenceTests` (real App + temp DB): (1) reproduces the exact
|
||||
code-behind mutation
|
||||
calls the trap, pumps the dispatcher until the save lands, asserts the DB `Source`
|
||||
SortOrder matches the in-memory `Elements` order.
|
||||
**Creator later insisted the reorder "doesn't save" even after the build — settled 2026-09-18 with a
|
||||
REAL-gesture test.** My first test short-circuited `EndListDrag` — it never exercised the mouse
|
||||
handlers (impossible with synthetic events: `e.GetPosition` reads the physical cursor). Added
|
||||
`RealMouseDrag_OnTheLayerList_PersistsTheReorder`: real `SetCursorPos` + `mouse_event`/`SendInput`
|
||||
against the shown MainWindow physically drag row 3 (ImgC) onto row 1 (ImgA), pumping between steps,
|
||||
then asserts the DB lands at `[Background, ImgC, ImgA, ImgB]` via the debounced save. **Both pass.**
|
||||
then asserts the DB lands at `[Background, ImgC, ImgA, ImgB]` — AND that ImgC's geometry
|
||||
(X/Y/W/H, the preview layout) is intact in the same rows. **Both pass.**
|
||||
The mouse-down/move/up → `_dragReordered` → `EndListDrag` → `OnSceneElementsReordered` → DB seam is
|
||||
now proven with real input; a real user drag working differently would mean a stale binary (the
|
||||
Debug exe from 08:42 postdates fix commit 08:18) or a different deployment.
|
||||
|
||||
## ✅ Committed — Rename Recording dialog taller + full-screen hook unhooked on shutdown (2026-09-18)
|
||||
|
||||
- `RenameRecordingDialog.xaml` `Height` 230 → **276** (+20%, creator: textbox cut off). The fix is
|
||||
real: content naturally needs ~225px, the old client area at 230 was ~193px (clipped), at 276 it's
|
||||
~239px (fits). **Good Dog test** `RenameRecordingDialogSizingTests`: shows the real dialog in the
|
||||
RealApp host and asserts the file-name textbox bottom edge is inside the client area. The dialog's
|
||||
- **WHERE/HOW:** the end-of-recording save dialog is `RenameRecordingDialog.xaml` (repo root — the
|
||||
dialog that pops up with a default file name when a recording is ended so it can be saved/renamed;
|
||||
title "Rename Recording"). Its fixed `Height` attribute controls everything: 230 → **276** (+20%,
|
||||
textbox clipped at 230) → **304** (+10% more, creator: the +20% revealed the Cancel/Save button
|
||||
row had ALSO been obscured). The Save button is named `SaveRecordingButton`.
|
||||
**Good Dog test** `RenameRecordingDialogSizingTests`: shows the real dialog in the RealApp host and
|
||||
asserts BOTH the file-name textbox bottom AND the Save button bottom sit inside the client area
|
||||
(client area ≈ Height − ~37px of chrome; measure via `TransformToAncestor` against the dialog's
|
||||
content root). The dialog's
|
||||
`Icon` was changed from root-relative `/Assets/...` to the explicit `/ytLive;component/...` (the
|
||||
form `MainWindow.xaml` already uses) — root-relative only resolves in production via
|
||||
`Application.ResourceAssembly`, so dialogs couldn't be constructed by tests otherwise. The other
|
||||
|
||||
Reference in New Issue
Block a user