Integrate Discover with canonical shared UI

This commit is contained in:
justinzeus 2026-11-05 20:57:57 +01:00
commit 575103ce98
690 changed files with 2899 additions and 174 deletions

View file

@ -59,9 +59,9 @@ cover the Wolfskin nav.
The independent `:wolfskin-design` module owns the shell components, fixed person
colours, focus policy, per-person root-view memory, palette and motion. Its
`tokens.json` is the copied approved TV-spec source, retaining the locked prototype
SHA and provenance. `shell-tokens.json` adds shell, grid and sheet measurements;
`home-tokens.json` adds Home geometry from that same locked prototype. Generate
the committed Kotlin, CSS and checksum manifest together:
SHA and provenance. `shell-tokens.json` adds shared shell, grid and sheet measurements;
`home-tokens.json` and `discover-tokens.json` add their screen geometry from that
same locked prototype. Generate the committed Kotlin, CSS and checksum manifest together:
```sh
python3 wolfskin-design/generate_tokens.py
@ -89,14 +89,59 @@ Coming-in sheet described below. **Advanced settings → Wolfskin screens** is t
rollout switch: turning it off renders upstream Home and library destinations with
the upstream Backdrop and top scrim, while retaining Wolfskin's nav, picker and
Settings list. Native Up traversal stays in content until the first focusable row,
then enters the nav. Turning the switch on renders Wolfskin Home; later-slice
screens remain explicitly labelled navigation targets.
then enters the nav. Turning the switch on renders Wolfskin Home and Libraries.
Discover and Requests are integrated Wolfskin surfaces; title hand-offs remain labelled.
Debug people, tabs and initials come from the shell-only projection of the locked
prototype fixture in `app/src/debug/assets/wolfskin-shell.json`; release resources
do not package it. Saved Jellyfin identities use existing upstream services. The
shell makes no Conductarr calls and does not add Conductarr sign-in.
Discover adds the picks hero, type chips, catalogue shelves, service pages, continuous
See all grids, Hidden picks, request chooser and receipts. Its `discover-title/...`
destination is an explicit title-family integration stub exposing only Discover's
request and pick actions. Unheld titles have no trailer control until the pinned
Conductarr title contract supplies a trailer.
The debug-only fixture and local art live in
`app/src/debug/assets/wolfskin-discover/`. Release builds remain on the explicit
Conductarr sign-in state. The fixture host cannot construct a network client:
debug request outcomes and dismissals stay in memory. The real mutation adapter
accepts an injected `ConductarrClient` and uses only its typed routes; it is not
wired to a live server. Unknown request outcomes force a fresh title-requests read
instead of blindly submitting again, including after closing a sheet or choosing
the same uncertain recipient from another chooser. Whole-series requests require every season.
Discover hero and Restore text use explicit per-line CSS allocations so native
paragraph overflow cannot enlarge the bottom-anchored stack. Restore subtitles
retain the sheet's negative top margin and bottom gap. Recovery panels may
overflow their fixed-height scroll row so sign-in copy never shrinks the retry
button. Native regressions cover those three layout boundaries.
Discover's native capture suite covers its 28 named acceptance states and emits
text-layout metrics beside the PNGs. Data-driven Android key replays cover opening
Discover in 4 presses, requesting for yourself in 7, requesting for Mindel in 9 and
Not interested in 8. Additional regressions exercise held-OK safety, uncertain
receipts, per-recipient outcomes, collection recovery and Undo, unknown seasons,
Dutch decimal formatting and short-row/tail clamping. Discover reuses the Libraries
grid, poster, ratings plate, See all and recovery cards, bounded image loader, caption
separator token and the shell's single hold guard. Both frames share the 180 ms scroll tween.
The TV keeps platform Roboto with the approved type sizes and weights. Browser
system-font wrapping is not a per-title contract: no bundled font, forced title
breaks or width compensation is applied. Discover's own stacked text preserves
untrimmed CSS line boxes without changing merged shell/library typography. Hero,
sheet and shared focused-content shadows use tokenized drop shadows, not Material
elevation; their alpha animates in the draw phase. Native text-layout measurements
accompany each acceptance capture; remaining font-driven wrapping and text-block
positions must be listed explicitly in its comparison report.
The asynchronous debug fixture seam hands loading focus back to the first loaded
action when Discover is still the selected destination. A JVM regression releases
the actual host's suspended fixture load and presses Android OK: it must open the
hero rather than activate the nav. Fixture completion does not steal a different
destination or nav selection.
Native Roborazzi captures use Robolectric SDK 34 and
`w960dp-h540dp-xhdpi` (1920×1080 at density 2.0). `make test` writes capture PNGs and
the sampled Compose nav-spring curve to `build/wolfskin-captures/`. Key replays
@ -125,15 +170,15 @@ attribution and project URL. The check does not depend on incremental merge file
Home is one lazy frame: a non-rotating resume → Next up → newest → pick hero,
Jellyfin shelves, per-destination "Your …" shelves and the Discover continuation.
The final action opens Discover at its top; Discover remains its named integration
target. Home's See all cards open the real `WolfskinSeeAllLists` grid, carrying
The final action opens the real merged Discover screen at its top through the
shell's root re-selection transition. Home's See all cards open `WolfskinSeeAllLists`, carrying
the complete underlying list rather than the visible shelf window. Title content
remains the later-slice target.
All Home components and immutable screen models live in `:wolfskin-design`.
The shell's remembered view owns vertical position, each row's selected card and
actual horizontal `LazyListState`, and the bounded six-hour ratings session cache.
Composing destinations bind `viewFor(route)` before navigation effects run, so a
Composing destinations bind `rememberedView(route)` before navigation effects run, so a
new See all grid cannot borrow or clamp Home's scroller. Re-entry restores the
remembered track before the page with `scrollToItem`, preserving exact indices and
pixel offsets rather than animating back. Android focus stays with the shell;
@ -148,7 +193,7 @@ when card widths differ. A visited row restores its column. Horizontal movement
keeps the track still while focus remains in its visible middle.
The initial skeleton parks focus on the nav. When the first content arrives,
an untouched fresh entry focuses hero button zero; intervening nav input prevents
that automatic transfer. Home and Libraries use the same `ShellContentFocus`
that automatic transfer. Home, Libraries and Discover use the same `ShellContentFocus`
release/repeat guard and Back ladder.
`HomeReadFacade` is the only Home code importing Jellyfin API clients. Release
@ -168,8 +213,8 @@ network reads in tests. Conductarr sign-in is not implemented here: real signed-
Home hides every rating and shows "Discover needs sign-in". No Seerr fallback is
used. Catalogue data and ratings in debug captures are fixture-backed.
Home and Libraries share `TitleCard`, `Caption`, `LibrarySeeAllCard` and one
`WolfskinImages` loader. Images request exact slot sizes, use RGB565 for posters,
Home, Libraries and Discover reuse `TitleCard`, `Caption` and `LibrarySeeAllCard`;
those screens and Requests share one `WolfskinImages` loader. Exact-slot requests use RGB565 for posters,
disable crossfades, share a 64 MiB memory/128 MiB disk cache, limit image work to
four reads and prefetch the next shelf. Rating plates start at 14 sp, shrink to 12 sp
and drop trailing entries rather than wrap. Their uncached read gate is 350 ms;
@ -180,8 +225,9 @@ own geometry; the Discover section uses a warning pill. Caption separators multi
the existing muted colour alpha by the shared 40% token. Home-only untrimmed styles
and `exactLineBox` honor the declared CSS line boxes despite Android's intrinsic
paragraph minimums; shell and library typography retain their existing defaults.
Home See all supplies its locked 8px column gap; the shared Library tail retains
its existing 10px default rather than leaking that measurement into Home.
The shared See all component uses its canonical locked 8px gap, not the generic
10px tail spacing. Focus lifts use the merged draw-only `FocusLift` implementation;
the obsolete Home shadow helper and duplicate gap/lift measurements are removed.
Vertical moves clamp to short target rows, including a final See all card.
`make test` includes `HomeCaptureTest` (23 native acceptance states) and the