Build the Wolfskin TV shell and navigation

This commit is contained in:
justinzeus 2026-11-05 14:38:38 +01:00
parent de452448ba
commit f60a22e435
97 changed files with 4363 additions and 91 deletions

View file

@ -7,7 +7,7 @@ Android SDK.
```sh
git fetch origin --tags
make apk # clean, signed default release: three ABI splits + universal
make test # upstream testDefaultDebugUnitTest in the same image, no secrets
make test # app default/debug suite plus wolfskin-design JVM/capture suite
make apk-debug # default debug, no secrets; MPV stub and no extra codec decoders
```
@ -48,6 +48,62 @@ not the working tree. An uncommitted merge still builds with the old version nam
Neither an upstream merge nor its validation build authorizes a release or TV
installation.
## Wolfskin shell
Wolfskin UI lives in `app/src/wolfskin/java`, beside upstream source. The signed-in
entry in `MainContent.kt` calls `WolfskinApp`; Wolfskin-only routes use the single
`Destination.Wolfskin` subtype in the existing navigation stack. Other destinations
continue through upstream `DestinationContent`. Full-screen player/settings pages
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 measurements from that same
prototype. Generate the committed Kotlin, CSS and checksum manifest together:
```sh
python3 wolfskin-design/generate_tokens.py
python3 wolfskin-design/generate_tokens.py --check
```
`preBuild` checks the manifest against the source JSON, generator and generated
outputs. Editing any of them without regenerating fails the build. The shell uses
the generated palette rather than the retired `WOLFSKIN` theme-enum value; the old
numeric value is reserved.
The small gear under the final person opens Settings with Requests focused.
Settings groups hand off to existing upstream pages; the Requests entry explicitly
has no request data yet. **Advanced settings → Wolfskin screens** is the persistent
rollout switch: turning it off renders upstream Home and library destinations,
while retaining Wolfskin's nav, picker and Settings list. Turning it on renders
the labelled placeholders until the corresponding screen slices ship.
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.
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
exercise the Android event adapter, including the 6/8/10/11-press shell paths.
The profile hand-off capture targets the real `HomeSettingsPage`; Playback is a
separate press-count path.
Robolectric SDK 28/30/34 runtimes resolve through Gradle's existing persistent
dependency cache, then copy to `wolfskin-design/build/robolectric-sdk/`. Test workers
use that local directory in offline mode instead of downloading Android JARs into
the container's ephemeral home. A cache miss still needs Maven Central; rate-limited
hosts can seed the existing cache from SHA512-verified local Maven artifacts without
changing the wrapper or adding volumes.
Branding strings and launcher artwork live in `app/src/default/res/`. Debug
assembly runs `checkWolfskinBranding` against every packaged APK through AGP's public
artifact provider and AAPT2. It checks all string, plural and array configurations,
rejecting user-visible upstream branding while preserving the upstream legal
attribution and project URL. The check does not depend on incremental merge files.
## Toolchain and disk use
`Dockerfile` pins Temurin JDK `21.0.11+10` by image digest, command-line tools