Polish title sheets, playback handoff and season motion #79

Closed
justinzeus wants to merge 0 commits from fm/polish-lane-d into fm/tv-round2
Owner

Title-page motion and immediate playback feedback

Implements Lane D of the approved TV polish, on foundation commit 74b737fb52bfbb2cc7afa0b0288ae59e67232320.

Idea Change and owned files
P06 Title side panels retain inert exit content, fade their bounded panel/shadow and use one scrim through Menu handoffs. TitlePage.kt, TitleOptionsSheet.kt, TitleMenu.kt, TitleControl.kt; amended only the authorized Menu-to-Media-info method in TitleRound2Test.kt.
P02 TitleNotice uses RecoveryToastHost; its existing dismissal timer is unchanged.
E04 Primary Play/Resume preserves width and reads Starting… during preparation. Duplicate activation is ignored; the player opens only after the draw-only veil reaches black. Failure restores the label/toast. Back, entry deactivation and title/person navigation cancel the intent, so late preparation cannot take over another page. TitleState.kt, TitleControl.kt, TitleHeader.kt, TitlePage.kt, TitleDestination.kt.
E05 Title/person vertical movement and laid-out season-chip movement use animateFrameScroll; only unlaid-out chips use scrollToItem. Deleted the private title tween. TitlePage.kt, PersonPage.kt.
E06 Header and card progress draw their changing fill without layout animation. First paint/different target and line-kind changes cut; later same-target fractions use heroFade/easeInOut, including runtime metadata arriving for an already-present resume track. TitleHeader.kt, TitleCard.kt.
E07 One draw-only season capsule carries nav-spring velocity through retargets. Per-entry/title/person cached episodes install synchronously and refresh in the background; refresh errors retain the real cards. TitlePage.kt, TitleState.kt, TitleDestination.kt.

Approved decisions and observation criteria

  • P06: Media info fades over the existing Menu scrim. The prior no-change assertion becomes one constant scrim plus a monotonic panel fade. Retained controls are inert; native page/opener focus checks remain strong in both motion modes. The permitted weaker logical-only fallback was not used.
  • E04: exact copy Starting… (U+2026), resting button width retained. Restart/card starts get the black handoff without a changed icon label. Keys are swallowed only during the veil; before it, Back retains its normal navigation/overlay behavior and cancels preparation.
  • E05: this branch migrates callers. Lane E owns spring momentum and its physics regression; the published foundation-only base still has the old primitive implementation. These caller captures prove pinned destinations/focus, not the final combined spring curve.
  • E06: progress text and watched/resume line-kind changes remain cuts; a continuous resume track interpolates.
  • E07, explicitly approved by steering 006: never a skeleton, empty or blank episode row. Native frame 0 may retain the outgoing real Season 6 cards; the incoming cached Season 5 subtree must appear by frame 1, one exact 16 ms step later. Every observed frame 0–3 checks Ready state, one interactive episode card and uniformly opaque real red/green fixture art (no blank/skeleton/partial-alpha pixels). Frames 1–3 additionally require the incoming red artwork and cached episode caption. Cache state is already Season 5 Ready before frame 0; this is composition latency, not default-season restoration. Frame 0 is the first capture after the selection/initial rendering tick, not an extra destination transition.
  • Reduced motion: fades are capped by the shared helper; progress and geometry snap. Every new motion scenario runs normally and with reduced motion.

Verification

All 132 named tests pass across the completed combined neighbour run and final focused native rerun. The combined run passed 100 app neighbours and nine design neighbours; its only failures were two new cancellation scenarios checking state before the entry provider committed. Their corrected native ownership barrier and all other TitlePolishTest scenarios subsequently passed (23/23). No production code changed between those runs.

Class Passing tests
TitlePolishTest 23
TitleRound2Test 13
TitleKeysTest 20
TitleCaptureTest 42
TitleAsyncFocusTest 3
TitlePlaybackNavigationTest 2
TitleThemeMusicTest 7
WatchReturnTest 1
TitleEntryBackTest 12
TitleReadinessMotionTest 2
CardBottomPixelTest 2
CardGeometryTest 5

The combined scoped command:

