86d67f6fc6
Previous fixes layered AnimatedSwitcher fades on top of a race: the audio_handler broadcasts MediaItem twice on every track change (bare metadata first, then with artUri once AlbumCoverCache resolves) and the image bytes themselves decode asynchronously after the widget mounts. The fades just smeared the resulting placeholder flash without addressing the underlying ordering. Rewrite the decision process around "load first, then swap": **Mini player** (rapid change is acceptable per operator preference): - Drop AnimatedSwitcher entirely - PlayerBar becomes stateful, holds the most-recent non-null artUri - Builds the child MediaItem with artUri = currentArtUri ?? _lastArtUri, so the previous cover stays visible across the null-artUri gap and the new cover snaps in the moment its artUri arrives **Full player** (operator wants the image fully loaded before any visible change): - Introduce _displayedMedia + _displayedDominant state - ref.listen on mediaItemProvider schedules a preload for each new track id (and for the artUri-bearing rebroadcast on the same id) - _scheduleSwap awaits precacheImage on the file:// artUri AND awaits albumColorProvider's future for the dominant color - Only then setState flips _displayedMedia + _displayedDominant in one frame — cover, title, gradient all advance atomically - Drop the per-element AnimatedSwitcher wrappers; the backdrop AnimatedContainer still tweens between successive dominant colors so the gradient transition is smooth, not snap Concurrency: rapid skips drop stale preload completions via _pendingPreloadId. Decode/color failures fall through to the previous dominant + the ServerImage/error-builder fallbacks.