refactor(flutter): drop legacy home snapshot path (#406)
The home screen renders solely from the per-item cached_home_index path (proven on devices for many releases); the legacy snapshot stack was dead weight. - library_providers: remove homeProvider + _encodeHomeData + _albumToJson/_artistToJson/_trackToJson; drop now-unused dart:convert and models/home_data.dart imports - metadata_prefetcher: re-point off homeIndexProvider/HomeIndex — pre-warm artistProvider from the rediscover/last-played artist sections (album/track tiles hydrate their own artist on render) - live_events_dispatcher: homeProvider -> homeIndexProvider so live events still refresh the home screen - db.dart: drop CachedHomeSnapshot (table class + @DriftDatabase entry); schemaVersion 10->11; from<3 createTable -> raw customStatement so the historical step compiles without the generated symbol; from<11 DROP TABLE cached_home_snapshot No test references the removed symbols. db.g.dart regenerated by CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+20
-19
@@ -120,19 +120,6 @@ class SyncMetadata extends Table {
|
||||
Set<Column> get primaryKey => {id};
|
||||
}
|
||||
|
||||
/// Single-row cache of the /api/home response (#357 follow-up). The
|
||||
/// home screen is the first thing the user sees on app open; storing
|
||||
/// the last successful HomeData as JSON lets us yield it immediately
|
||||
/// before the REST round-trip resolves, eliminating the cold-start
|
||||
/// blank on slow / remote connections. Schema 3+.
|
||||
class CachedHomeSnapshot extends Table {
|
||||
IntColumn get id => integer().withDefault(const Constant(1))();
|
||||
TextColumn get json => text()();
|
||||
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
}
|
||||
|
||||
/// Single-row cache of the /api/me/history response. Mirrors the
|
||||
/// CachedHomeSnapshot pattern: opening the History tab in the Library
|
||||
/// screen yields the last-known page immediately while a fresh REST
|
||||
@@ -255,7 +242,6 @@ enum CacheSource { manual, autoLiked, autoPlaylist, autoPrefetch, incidental }
|
||||
CachedPlaylistTracks,
|
||||
AudioCacheIndex,
|
||||
SyncMetadata,
|
||||
CachedHomeSnapshot,
|
||||
CachedHistorySnapshot,
|
||||
CachedQuarantineMine,
|
||||
CachedHomeIndex,
|
||||
@@ -267,7 +253,7 @@ class AppDb extends _$AppDb {
|
||||
AppDb([QueryExecutor? e]) : super(e ?? driftDatabase(name: 'minstrel_cache'));
|
||||
|
||||
@override
|
||||
int get schemaVersion => 10;
|
||||
int get schemaVersion => 11;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy(
|
||||
@@ -284,10 +270,16 @@ class AppDb extends _$AppDb {
|
||||
await customStatement('UPDATE sync_metadata SET cursor = 0');
|
||||
}
|
||||
if (from < 3) {
|
||||
// Schema 3: cached_home_snapshot for #357 drift-first
|
||||
// home page. No existing rows to migrate — table starts
|
||||
// empty; the first /api/home fetch populates it.
|
||||
await m.createTable(cachedHomeSnapshot);
|
||||
// Schema 3: cached_home_snapshot (legacy drift-first home).
|
||||
// The table + its homeProvider/JSON encoders were removed
|
||||
// in #406; recreated here as raw SQL so this historical
|
||||
// step still compiles without the generated table symbol.
|
||||
// The from<11 step below drops it.
|
||||
await customStatement(
|
||||
'CREATE TABLE IF NOT EXISTS "cached_home_snapshot" '
|
||||
'("id" INTEGER NOT NULL DEFAULT 1, "json" TEXT, '
|
||||
'"updated_at" INTEGER, PRIMARY KEY ("id"));',
|
||||
);
|
||||
}
|
||||
if (from < 4) {
|
||||
// Schema 4: cached_history_snapshot for drift-first
|
||||
@@ -337,6 +329,15 @@ class AppDb extends _$AppDb {
|
||||
// first persist populates it.
|
||||
await m.createTable(cachedResumeState);
|
||||
}
|
||||
if (from < 11) {
|
||||
// Schema 11 (#406): drop the legacy cached_home_snapshot
|
||||
// table. The home screen now renders solely from the
|
||||
// per-item cached_home_index path; the legacy homeProvider
|
||||
// + its JSON encoders were removed.
|
||||
await customStatement(
|
||||
'DROP TABLE IF EXISTS "cached_home_snapshot";',
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+15
-22
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../library/library_providers.dart';
|
||||
import '../models/home_data.dart';
|
||||
import '../models/home_index.dart';
|
||||
|
||||
/// Pre-warms the drift cache for likely-tap targets. Conservative on
|
||||
/// purpose: only warms artistProvider rows (single row, single round
|
||||
@@ -10,10 +10,15 @@ import '../models/home_data.dart';
|
||||
/// list when missing, and pre-warming N albums fans out N parallel
|
||||
/// "fetch tracks" round trips that compete with the user's actual
|
||||
/// playback request for bandwidth.
|
||||
///
|
||||
/// Driven off the per-item home path (homeIndexProvider). Only the
|
||||
/// artist-typed sections (rediscover / last-played artists) carry
|
||||
/// artist ids directly; album/track tiles hydrate their own artist on
|
||||
/// render via the per-item path, so warming those here is unnecessary.
|
||||
class MetadataPrefetcher {
|
||||
MetadataPrefetcher(this._ref) {
|
||||
_ref.listen<AsyncValue<HomeData>>(homeProvider, (_, next) {
|
||||
next.whenData(_warmHome);
|
||||
_ref.listen<AsyncValue<HomeIndex>>(homeIndexProvider, (_, next) {
|
||||
next.whenData(_warmIndex);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,7 +29,8 @@ class MetadataPrefetcher {
|
||||
/// ids we've already warmed.
|
||||
final Set<String> _warmedArtists = {};
|
||||
|
||||
/// Cap per section. Covers what fits on screen without scrolling.
|
||||
/// Cap warmed per emission. Covers what fits on screen without
|
||||
/// scrolling.
|
||||
static const _topN = 8;
|
||||
|
||||
/// Pre-warm artists. Albums are intentionally not pre-warmed —
|
||||
@@ -39,24 +45,11 @@ class MetadataPrefetcher {
|
||||
}
|
||||
}
|
||||
|
||||
void _warmHome(HomeData h) {
|
||||
final artistIds = <String>{};
|
||||
for (final a in h.recentlyAddedAlbums.take(_topN)) {
|
||||
if (a.artistId.isNotEmpty) artistIds.add(a.artistId);
|
||||
}
|
||||
for (final a in h.rediscoverAlbums.take(_topN)) {
|
||||
if (a.artistId.isNotEmpty) artistIds.add(a.artistId);
|
||||
}
|
||||
for (final ar in h.rediscoverArtists.take(_topN)) {
|
||||
if (ar.id.isNotEmpty) artistIds.add(ar.id);
|
||||
}
|
||||
for (final ar in h.lastPlayedArtists.take(_topN)) {
|
||||
if (ar.id.isNotEmpty) artistIds.add(ar.id);
|
||||
}
|
||||
for (final t in h.mostPlayedTracks.take(_topN)) {
|
||||
if (t.artistId.isNotEmpty) artistIds.add(t.artistId);
|
||||
}
|
||||
warmArtists(artistIds);
|
||||
void _warmIndex(HomeIndex h) {
|
||||
warmArtists(<String>{
|
||||
...h.rediscoverArtists.take(_topN),
|
||||
...h.lastPlayedArtists.take(_topN),
|
||||
});
|
||||
}
|
||||
|
||||
/// Discards the return value and any error from a fire-and-forget
|
||||
|
||||
Reference in New Issue
Block a user