Fix critical data loss bugs and improve error handling
## Critical Fixes - Fix CRITICAL-1: Empty scans no longer delete entire library - Use timestamp-based tombstone logic instead of path-based - Only mark missing if livePaths is not empty - Fix CRITICAL-2: Re-scanned files now return from deleted state - Add deleted=false to SongsCompanion.insert in both scanners ## High Priority Fixes - HIGH-1: Fix SQLite variable limit crash on large libraries - Replace isNotIn() with timestamp comparison (O(1) not O(n)) - HIGH-2: Fix UI freezing during scan - Throttle progress updates (every 50 files or end of scan) - HIGH-3: Add error handling for scan failures - Wrap scanFolders/scanAndroidMediaStore in try/catch - Display scanError banner in LibraryScreen - HIGH-4: Add error handling for playback failures - Wrap loadPlaylist in try/catch ## Medium Priority Fixes - MEDIUM-1: Replace ! with ?? to handle unknown ProcessingState - MEDIUM-2: Escape LIKE wildcards in search queries - MEDIUM-4: Display StreamBuilder errors instead of treating as empty - MEDIUM-8: Add tooltips to all IconButtons for accessibility - Add doc comments to public database APIs ## Testing - Add regression tests for CRITICAL-1 and CRITICAL-2 - All 9 existing tests pass Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
b5ab7bd9dd
commit
4fa8d12fa0
@@ -68,9 +68,13 @@ Future<int> scanFolders(
|
||||
var coverPath = prev?.coverPath;
|
||||
final pics = meta?.pictures ?? const <Picture>[];
|
||||
if (pics.isNotEmpty && coverPath == null) {
|
||||
final f = File(p.join(covers.path, '$id.img'));
|
||||
await f.writeAsBytes(pics.first.bytes);
|
||||
coverPath = f.path;
|
||||
try {
|
||||
final f = File(p.join(covers.path, '$id.img'));
|
||||
await f.writeAsBytes(pics.first.bytes);
|
||||
coverPath = f.path;
|
||||
} catch (_) {
|
||||
// Kaputtes Cover verzögert nicht den Scan.
|
||||
}
|
||||
}
|
||||
|
||||
companions.add(SongsCompanion.insert(
|
||||
@@ -83,11 +87,17 @@ Future<int> scanFolders(
|
||||
coverPath: Value(coverPath),
|
||||
dateAddedMs: prev?.dateAddedMs ?? now,
|
||||
updatedAtMs: now,
|
||||
deleted: const Value(false),
|
||||
));
|
||||
onProgress?.call(++done, files.length);
|
||||
++done;
|
||||
if (done % 50 == 0 || done == files.length) {
|
||||
onProgress?.call(done, files.length);
|
||||
}
|
||||
}
|
||||
|
||||
await db.upsertSongs(companions);
|
||||
await db.markMissing(livePaths, now);
|
||||
if (livePaths.isNotEmpty) {
|
||||
await db.markMissing(now);
|
||||
}
|
||||
return companions.length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user