bash docker/gradle.sh debug --continue \
  :wolfskin-design:cacheRobolectricSdk :app:testDefaultDebugUnitTest \
  --tests org.justinvisser.wolfskin.tv.TitlePolishTest \
  --tests org.justinvisser.wolfskin.tv.TitleRound2Test \
  --tests org.justinvisser.wolfskin.tv.TitleKeysTest \
  --tests org.justinvisser.wolfskin.tv.TitleCaptureTest \
  --tests org.justinvisser.wolfskin.tv.TitleAsyncFocusTest \
  --tests org.justinvisser.wolfskin.tv.TitlePlaybackNavigationTest \
  --tests org.justinvisser.wolfskin.tv.TitleThemeMusicTest \
  --tests org.justinvisser.wolfskin.tv.WatchReturnTest \
  --tests org.justinvisser.wolfskin.tv.TitleEntryBackTest \
  :wolfskin-design:testDebugUnitTest \
  --tests org.justinvisser.wolfskin.design.TitleReadinessMotionTest \
  --tests org.justinvisser.wolfskin.design.CardBottomPixelTest \
  --tests org.justinvisser.wolfskin.design.CardGeometryTest

Final focused native rerun (23 passed):

bash docker/gradle.sh debug :wolfskin-design:cacheRobolectricSdk \
  :app:testDefaultDebugUnitTest \
  --tests org.justinvisser.wolfskin.tv.TitlePolishTest \
  -x :wolfskin-design:testDebugUnitTest

Earlier runs, disclosed rather than hidden:

  • Initial capture-only TitlePolishTest run used the focused command above: one failed capture because the fixture had no playTarget. Corrected capture harness plus TitleRound2Test.menuToMediaInfoNeverDoubleDimsOrPopsAndBackKeepsOneScrim passed.
  • Implementation batches used the combined named-class selectors above: app 110/5 failures, 115/3, 119/2, then 119/1. In the first batch the design command was behind && and did not execute; subsequent combined batches passed all nine design neighbours. Failures drove the scrim ownership, native close-focus, quantization, carried-velocity and cached-frame corrections described here.
  • Two focused cache-diagnostic runs used the focused command above with the two season methods as selectors (seasonCapsuleGlidesAndCachedSeasonSkipsSkeleton, reducedSeasonCapsuleSnapsAndCachedSeasonSkipsSkeleton): each had 2 tests/1 failure under the old stricter outgoing-frame assertion. Steering 006 approved the explicit incoming-frame criterion; it now passes normally and reduced.
  • The first final combined invocation stopped at compilation (missing drawBehind import after caching the capsule stroke); no tests ran. Import restored. Corrected combined invocation: 123 app tests/2 cancellation-test failures, 9 design passed; final focused native rerun: 23 passed as above.

Matched native baseline recapture: the focused command above ran 7 capture-only scenarios, all passed, on detached foundation 74b737fb52bfbb2cc7afa0b0288ae59e67232320. The temporary harness was removed and the verified feature branch restored. Matched synthetic artwork/profile data removes incidental fixture differences from the before/after review; the original Menu handoff baseline is retained.

Published native PNGs (with sampled CSVs):

Idea Before After
P06, including Menu handoff 50 66
E04 13 47
E05 52 104
E06 48 147
E07 31 112

Authorized existing-test adaptations: the next-up/restart/explicit-episode playback test now composes/advances the veil; the real-episode theme-music test advances the handoff clock. Their identity and stop-before-navigation ordering assertions remain intact.

Native proof

Before/after PNG strips and sampled CSVs are published at:

/root/.treehouse/firstmate-7bab20/2/firstmate/data/ui-polish-build/lane-d/<ID>/{before,after}/

IDs: P06, E04, E05, E06, E07. P06 includes the Menu-to-Media-info handoff. The P02 host's component motion proof belongs to Lane E; Lane D changes only its title caller.

No TV box, ADB, emulator, APK build or full-suite run. Central TV spec documentation belongs to Lane C and is intentionally untouched. No merge requested or performed.

