TASK 7 UI polish batch: scene/source row cleanup, dedup naming, full social handles — scenes are now pure selection rows (edit/trash/visibility icons and inline rename removed with EditSceneCommand/RemoveSceneCommand/ToggleSceneVisibilityCommand + Scene.IsEditing); source rows gained the trio (new EditElementCommand → inline rename via SceneElement.IsEditing, ToggleElementVisibilityCommand → eye flips IsVisible, open/slashed style rebound, hidden rows dim to 45%); duplicate resource names get a no-space incrementing suffix via shared NextSourceName (Image, Image2, Image3…) derived from actual names so deletions never collide (AddSource + AddReusedImage); social bar renders the full validated handle (MaxWidth=200 + TextTrimming removed from SocialBarRenderer and the preview template); side panels stay fixed 220/300; focus-loss capture lag documented in ai.md as a known OS limit (deferred) — the two real-App tests now share RealAppHost, a dedicated STA thread owning the single WPF App, instead of each calling new App(); new SourceNamingTests integration test (Text/Text2/Text3, delete-middle re-add no-collision) — 170 tests passing, 0 warnings
This commit is contained in:
+47
-37
@@ -7,34 +7,39 @@
|
||||
|
||||
## Session state (last updated: 2026-08-13)
|
||||
|
||||
- **Branch:** `main`. The audio UX follow-up (`9f9ed34`), round 2 (`18abe42`),
|
||||
and round 3 (`dc29adf`) are **committed and pushed**.
|
||||
- **This session (TASK 4 ship step 6 — health stats in the bottom bar):**
|
||||
1. **Wiring:** `MainViewModel.OnFramePumpHealthUpdated` subscribes to
|
||||
`FramePump.HealthUpdated` and marshals onto the UI thread (the encoder's
|
||||
stderr loop raises on a background thread — same pattern as the audio
|
||||
level handlers), copying the parsed bitrate/FPS/dropped/duration into
|
||||
`CurrentHealth`, which the bottom bar's left stats group already binds
|
||||
(bitrate/FPS/dropped/duration/health-message).
|
||||
2. **Session hygiene:** `ResetHealth(status)` zeroes dropped frames + the
|
||||
elapsed duration (and clears `LastError`) on go-live and on End so stats
|
||||
never linger from a previous stream; bitrate/FPS stay on the tier's
|
||||
targets from `ApplyStreamQuality`.
|
||||
3. **Reality:** the bar lights up with REAL encoder values once TASK 5 fills
|
||||
`_rtmpUrlProvider` with the reusable stream's ingest URL — until then the
|
||||
pump skips the encoder (logged) and the bar shows the tier's targets.
|
||||
No new tests needed: `FramePumpTests.HealthUpdated_ForwardsEncoderHealth`
|
||||
already covers the pump→event seam; the VM handler is a thin marshal+copy.
|
||||
- **Mic status contract (creator's rule, verified — do NOT "fix"):** the status dot is
|
||||
**red until a mic resource is actually connected**. `MicStatus` starts `NotConnected`
|
||||
(red); it goes green ONLY when the mixer's `MicConnected` fires, which comes strictly
|
||||
from the mic source's `Started` event raised after `StartRecording()` succeeds. Zero
|
||||
devices at startup → stays red and the mixer is never started; capture failure → yellow.
|
||||
Green must never be raised earlier (e.g. on loopback start or on `Start()` being called).
|
||||
- **Uncommitted:** this session — `ViewModels/MainViewModel.cs` (health wiring +
|
||||
`ResetHealth`), `TASKS.md` (ship step 6 ✅), `ai.md`, `ViewModels/index.md`, `HANDOFF`.
|
||||
- **Verified:** pending (build + full test run right before commit).
|
||||
- **Branch:** `main`, in sync with `origin/main`.
|
||||
- **This session (TASK 7 — UI polish batch, gramps's 6-point review):**
|
||||
1. **Scenes list cleaned:** the per-row edit/trash/visibility icons and the inline
|
||||
rename TextBox are gone. Scenes are pure selection rows; `IsHidden` stays
|
||||
persisted and still dims a hidden row to 45%. Removed dead surface:
|
||||
`EditSceneCommand`/`RemoveSceneCommand`/`ToggleSceneVisibilityCommand` +
|
||||
`BeginEditScene`/`ToggleSceneVisibility`/`RemoveScene` handlers + `Scene.IsEditing`.
|
||||
2. **Sources list upgraded:** each row now has edit + visibility eye + trash. New
|
||||
`EditElementCommand` (`SceneElement.IsEditing` → inline rename TextBox, Enter/Esc/
|
||||
lost-focus commits) and `ToggleElementVisibilityCommand` (flips `SceneElement.IsVisible`);
|
||||
the eye style now binds `IsVisible` and hidden rows dim to 45%.
|
||||
3. **Duplicate naming:** shared `NextSourceName(scene, baseName)` → `Image`, `Image2`,
|
||||
`Image3`… (no space), next free number derived from actual names so deletions never
|
||||
collide. Used by both `AddSource` and `AddReusedImage`.
|
||||
4. **Social bar:** `MaxWidth=200` + `CharacterEllipsis` removed from BOTH
|
||||
`SocialBarRenderer.cs` and the preview DataTemplate — full validated handle renders.
|
||||
5. **Panels:** left 220 / right 300 fixed widths are deliberate — panels never re-layout
|
||||
on resize; the preview absorbs it. No change.
|
||||
6. **Focus-loss capture lag:** recorded in `ai.md` as a known OS limit (DWM/WGC
|
||||
throttling when unfocused + GPU readback contention + the `_framePending` /
|
||||
`DispatcherPriority.Render` gates). NOT an in-app throttle; deferred by user decision.
|
||||
- **Test infra change:** the two real-WPF-App tests (round-clip + new source-naming) now
|
||||
share `RealAppHost` — a dedicated STA thread owning the single `App` — via the `RealApp`
|
||||
serial collection. WPF allows exactly one `Application` per AppDomain; never add a test
|
||||
that calls `new App()` directly again — marshal onto `RealAppHost` instead.
|
||||
- **Uncommitted:** `MainWindow.xaml` + `MainWindow.xaml.cs` (rows), `ViewModels/MainViewModel.cs`
|
||||
(commands + naming), `Models/SceneElement.cs` (+`IsEditing`), `Models/Scene.cs` (−`IsEditing`),
|
||||
`Services/Compositor/SocialBarRenderer.cs` (no truncation), `ytLive.Tests/SourceNamingTests.cs`
|
||||
(new), `ytLive.Tests/RealAppCollection.cs` (new), `ytLive.Tests/RoundClipInteractionTests.cs`
|
||||
(now uses the shared host), `TASKS.md` (TASK 7 ✅), `ai.md`, `ViewModels/index.md`, `HANDOFF`.
|
||||
- **Verified:** build 0 warnings / 0 errors; **170/170 tests pass** (169 + the naming test).
|
||||
- **Landmines:**
|
||||
- Never add another test that constructs `new App()` — use `RealAppHost.Run(...)`.
|
||||
- Never set a local `Canvas.SetTop` on the social bar — a local value permanently
|
||||
overrides `{Binding SocialBarTop}` (the `ClearValue` lesson from 5.5).
|
||||
- `AudioMixer` meter `Push` is unconditional **by design now**: `OnMicSample`/
|
||||
@@ -44,7 +49,7 @@
|
||||
- `MicConnected` comes from the source `Started` event, raised right after
|
||||
`StartRecording()` succeeds — tests must `MarkStarted()` the fake source
|
||||
before asserting connection state.
|
||||
- The mic dot is red until a resource connects (see contract above) — green
|
||||
- The mic dot is red until a resource connects (see contract below) — green
|
||||
only after `Started`, yellow on `Failed`.
|
||||
- Zero mic devices at startup = red dot AND the mixer is never started, so
|
||||
loopback + the game bar can't run either (no capture at all) — acceptable.
|
||||
@@ -56,17 +61,22 @@
|
||||
- `StopAsync` must stop the encoder (closes stdin) **before** awaiting the pump
|
||||
loop — closing stdin unblocks a write stuck on pipe backpressure; the reverse
|
||||
order deadlocks.
|
||||
- Tests never instantiate `MainViewModel` directly except the round-clip
|
||||
integration test (a real `MainWindow`), which never goes live — keep it that way.
|
||||
- Tests never instantiate `MainViewModel` directly except via a real `MainWindow`
|
||||
on the `RealAppHost` STA thread (round-clip + naming), which never go live.
|
||||
- Sandbox can't reach outbound HTTPS — `HttpSocialValidator` stub-handler tests
|
||||
only, never the real instance.
|
||||
- **Next step:** commit + push this ship-step-6 work (one commit). Then the remaining
|
||||
TASK 4 requirement is **ship step 7 — one-click go live + private-only enforcement**
|
||||
(honor the dialog's chosen visibility / enforce `privacyStatus = "private"`; also
|
||||
fixes the REC sign's private state — see round-3 note above). Also queued: task 21
|
||||
(logo + About hub), task 22 (voice filters). Nothing else queued — do not expand
|
||||
the task queue on your own. Optional, not queued: rewriting the healed entry's
|
||||
`ProfileUrl` to `https://mastodon.llamachile.tube/@gramps` (user must say the word).
|
||||
- **Mic status contract (creator's rule, verified — do NOT "fix"):** the status dot is
|
||||
**red until a mic resource is actually connected**. `MicStatus` starts `NotConnected`
|
||||
(red); it goes green ONLY when the mixer's `MicConnected` fires, which comes strictly
|
||||
from the mic source's `Started` event raised after `StartRecording()` succeeds. Zero
|
||||
devices at startup → stays red and the mixer is never started; capture failure → yellow.
|
||||
- **Next step:** commit + push this TASK 7 batch (one commit). Then the remaining TASK 4
|
||||
requirement is **ship step 7 — one-click go live + private-only enforcement** (honor the
|
||||
dialog's chosen visibility / enforce `privacyStatus = "private"`; also fixes the REC sign's
|
||||
private state — see round-3 note). Also queued: task 21 (logo + About hub), task 22 (voice
|
||||
filters). Nothing else queued — do not expand the task queue on your own. Optional, not
|
||||
queued: rewriting the healed entry's `ProfileUrl` to `https://mastodon.llamachile.tube/@gramps`
|
||||
(user must say the word).
|
||||
|
||||
- **Secret/DB/port facts live:** OAuth client id/secret in `Helpers/OAuthCredentials.cs`;
|
||||
OAuth session token in `Helpers/TokenStore.cs` (DPAPI → `%APPDATA%\ytLlive\ytLlive.auth`);
|
||||
|
||||
Reference in New Issue
Block a user