From 0d171490c3fd3cc6b452a53a0c4a4c8eca5c4024 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 10 May 2026 10:18:38 -0400 Subject: [PATCH] fix(flutter): analyze errors after Plan B push MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleared 5 errors + 1 warning + 1 info from CI flutter analyze on 5114a81: - prefetcher.dart: Riverpod listener callbacks used (_, _) for two placeholder params — Dart 3 enforces unique names. Changed to (_, __). - prefetcher.dart: Riverpod 3's AsyncValue exposes `.value` (nullable) not `.valueOrNull`. Three call sites updated. - sync_controller.dart: doc comment had `?since=` → analyzer warned about unintended HTML. Wrapped in backticks with `{cursor}`. - sync_controller.dart: delete loop over heterogeneous Table list inferred as List; drift's delete() expects TableInfo. Unrolled to explicit per-table deletes. - audio_cache_manager_test.dart: db.into(...).insertAll([...]) doesn't exist on InsertStatement — only insert/insertOnConflictUpdate. Used db.batch((b) => b.insertAll(table, [...])) instead, in two test cases. - audio_handler.dart: LockCachingAudioSource is marked experimental in just_audio. Added // ignore: experimental_member_use — operator acknowledged the experimental status during brainstorming and we're the project; CI's --fatal-infos would otherwise gate. Co-Authored-By: Claude Opus 4.7 (1M context) --- flutter_client/lib/cache/prefetcher.dart | 10 ++-- flutter_client/lib/cache/sync_controller.dart | 18 +++----- flutter_client/lib/player/audio_handler.dart | 1 + .../test/cache/audio_cache_manager_test.dart | 46 +++++++++++-------- 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/flutter_client/lib/cache/prefetcher.dart b/flutter_client/lib/cache/prefetcher.dart index 12cbc2ea..0321ab87 100644 --- a/flutter_client/lib/cache/prefetcher.dart +++ b/flutter_client/lib/cache/prefetcher.dart @@ -18,18 +18,18 @@ class Prefetcher { // The mediaItem stream changes whenever the active track changes // (skipNext/skipPrev or natural progression). Settings changes (e.g. // operator bumps prefetch window) also trigger a reconcile. - _ref.listen>(mediaItemProvider, (_, _) => _reconcile()); - _ref.listen>(cacheSettingsProvider, (_, _) => _reconcile()); + _ref.listen>(mediaItemProvider, (_, __) => _reconcile()); + _ref.listen>(cacheSettingsProvider, (_, __) => _reconcile()); } final Ref _ref; Future _reconcile() async { - final settings = _ref.read(cacheSettingsProvider).valueOrNull; + final settings = _ref.read(cacheSettingsProvider).value; if (settings == null) return; - final queue = _ref.read(queueProvider).valueOrNull ?? const []; - final current = _ref.read(mediaItemProvider).valueOrNull; + final queue = _ref.read(queueProvider).value ?? const []; + final current = _ref.read(mediaItemProvider).value; if (queue.isEmpty || current == null) return; final currentIdx = queue.indexWhere((m) => m.id == current.id); diff --git a/flutter_client/lib/cache/sync_controller.dart b/flutter_client/lib/cache/sync_controller.dart index c58c4e1e..9484365f 100644 --- a/flutter_client/lib/cache/sync_controller.dart +++ b/flutter_client/lib/cache/sync_controller.dart @@ -19,7 +19,7 @@ class SyncResult { } /// Drives the delta-sync against the server (#357 Plan A endpoint). -/// Reads cursor from drift, calls /api/library/sync?since=, +/// Reads cursor from drift, calls `/api/library/sync?since={cursor}`, /// applies upserts + deletes, advances cursor. class SyncController extends AsyncNotifier { @override @@ -55,16 +55,12 @@ class SyncController extends AsyncNotifier { // local state and retry once with cursor=0. if (resp.statusCode == 410) { await db.transaction(() async { - for (final t in [ - db.cachedArtists, - db.cachedAlbums, - db.cachedTracks, - db.cachedLikes, - db.cachedPlaylists, - db.cachedPlaylistTracks, - ]) { - await db.delete(t).go(); - } + await db.delete(db.cachedArtists).go(); + await db.delete(db.cachedAlbums).go(); + await db.delete(db.cachedTracks).go(); + await db.delete(db.cachedLikes).go(); + await db.delete(db.cachedPlaylists).go(); + await db.delete(db.cachedPlaylistTracks).go(); await db.into(db.syncMetadata).insertOnConflictUpdate( SyncMetadataCompanion.insert(cursor: const drift.Value(0)), ); diff --git a/flutter_client/lib/player/audio_handler.dart b/flutter_client/lib/player/audio_handler.dart index 732bfdaa..d1ecfefe 100644 --- a/flutter_client/lib/player/audio_handler.dart +++ b/flutter_client/lib/player/audio_handler.dart @@ -114,6 +114,7 @@ class MinstrelAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandl final cacheFile = File('${cacheDir.path}/audio_cache/${t.id}.mp3'); debugPrint('audio_handler: cache miss for track.id=${t.id}, ' 'using LockCachingAudioSource → ${cacheFile.path}'); + // ignore: experimental_member_use return LockCachingAudioSource(parsed, headers: headers, cacheFile: cacheFile); } diff --git a/flutter_client/test/cache/audio_cache_manager_test.dart b/flutter_client/test/cache/audio_cache_manager_test.dart index 06f2cdee..fabd9326 100644 --- a/flutter_client/test/cache/audio_cache_manager_test.dart +++ b/flutter_client/test/cache/audio_cache_manager_test.dart @@ -31,12 +31,20 @@ void main() { dioFactory: () async => Dio(), cacheDirFactory: () async => tmp, ); - await db.into(db.audioCacheIndex).insertAll([ - AudioCacheIndexCompanion.insert( - trackId: 'a', path: 'p', sizeBytes: 100, source: CacheSource.manual), - AudioCacheIndexCompanion.insert( - trackId: 'b', path: 'p', sizeBytes: 250, source: CacheSource.incidental), - ]); + await db.batch((b) { + b.insertAll(db.audioCacheIndex, [ + AudioCacheIndexCompanion.insert( + trackId: 'a', + path: 'p', + sizeBytes: 100, + source: CacheSource.manual), + AudioCacheIndexCompanion.insert( + trackId: 'b', + path: 'p', + sizeBytes: 250, + source: CacheSource.incidental), + ]); + }); expect(await mgr.usageBytes(), 350); }); @@ -55,18 +63,20 @@ void main() { final f2 = File('${tmp.path}/audio_cache/man.mp3'); await f2.create(recursive: true); await f2.writeAsBytes(List.filled(100, 0)); - await db.into(db.audioCacheIndex).insertAll([ - AudioCacheIndexCompanion.insert( - trackId: 'inc', - path: f1.path, - sizeBytes: 100, - source: CacheSource.incidental), - AudioCacheIndexCompanion.insert( - trackId: 'man', - path: f2.path, - sizeBytes: 100, - source: CacheSource.manual), - ]); + await db.batch((b) { + b.insertAll(db.audioCacheIndex, [ + AudioCacheIndexCompanion.insert( + trackId: 'inc', + path: f1.path, + sizeBytes: 100, + source: CacheSource.incidental), + AudioCacheIndexCompanion.insert( + trackId: 'man', + path: f2.path, + sizeBytes: 100, + source: CacheSource.manual), + ]); + }); expect(await mgr.usageBytes(), 200); await mgr.evict(targetBytes: 100); expect(await mgr.isCached('inc'), false);