Remove the unfocused watched control ring #69

Merged
justinzeus merged 1 commit from fm/tv-watched-ring into fm/tv-round2 2026-11-07 23:28:01 +01:00
Owner

Outcome

The watched eye no longer looks focused when focus is elsewhere. Justin (2026-11-07): ‘the watches icon on details pages has a border, making it look like it's active/selected.’ This supersedes the older inset-on-ring specification.

Change

Delete only the option.on && !focused border from TitleControl. Keep the existing open-eye/crossed-eye glyphs, Watched header, Mark as unwatched caption, selected accessibility semantics, and unchanged focus ring/scale/fill. No new colour, token, or icon. Update the local TV spec and Docker developer documentation.

Shared-component inventory: before → after

Only Watched sets TitleOption.on; favourite and watchlist are not controls built by this component.

Shared controls Before → after
Mark as watched / Mark as unwatched, including series and episode targets Unfocused on: open eye with 3 px inset accent border → same open eye without border. Unfocused off: crossed eye without border → unchanged. Focused on/off: existing accent focus ring → unchanged.
Play / Resume (including episode labels) Primary light fill and playback glyph → unchanged.
Restart; Version; Audio and subtitles; Play trailer; Menu Secondary icon buttons, accent ring only while focused → unchanged.
Request / Requested status Primary labelled action with existing stage glyph → unchanged.
Not interested; Show again Labelled secondary eye-off / undo action, focus-only ring → unchanged; neither sets on.
Try again; Back, including unavailable/offline recovery actions Primary retry or secondary Back button, focus-only ring → unchanged.
Menu: Media info; Add for someone Full-width labelled actions with existing focus treatment → unchanged.
Audio/subtitles sheet: Done; media-info sheet: Close Primary labelled actions → unchanged.
Series watched confirmation: Mark as watched / Mark as unwatched; Cancel Primary confirm and secondary Cancel → unchanged.
Hidden receipt: Undo; Done Primary Undo and secondary Done → unchanged.

TitleRadio and selected season/filter chips are separate controls and are untouched.

Verification

One native same-fixture Details-row before/after comparison covers watched off/on × unfocused/focused (Robolectric SDK 34, 1920×1080). The three unaffected full-frame PNGs are byte-identical before/after; only watched-on/unfocused changes. Visually checked the native comparison: open eye remains distinguishable, and the true focus ring stays on Audio/subtitles or the eye as appropriate.

Added and ran only TitleCaptureTest.watchedRingBelongsOnlyToFocus. Failing-before: resting watched edge contained exactly three accent pixels. Passing-after: one test, zero failures; both resting states have no accent edge; both focused states keep identical accent edge pixels.

Command (through shared-lock wrapper):

WOLFSKIN_DEBUG_KEYSTORE=/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-watched-ring/debug.keystore bash docker/gradle.sh debug :app:testDefaultDebugUnitTest --tests org.justinvisser.wolfskin.tv.TitleCaptureTest.watchedRingBelongsOnlyToFocus -x :wolfskin-design:testDebugUnitTest -PuseMpvStub=true

No full suite, APK build, TV, or box access. Native proof and test XML: /root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-watched-ring/ (before/, after/, details-action-row-before-after.png; before left, after right; off/unfocused, on/unfocused, off/focused, on/focused top to bottom).

Risk

Local presentation only. No action, persistence, navigation, token, or focus-painter change. AI-assisted implementation and PR description.

