From f91bf8715d974d44d21b0a7280c29f59064db0ca Mon Sep 17 00:00:00 2001 From: gramps Date: Fri, 18 Sep 2026 10:20:25 -0700 Subject: [PATCH] =?UTF-8?q?fix(reorder):=20save=20layer=20list=20AND=20pre?= =?UTF-8?q?view=20layout=20immediately=20at=20drop;=20recording=20save=20d?= =?UTF-8?q?ialog=20+10%=20(276=E2=86=92304)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- HANDOFF.md | 35 ++++++++++------ MyMistakes.md | 22 ++++++++++ RenameRecordingDialog.xaml | 4 +- ViewModels/MainViewModel.Sources.cs | 7 +++- ytLive.Tests/LayerReorderPersistenceTests.cs | 42 +++++++++++++++++-- .../RenameRecordingDialogSizingTests.cs | 27 ++++++++---- 6 files changed, 107 insertions(+), 30 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index b983dad..8ee4db8 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -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 diff --git a/MyMistakes.md b/MyMistakes.md index 048113b..5d9c848 100644 --- a/MyMistakes.md +++ b/MyMistakes.md @@ -36,6 +36,28 @@ one rejected call inside a fallback ladder aborts the whole ladder and every unt Applied in `MediaCaptureFrameSource`'s reader-subtype ladder (2026-09-15, webcam-take fix). +### "SAVE-RECORDING DIALOG IS CLIPPING CONTENT" — WHERE + HOW (RECIPE) + +**WHERE:** the end-of-recording modal (creator: "when I end a recording the app throws up a +save-recording dialog with a default filename") is **`RenameRecordingDialog.xaml` at the repo ROOT** +(title "Rename Recording", `x:Class="ytLive.RenameRecordingDialog"`). It is NOT one of the +`*Dialog.xaml` files under `Controls/` — grep for the window title, not the filename, when the +user names a dialog by what it does. Only fix dialogs the user actually named; do not "while I'm +here" bump sibling dialogs. + +**HOW:** the dialog is `ResizeMode="NoResize"` with a fixed `Height` attribute; content client area +≈ `Height − ~37px` of window chrome. Sizing/margin changes pushed content down in Z-order until it +clipped — first the file-name textbox (230 too short), and after the +20% bump (→276) the creator +found the Cancel/Save button row had ALSO been obscured. Fixed `Height` to 304 (+10% more), +`x:Name` the last interactive control (`SaveRecordingButton`) so a test can measure it. + +**Verify (never eyeball-predict):** `RenameRecordingDialogSizingTests` (RealApp host) instantiates +the real dialog, `Show()` + `UpdateLayout()`, then asserts the BOTTOM EDGE of each named control +(`TransformToAncestor` against the content root → `TransformBounds(RenderSize).Bottom`) is ≤ the +client `ActualHeight`. Every such dialog fix ships with that assertion for every control that was +reported obscured. (Client-area math means the button row needs MORE slack than the textbox: its +bottom sits deeper because of the `Margin="0,20,0,0"` above it.) + ### SPIN GUARD → RESOLVED — web overlay transparency + bounding box (RECIPE) **THE ONE ROOT CAUSE THAT EXPLAINS EVERY FAILED TAKE:** WebView2's `CapturePreviewAsync` diff --git a/RenameRecordingDialog.xaml b/RenameRecordingDialog.xaml index 763f8b3..a673e6a 100644 --- a/RenameRecordingDialog.xaml +++ b/RenameRecordingDialog.xaml @@ -1,7 +1,7 @@ @@ -32,7 +32,7 @@ Margin="0,20,0,0">