Android #618 offline-mode UX + Sonos polish + server DRY #81
Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
10 commits since v2026.06.04.
Android #618 — offline-mode UX composite (Phases 1, 3, 2, 4, 5)
The five sub-phases of #618 land together as a single coherent offline experience.
ServerHealthControllertri-state (Healthy / Offline / ServerDown) composed fromConnectivityObserver.online+VersionCheckController.reachable. Banner copy distinguishes "no device network" from "server unreachable" so the user can act on it.VersionCheckControllergains areachable: StateFlow<Boolean>driven by the existing 5-min/healthzpoll.OfflineGatedDataSourcewraps theOkHttpDataSourceupstream ofCacheDataSource. On a cache miss while ServerHealth is non-Healthy, it throwsOfflineExceptionimmediately instead of letting OkHttp wait out a multi-second timeout (which then surfaced as a silent decode failure). Cached playback unaffected —CacheDataSourceonly consults upstream on miss.SearchRepositoryfalls back to Room LIKE queries overcached_artists/cached_albums/cached_trackswhen offline. NewsearchByName/searchByTitleDAOs; the screen shows a one-line "on-device only" hint above the results.TrackRowconsumes newLocalServerHealthCompositionLocal. Tracks not inLocalCachedTrackIdsdim to 0.4 alpha when offline; tap fires a Toast ("Not downloaded — connect to play") instead of attempting playback. Trailing slot (kebab, like, playlist-add) stays interactive so write affordances can queue.MutationQueueemits auserEnqueueHints: SharedFlow<String>on user-driven enqueues (like toggle, playlist append, request create/cancel, quarantine flag/unflag). ShellScaffold subscribes viaOfflineWriteHintViewModeland surfaces "Saved — will sync when online" via its snackbar host. Background enqueues (play-events, playback-error reports) don't emit — those fire from non-foreground paths.Android — Sonos polish
MediaSession picks up UPnP state—MinstrelForwardingPlayerdirectly invokesPlayer.Listener.onIsPlayingChanged/onPlaybackStateChanged/onMediaItemTransitionwhenremoteStatemutates, so the notification card and lock-screen heart track the actual Sonos transport.UPnP extend throttle— 50ms delay between consecutiveAddURIToQueueSOAP calls inextendQueueOnSonos, preventing the burst-rate-limit that Sonos was hitting on queue-extension flushes.Server / CI
Unify stream URL builders + MIME tables + cover-path helper— closes the divergent-provider audit from 2026-06-04.streamURLhelper used everywhere;audioContentTypeis the canonicalfile_format → MIMElookup;coverart.ResolveAlbumPathextracted;api/media.goandsubsonic/stream.goboth delegate.Collage center-crop—drawScaledno longer nearest-neighbor stretches non-square covers to fill 300×300 cells. Now preserves aspect + center-crops, matching every other UI surface. Existing collages re-render on the next 03:00 system-playlist rebuild.CI integration test 2.4× speedup—ALTER SYSTEM SET fsync = off / synchronous_commit = off / full_page_writes = offon the throwaway CI Postgres before migrations. Wall-clock 10m34s → 4m27s;internal/api7.8×.Test plan