## Outcome The watched eye no longer looks focused when focus is elsewhere. Justin (2026-11-07): ‘the watches icon on details pages has a border, making it look like it's active/selected.’ This supersedes the older inset-on-ring specification. ## Change Delete only the `option.on && !focused` border from `TitleControl`. Keep the existing open-eye/crossed-eye glyphs, Watched header, Mark as unwatched caption, selected accessibility semantics, and unchanged focus ring/scale/fill. No new colour, token, or icon. Update the local TV spec and Docker developer documentation. ## Shared-component inventory: before → after Only Watched sets `TitleOption.on`; favourite and watchlist are not controls built by this component. | Shared controls | Before → after | |---|---| | Mark as watched / Mark as unwatched, including series and episode targets | Unfocused on: open eye with 3 px inset accent border → same open eye without border. Unfocused off: crossed eye without border → unchanged. Focused on/off: existing accent focus ring → unchanged. | | Play / Resume (including episode labels) | Primary light fill and playback glyph → unchanged. | | Restart; Version; Audio and subtitles; Play trailer; Menu | Secondary icon buttons, accent ring only while focused → unchanged. | | Request / Requested status | Primary labelled action with existing stage glyph → unchanged. | | Not interested; Show again | Labelled secondary eye-off / undo action, focus-only ring → unchanged; neither sets on. | | Try again; Back, including unavailable/offline recovery actions | Primary retry or secondary Back button, focus-only ring → unchanged. | | Menu: Media info; Add for someone | Full-width labelled actions with existing focus treatment → unchanged. | | Audio/subtitles sheet: Done; media-info sheet: Close | Primary labelled actions → unchanged. | | Series watched confirmation: Mark as watched / Mark as unwatched; Cancel | Primary confirm and secondary Cancel → unchanged. | | Hidden receipt: Undo; Done | Primary Undo and secondary Done → unchanged. | `TitleRadio` and selected season/filter chips are separate controls and are untouched. ## Verification One native same-fixture Details-row before/after comparison covers watched off/on × unfocused/focused (Robolectric SDK 34, 1920×1080). The three unaffected full-frame PNGs are byte-identical before/after; only watched-on/unfocused changes. Visually checked the native comparison: open eye remains distinguishable, and the true focus ring stays on Audio/subtitles or the eye as appropriate. Added and ran only `TitleCaptureTest.watchedRingBelongsOnlyToFocus`. Failing-before: resting watched edge contained exactly three accent pixels. Passing-after: one test, zero failures; both resting states have no accent edge; both focused states keep identical accent edge pixels. Command (through shared-lock wrapper): ```sh WOLFSKIN_DEBUG_KEYSTORE=/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-watched-ring/debug.keystore bash docker/gradle.sh debug :app:testDefaultDebugUnitTest --tests org.justinvisser.wolfskin.tv.TitleCaptureTest.watchedRingBelongsOnlyToFocus -x :wolfskin-design:testDebugUnitTest -PuseMpvStub=true ``` No full suite, APK build, TV, or box access. Native proof and test XML: `/root/.treehouse/firstmate-7bab20/2/firstmate/data/tv-watched-ring/` (`before/`, `after/`, `details-action-row-before-after.png`; before left, after right; off/unfocused, on/unfocused, off/focused, on/focused top to bottom). ## Risk Local presentation only. No action, persistence, navigation, token, or focus-painter change. AI-assisted implementation and PR description.
justinzeus added 1 commit 2026-11-07 23:24:03 +01:00
Remove the unfocused watched control ring
All checks were successful
review/code-claude Code APPROVE: one-line ring removal, only Watched uses on
review/design-claude Design PASS: on state readable by glyph, focus ring unchanged
d73796742c
Author
Owner

Review of the watched-ring fix at head d73796742c1a4dee641576965320c0e086726c21 (base fm/tv-round2).

Code verdict: APPROVE (review/code-claude = success).
Design verdict: PASS (review/design-claude = success). No blocking finding.

The change. One production line is removed from TitleControl: the option.on && !focused accent border. The focus ring, scale, fill, selected semantics, glyphs and captions are untouched. No colour, token or icon is added. TitleRadio still uses radioBorder, so that token stays in use.