## Title-page motion and immediate playback feedback Implements Lane D of the approved TV polish, on foundation commit `74b737fb52bfbb2cc7afa0b0288ae59e67232320`. | Idea | Change and owned files | |---|---| | P06 | Title side panels retain inert exit content, fade their bounded panel/shadow and use one scrim through Menu handoffs. `TitlePage.kt`, `TitleOptionsSheet.kt`, `TitleMenu.kt`, `TitleControl.kt`; amended only the authorized Menu-to-Media-info method in `TitleRound2Test.kt`. | | P02 | `TitleNotice` uses `RecoveryToastHost`; its existing dismissal timer is unchanged. | | E04 | Primary Play/Resume preserves width and reads **Starting…** during preparation. Duplicate activation is ignored; the player opens only after the draw-only veil reaches black. Failure restores the label/toast. Back, entry deactivation and title/person navigation cancel the intent, so late preparation cannot take over another page. `TitleState.kt`, `TitleControl.kt`, `TitleHeader.kt`, `TitlePage.kt`, `TitleDestination.kt`. | | E05 | Title/person vertical movement and laid-out season-chip movement use `animateFrameScroll`; only unlaid-out chips use `scrollToItem`. Deleted the private title tween. `TitlePage.kt`, `PersonPage.kt`. | | E06 | Header and card progress draw their changing fill without layout animation. First paint/different target and line-kind changes cut; later same-target fractions use `heroFade`/`easeInOut`, including runtime metadata arriving for an already-present resume track. `TitleHeader.kt`, `TitleCard.kt`. | | E07 | One draw-only season capsule carries nav-spring velocity through retargets. Per-entry/title/person cached episodes install synchronously and refresh in the background; refresh errors retain the real cards. `TitlePage.kt`, `TitleState.kt`, `TitleDestination.kt`. | ### Approved decisions and observation criteria - P06: Media info fades over the existing Menu scrim. The prior no-change assertion becomes **one constant scrim plus a monotonic panel fade**. Retained controls are inert; native page/opener focus checks remain strong in both motion modes. The permitted weaker logical-only fallback was not used. - E04: exact copy **Starting…** (U+2026), resting button width retained. Restart/card starts get the black handoff without a changed icon label. Keys are swallowed only during the veil; before it, Back retains its normal navigation/overlay behavior and cancels preparation. - E05: this branch migrates callers. Lane E owns spring momentum and its physics regression; the published foundation-only base still has the old primitive implementation. These caller captures prove pinned destinations/focus, not the final combined spring curve. - E06: progress text and watched/resume line-kind changes remain cuts; a continuous resume track interpolates. - E07, explicitly approved by steering 006: **never a skeleton, empty or blank episode row**. Native frame 0 may retain the outgoing real Season 6 cards; the incoming cached Season 5 subtree must appear by frame 1, one exact 16 ms step later. Every observed frame 0–3 checks Ready state, one interactive episode card and uniformly opaque real red/green fixture art (no blank/skeleton/partial-alpha pixels). Frames 1–3 additionally require the incoming red artwork and cached episode caption. Cache state is already Season 5 Ready before frame 0; this is composition latency, not default-season restoration. Frame 0 is the first capture after the selection/initial rendering tick, not an extra destination transition. - Reduced motion: fades are capped by the shared helper; progress and geometry snap. Every new motion scenario runs normally and with reduced motion. ### Verification **All 132 named tests pass** across the completed combined neighbour run and final focused native rerun. The combined run passed 100 app neighbours and nine design neighbours; its only failures were two new cancellation scenarios checking state before the entry provider committed. Their corrected native ownership barrier and all other `TitlePolishTest` scenarios subsequently passed (23/23). No production code changed between those runs. | Class | Passing tests | |---|---:| | TitlePolishTest | 23 | | TitleRound2Test | 13 | | TitleKeysTest | 20 | | TitleCaptureTest | 42 | | TitleAsyncFocusTest | 3 | | TitlePlaybackNavigationTest | 2 | | TitleThemeMusicTest | 7 | | WatchReturnTest | 1 | | TitleEntryBackTest | 12 | | TitleReadinessMotionTest | 2 | | CardBottomPixelTest | 2 | | CardGeometryTest | 5 | The combined scoped command: ```sh bash docker/gradle.sh debug --continue \ :wolfskin-design:cacheRobolectricSdk :app:testDefaultDebugUnitTest \ --tests org.justinvisser.wolfskin.tv.TitlePolishTest \ --tests org.justinvisser.wolfskin.tv.TitleRound2Test \ --tests org.justinvisser.wolfskin.tv.TitleKeysTest \ --tests org.justinvisser.wolfskin.tv.TitleCaptureTest \ --tests org.justinvisser.wolfskin.tv.TitleAsyncFocusTest \ --tests org.justinvisser.wolfskin.tv.TitlePlaybackNavigationTest \ --tests org.justinvisser.wolfskin.tv.TitleThemeMusicTest \ --tests org.justinvisser.wolfskin.tv.WatchReturnTest \ --tests org.justinvisser.wolfskin.tv.TitleEntryBackTest \ :wolfskin-design:testDebugUnitTest \ --tests org.justinvisser.wolfskin.design.TitleReadinessMotionTest \ --tests org.justinvisser.wolfskin.design.CardBottomPixelTest \ --tests org.justinvisser.wolfskin.design.CardGeometryTest ``` Final focused native rerun (**23 passed**): ```sh bash docker/gradle.sh debug :wolfskin-design:cacheRobolectricSdk \ :app:testDefaultDebugUnitTest \ --tests org.justinvisser.wolfskin.tv.TitlePolishTest \ -x :wolfskin-design:testDebugUnitTest ``` Earlier runs, disclosed rather than hidden: - Initial capture-only `TitlePolishTest` run used the focused command above: one failed capture because the fixture had no `playTarget`. Corrected capture harness plus `TitleRound2Test.menuToMediaInfoNeverDoubleDimsOrPopsAndBackKeepsOneScrim` passed. - Implementation batches used the combined named-class selectors above: app **110/5 failures**, **115/3**, **119/2**, then **119/1**. In the first batch the design command was behind `&&` and did not execute; subsequent combined batches passed all nine design neighbours. Failures drove the scrim ownership, native close-focus, quantization, carried-velocity and cached-frame corrections described here. - Two focused cache-diagnostic runs used the focused command above with the two season methods as selectors (`seasonCapsuleGlidesAndCachedSeasonSkipsSkeleton`, `reducedSeasonCapsuleSnapsAndCachedSeasonSkipsSkeleton`): each had **2 tests/1 failure** under the old stricter outgoing-frame assertion. Steering 006 approved the explicit incoming-frame criterion; it now passes normally and reduced. - The first final combined invocation stopped at compilation (missing `drawBehind` import after caching the capsule stroke); no tests ran. Import restored. Corrected combined invocation: **123 app tests/2 cancellation-test failures**, **9 design passed**; final focused native rerun: **23 passed** as above. Matched native baseline recapture: the focused command above ran **7 capture-only scenarios, all passed**, on detached foundation `74b737fb52bfbb2cc7afa0b0288ae59e67232320`. The temporary harness was removed and the verified feature branch restored. Matched synthetic artwork/profile data removes incidental fixture differences from the before/after review; the original Menu handoff baseline is retained. Published native PNGs (with sampled CSVs): | Idea | Before | After | |---|---:|---:| | P06, including Menu handoff | 50 | 66 | | E04 | 13 | 47 | | E05 | 52 | 104 | | E06 | 48 | 147 | | E07 | 31 | 112 | Authorized existing-test adaptations: the next-up/restart/explicit-episode playback test now composes/advances the veil; the real-episode theme-music test advances the handoff clock. Their identity and stop-before-navigation ordering assertions remain intact. ### Native proof Before/after PNG strips and sampled CSVs are published at: `/root/.treehouse/firstmate-7bab20/2/firstmate/data/ui-polish-build/lane-d/<ID>/{before,after}/` IDs: **P06, E04, E05, E06, E07**. P06 includes the Menu-to-Media-info handoff. The P02 host's component motion proof belongs to Lane E; Lane D changes only its title caller. No TV box, ADB, emulator, APK build or full-suite run. Central TV spec documentation belongs to Lane C and is intentionally untouched. No merge requested or performed.
justinzeus added 2 commits 2026-11-08 04:12:27 +01:00
Author
Owner

Landed through the round 2 candidate #82 (merged into fm/tv-round2 as c21d17df). Closing as superseded; nothing from this branch is lost.

Landed through the round 2 candidate https://git.justinvisser.org/justinzeus/wolfskin/pulls/82 (merged into fm/tv-round2 as c21d17df). Closing as superseded; nothing from this branch is lost.
justinzeus closed this pull request 2026-11-08 13:59:34 +01:00

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
exploring
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: justinzeus/wolfskin#79
No description provided.