Files
minstrel/android
bvandeusen 2a87a50b81 feat(android): offline-pool Home cards (audit v3 §4.3) — closes #28
Faithful port of Flutter's _OfflinePoolCard + shuffle_source.dart.
I was wrong earlier that Android lacked the source — the
audio_cache_index table already carries lastPlayedAt, exactly what
Flutter reads.

* ShuffleSource @Singleton over the local cache: recentlyPlayed()
  = audio_cache_index ordered by lastPlayedAt desc, materialized
  from cached_tracks; liked() = same ∩ the liked track-id set.
  Both are unions over the cache regardless of storage bucket,
  matching Flutter's note that the bucket split is eviction-only.
* OfflinePoolCard widget (sized to match PlaylistCard).
* AudioCacheIndexDao.trackIdsByRecency(); LikesRepository.likedTrackIds().
* HomeViewModel: offline StateFlow from ConnectivityObserver,
  playPool(kind) shuffles + plays (snackbar "No cached X tracks yet"
  when empty), transientMessages channel.
* buildPlaylistsRow gains an `offline` flag; when offline the two
  pool cards (Recently played, Liked) LEAD the Playlists row, before
  the system slots — the rest of the row (placeholders + user
  playlists) renders regardless, exactly as Flutter does.
* HomeScreen gains a SnackbarHost for the empty-pool message.

Together with edbc8053 (placeholders) this closes audit v3 #28.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 07:52:55 -04:00
..