Shared component. TitleOption.on is set in exactly one place, the Watched control (TitleState.kt:302). I grepped every TitleOption( in the design and app sources and found no other on =. Every other user of the component (Play, Restart, Version, Audio and subtitles, trailer, menu, Request, Not interested, Try again, Back, the sheet buttons, the receipt) cannot change. The PR's inventory table matches the code.

On state is still readable. The control still switches between the open eye (watched) and the crossed-out eye, the focused caption reads Mark as unwatched or Mark as watched, and the selected accessibility flag is kept. In the native before and after comparison the unfocused watched eye loses its ring and stays clearly different from the crossed eye. The focus rings on Audio and subtitles and on the eye are identical before and after. The three other states are byte-identical to before.

Test. TitleCaptureTest.watchedRingBelongsOnlyToFocus renders all four watched and focus combinations and scans the control's left edge. Neither resting state has an accent pixel and both have the same edge. Both focused states keep an identical accent edge. The PR reports it failing before (three accent pixels) and passing after. It asserts the rendered result, not wiring.

Docs. The spec gains a "Details watched control" paragraph and the README a matching one. Both cite Justin's quote with the date and say the state is carried by glyph, header and caption with no new token. The older "inset accent ring" wording is not in this repository's spec.md, so nothing contradictory is left.

Merge. A merge-tree check against current fm/tv-round2 is clean.

Non-blocking notes:

  1. The unfocused on state now rests on the glyph alone. It is distinguishable but subtle. A filled accent glyph would be a new look and would need Justin's call, which his words do not require.
  2. The earlier approved written spec and frames outside this repository's spec.md still show the ring. The override paragraph is the pointer. Fold it into the next spec revision.
  3. The test probes a single row at the control's left edge, where the old border was drawn. A ring drawn elsewhere on the control would not be caught.

Full report (review 7): /root/.treehouse/firstmate-7bab20/2/firstmate/data/round2-review/report.md. Not run: Gradle/make, nothing on the box.

Review of the watched-ring fix at head `d73796742c1a4dee641576965320c0e086726c21` (base `fm/tv-round2`). **Code verdict: APPROVE (`review/code-claude` = success).** **Design verdict: PASS (`review/design-claude` = success).** No blocking finding. **The change.** One production line is removed from `TitleControl`: the `option.on && !focused` accent border. The focus ring, scale, fill, `selected` semantics, glyphs and captions are untouched. No colour, token or icon is added. `TitleRadio` still uses `radioBorder`, so that token stays in use. **Shared component.** `TitleOption.on` is set in exactly one place, the Watched control (`TitleState.kt:302`). I grepped every `TitleOption(` in the design and app sources and found no other `on =`. Every other user of the component (Play, Restart, Version, Audio and subtitles, trailer, menu, Request, Not interested, Try again, Back, the sheet buttons, the receipt) cannot change. The PR's inventory table matches the code. **On state is still readable.** The control still switches between the open eye (watched) and the crossed-out eye, the focused caption reads `Mark as unwatched` or `Mark as watched`, and the `selected` accessibility flag is kept. In the native before and after comparison the unfocused watched eye loses its ring and stays clearly different from the crossed eye. The focus rings on Audio and subtitles and on the eye are identical before and after. The three other states are byte-identical to before. **Test.** `TitleCaptureTest.watchedRingBelongsOnlyToFocus` renders all four watched and focus combinations and scans the control's left edge. Neither resting state has an accent pixel and both have the same edge. Both focused states keep an identical accent edge. The PR reports it failing before (three accent pixels) and passing after. It asserts the rendered result, not wiring. **Docs.** The spec gains a "Details watched control" paragraph and the README a matching one. Both cite Justin's quote with the date and say the state is carried by glyph, header and caption with no new token. The older "inset accent ring" wording is not in this repository's `spec.md`, so nothing contradictory is left. **Merge.** A merge-tree check against current `fm/tv-round2` is clean. **Non-blocking notes:** 1. The unfocused on state now rests on the glyph alone. It is distinguishable but subtle. A filled accent glyph would be a new look and would need Justin's call, which his words do not require. 2. The earlier approved written spec and frames outside this repository's `spec.md` still show the ring. The override paragraph is the pointer. Fold it into the next spec revision. 3. The test probes a single row at the control's left edge, where the old border was drawn. A ring drawn elsewhere on the control would not be caught. Full report (review 7): `/root/.treehouse/firstmate-7bab20/2/firstmate/data/round2-review/report.md`. Not run: Gradle/make, nothing on the box.
justinzeus merged commit 4af1898fd2 into fm/tv-round2 2026-11-07 23:28:01 +01:00
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#69
No description provided.