Cold start on the target TV box reaches its first frame 21 ms after `dart_main`,
so nothing Dart-side gates the splash. Everything below is on the path to the
first *useful* frame, which is a strictly serial chain and where the viewer
actually waits.
- `monoTheme` is a pure function of two bools that builds a full `ColorScheme`, an
applied-and-copied 15-style `TextTheme`, ~14 sub-themes and then clones the whole
`ThemeData` again. It was rebuilt five times per cold start, two of them before
`runApp`, and twice more per app-shell rebuild. It is memoized now, keyed by
palette plus `TargetPlatform` -- the platform matters because `ThemeData()`
derives tap target size, visual density and typography from
`defaultTargetPlatform`, so a palette-only key would be wrong under a debug or
test platform override.
- `initializeDateFormatting` ignores its locale argument and builds CLDR symbols
and patterns for all 121 locales synchronously. It blocked the gate ahead of the
database open for data that only content screens use.
- `DownloadStorageService.initialize` ended in a `path_provider` round trip plus
mkdir at the tail of the gate, contradicting the comment above it that already
explained offline artwork is not a launch requirement.
- `recoverInterruptedDownloads()` and `TrackerCoordinator.initialize()` ran from
`initState` of the widget whose first build produces the first app frame, and
the RSS watchdog installed a periodic timer there whose first useful sample is
15 s away regardless.
- `CredentialVault` decrypted every token with pure-Dart AES-GCM on the main
isolate, uncached, on every registry read and on every Drift re-emit -- and the
binder writes tokens during the startup sweep, so writes re-triggered reads.
Decryption is memoized by ciphertext, with `invalidateCache()` wired into the
preference-store repair path so a repaired install cannot serve stale plaintext.
- `reloadFromStorage` now coalesces in-flight callers. The two serial awaits around
the legacy migration are deliberately not merged; only genuinely concurrent
callers share a snapshot.
- `_sameConnections` ran two `jsonEncode` calls per connection on every Drift emit
purely to compare, allocating two maps and two strings each time.
- The splash rendered one `CircularProgressIndicator` per pending server on top of
the aggregate one, so N+1 tickers scheduled a frame every vsync for the whole of
`awaitBindingSettle` -- competing with the startup work they were reporting on.
Measured on device in a settled dexopt state: time to `main_screen` 1495 -> 1400 ms,
`credentials_loaded` 1238 -> 1128 ms, `database_ready` 501 -> 443 ms. First frame is
unchanged at ~18 ms, as expected.
MemoryLogOutput extended LogOutput but was never wired as a Logger output (storage happens in the printer); DeletionNotifier/WatchStateNotifier's forServer/forItem filtered streams and WatchStateEvent.mediaType had no production consumers (tests now filter .stream directly); context.hiddenLibraries/profileSettings and toPlexUrl had zero call sites; MonoTokens.splashFactory was never read; OptimizedMediaImage's enableTranscoding/cacheKey chains, FocusableMediaCard.width/height/forceGridMode, TvBrowseRail's constant-zero gap functions, and media_image_helper's scaleFactor were never varied by any caller. The sha1 LRU stays (rebuild-hot artwork URLs); TvRailTrailing.none and the mono-theme copyWith stay live (lerp delegates to copyWith). Also carries the MusicPlayContext.id argument drops in the music screens and remaining sweep test updates.
Introduces shared seams for paginated views, D-pad reorder, media control
routing, async singletons and the device method channel, then points the
open-coded copies at them.
Also removes unused models and duplicated provider/server plumbing, folds
the twice-implemented artifact store in the server, and factors the
repeated Flutter toolchain prologue in CI into a composite action.
Use GappedTrackShape (no stop indicator) globally.
Timeline/volume sliders get local overrides for thinner
track, zero padding, and no overlay. Chapter markers
rendered as track gaps. Live TV timeline matches style.
Timeline thumb hidden when unfocused in dpad mode.