diff --git a/flutter_client/lib/playlists/playlists_provider.dart b/flutter_client/lib/playlists/playlists_provider.dart index c0164b5b..092bca37 100644 --- a/flutter_client/lib/playlists/playlists_provider.dart +++ b/flutter_client/lib/playlists/playlists_provider.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:dio/dio.dart'; import 'package:drift/drift.dart' as drift; import 'package:flutter/foundation.dart' show debugPrint; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -44,7 +45,21 @@ final playlistsListProvider = debugPrint( 'playlistsListProvider($kind): wire returned owned=${fresh.owned.length} ' '(system=$ownedSysCount) public=${fresh.public.length}'); + + // Reconcile: BuildSystemPlaylists rotates system-playlist UUIDs + // every rebuild, so insertOrReplace alone leaves stale rows in + // drift. Tapping one of those stale tiles 404s. Delete every + // owned drift row whose id isn't in the fresh response, then + // upsert the fresh set. + final freshOwnedIds = + fresh.owned.map((p) => p.id).toSet(); await db.batch((b) { + if (user != null) { + b.deleteWhere(db.cachedPlaylists, (t) { + return t.userId.equals(user.id) & + t.id.isNotIn(freshOwnedIds); + }); + } for (final p in fresh.all) { b.insert(db.cachedPlaylists, p.toDrift(), mode: drift.InsertMode.insertOrReplace); @@ -216,6 +231,21 @@ final playlistDetailProvider = 'playlistDetailProvider($id): drift write done; awaiting watch re-emit'); return true; } catch (e, st) { + // 404 = the playlist row in drift is stale (BuildSystemPlaylists + // rotates UUIDs on each rebuild, so old For-You / Songs-Like + // tiles can outlive the actual server-side playlist). Wipe the + // stale row + its track positions so the home tile disappears + // on next render and we don't keep trying. + if (e is DioException && e.response?.statusCode == 404) { + debugPrint( + 'playlistDetailProvider($id): server says 404, evicting stale drift rows'); + await db.batch((b) { + b.deleteWhere( + db.cachedPlaylistTracks, (t) => t.playlistId.equals(id)); + b.deleteWhere(db.cachedPlaylists, (t) => t.id.equals(id)); + }); + return false; + } debugPrint('playlistDetailProvider($id): fetch failed: $e\n$st'); return false; }