Files
LlamaCasty/TASKS/task-42-top-bar-redesign.md
T
gramps e69db4d26c feat(ui): TASK 42 top bar redesign — one Record-or-Stream surface (2026-09-22)
The bar now renders ONE surface from the FIRST decision the creator makes —
Record or Stream — with each world being the whole bar. Creator directive:
"I wrote the fucking thing and I still can't figure-out how to do stuff",
"forget this one dog plan bullshit". OBS/streaming-tool reference for the
one-surface paradigm: https://obsproject.com (single mode toggle + context
actions) — cited per spin-guard habit; the go-live/test pattern follows
CEV (https://cev-desktop.aSean.xyz) precedent.

- Mode: single segmented REC|ON-AIR switch (SegmentToggle/SegmentLabel in
  Themes/Controls.xaml); radio-exclusive world selection, one tap to flip.
- Record world: switch + Start Recording, zero YouTube identity.
- Stream world: switch + Go Live + Test + account zone right (Sign In until
  connected, then avatar with Change Account/Logout context menu).
- Test is a child of Stream: procs only stream-armed AND signed-in.
- Running: one reality line "dot word elapsed" (REC/LIVE/TEST; green/red/
  gold) + End; worlds + switch retire.
- Gear moved up from bottom bar, ~3 wordmark letters past the brand, single
  click opens Settings/Bug/Feature/About menu (TASK 40 Unit B shipped early).
- Fix folded in: BeginTestStream now arms OnAirPillOn explicitly (unarmed
  pump booted with zero encoder outputs -> "At least one output is required"
  forced-stop cascade from TASK 41's pipeline).
- VM: world/reality props + RaiseTopBarModes() wired into StreamStatus,
  pill, IsRecording, IsTestStream, IsConnected setters.

Doc: ai.md top-bar model, ViewModels/index.md, Controls/index.md, TASKS.md,
HANDOFF.md, new TASKS/task-42-top-bar-redesign.md; task-40 note.

Tests: TopBarModeTests.cs (new Good Dog), PillRadioTests + TestStreamTests
gates updated. Build 0 warnings; full suite 314/315 — single abort is the
pre-existing env-dependent RealMouseDrag test (Path of Exile 2 running)
2026-09-22 17:57:06 -07:00

4.1 KiB

TASK 42 — Top bar redesign (shipped 2026-09-22)

One work unit, no sub-tasks (creator directive: "forget this one dog plan bullshit. Our one plan is replacing the top menu bar with something usable"). Good Dog = ONE integration test: ytLive.Tests/TopBarModeTests.cs.

The problem

The old bar packed three widget grammars (sliding pills = intent, dots/badges = state, buttons = action), a hidden sign-in context menu, an account status dot that collided with live red, six simultaneous "you're running" signals, and a dead pieces (PRIVATE chip — dev-phase forced option, becomes real at ship; status light whose pulsing spec never shipped). The creator: "I wrote the fucking thing and I still can't figure-out how to do stuff."

The product model (locked in conversation)

The bar is ONE surface rendered by the FIRST decision — Record or Stream — each world is the whole bar; the other world never exists on screen.

  • Mode switch: one segmented REC|ON-AIR toggle (former two pills are a binary, radio-exclusive decision). Going back = one tap on the other segment. Idle-only; while running the switch retires.
  • Record world: switch + Start Recording. No YouTube identity at all.
  • Stream world: switch + Go Live + Test and the account zone on the right (Sign In while signed-out — the pending sequence step rendered exactly when needed; the avatar once connected, right-click = Change Account/Logout).
  • Test is a child of Stream (creator ruling): it procs only when ON-AIR is armed AND signed in — you can't dry-run a recording.
  • Running: the worlds retire; one reality line ● REC|LIVE|TEST 00:12:34 (green/red/gold) + End. Full-bar color flip stays.
  • Gear moved up from the bottom bar to ~3 wordmark-letters past the brand (task 40 Unit B spec): one menu — App Settings / Report Bug / Feature Request / About. Removed from BottomBar.
  • Sign-in flow: Stream → (Sign In appears, or avatar confirms the account) → Go Live → Stop. Account switch = one re-auth → Google's own chooser pre-selected (no accounts-list API exists; login_hint+select_account is the source of truth).

Files (declared scope)

  • Themes/Controls.xaml — SegmentToggle / SegmentLabel (segmented switch)
  • Controls/TopBar.xaml(.cs) — full rewrite; GearButton_Click moved in
  • Controls/BottomBar.xaml(.cs) — gear removed
  • ViewModels/MainViewModel.Streaming.cs — world/reality props + RaiseTopBarModes() (called from StreamStatus/IsRecording/IsTestStream/pill setters); PrimaryStartButtonLabel = "Start Recording"/"Go Live"; ShowTestButton/CanStartTest = stream world AND connected
  • ViewModels/MainViewModel.Streaming.Operations.cs — BeginTestStream arms OnAirPillOn explicitly (the TASK 41 pipeline bug: a test that never armed the pill booted a pump with zero encoder outputs → "At least one output is required")
  • ViewModels/MainViewModel.Account.cs — IsConnected raises RaiseTopBarModes()
  • ytLive.Tests/PillRadioTests.cs / TestStreamTests.cs — updated to the new gates (label + middle-mover + Test-on-Stream)
  • ytLive.Tests/TopBarModeTests.cs — NEW Good Dog
  • Docs: ai.md, ViewModels/index.md, Controls/index.md, TASKS.md, HANDOFF.md

Build / test

Main + tests build clean, 0 warnings; full-suite run: 314/315 pass — the single abort is the known environment-dependent LayerReorderPersistenceTests.RealMouseDrag (Path of Exile 2 was open; its injected physical mouse events no-op when a game window interferes — documented in the test's own docstring). 314 prior tests + the new Good Dog, all green; the drag test passes on a clean desktop. Test environment note: a dev machine may hold a real saved OAuth session that loads synchronously in the ctor — signed-in-world assertions must force IsConnected first (the record of that trap lives here and in the tests).

Not in this task (carried)

  • App Settings round (TASK 40) — camera picker, defaults, accent units still queued; its Unit B (gear) is now DONE early by this task; BottomBar gear already removed.
  • Account-confirm via Google chooser is behavior folded into Sign In (no new code).