Skip to content

commit 1cd31b4

abduznik edited this page May 23, 2026 · 1 revision

feat(scanner): implement Lazy Sync on game detail screen

Commit: 1cd31b4eb0fc7eba585cf73e5cb7885dbef92d76

Author: abduznik

Date: 2026-04-28

Why: Adds a new feature or capability to the application.

Files Changed

lib/core/romm/rom_scanner_service.dart | 32 +++++++++++++++++++++++++++++++-
 lib/providers/romm_provider.dart       |  8 ++++++--
 lib/ui/screens/game_detail_screen.dart | 11 +++++++++++
 3 files changed, 48 insertions(+), 3 deletions(-)
  • lib/core/romm/rom_scanner_service.dart
  • lib/providers/romm_provider.dart
  • lib/ui/screens/game_detail_screen.dart

Diff

diff --git a/lib/core/romm/rom_scanner_service.dart b/lib/core/romm/rom_scanner_service.dart
index f538ff4..6f2dde4 100644
--- a/lib/core/romm/rom_scanner_service.dart
+++ b/lib/core/romm/rom_scanner_service.dart
@@ -5,6 +5,7 @@ import 'romm_service.dart';
 import '../storage/rom_mapping_service.dart';
 import 'romm_models.dart';
 import 'package:crypto/crypto.dart';
+import '../storage/directory_service.dart';
 
 class RomSyncResult {
   final String path;
@@ -20,8 +21,9 @@ class RomSyncResult {
 class RomScannerService {
   final RommService _rommService;
   final RomMappingService _mappingService;
+  final DirectoryService _directoryService;
 
-  RomScannerService(this._rommService, this._mappingService);
+  RomScannerService(this._rommService, this._mappingService, this._directoryService);
 
   /// Performs an incremental sync of the ROM directory.
   Stream<RomSyncResult> sync(String romsRoot) async* {
@@ -178,6 +180,34 @@ class RomScannerService {
     return sha1.convert(bytes).toString();
   }
 
+  /// Targeted sync for a single game. Useful for "Lazy Sync" on Detail screen.
+  Future<void> syncSingleGame(Game game) async {
+    final mappings = _mappingService.getMappings();
+    
+    // Check if we already have a mapping for this game ID
+    final existingPath = mappings.entries.where((e) => e.value == game.id).map((e) => e.key).firstOrNull;
+    
+    if (existingPath != null) {
+      // Verify if the file still exists
+      if (await File(existingPath).exists()) {
+        debugPrint('[RomScanner] Single Sync: ${game.name} already correctly mapped.');
+        return;
+      } else {
+        debugPrint('[RomScanner] Single Sync: ${game.name} was mapped to missing file. Removing.');
+        await _mappingService.removeMapping(existingPath);
+      }
+    }
+
+    // Try to find the game on disk using DirectoryService's robust logic
+    final foundPath = await _directoryService.findExistingRomPath(game);
+    if (foundPath != null) {
+      debugPrint('[RomScanner] Single Sync REPAIR: Found ${game.name} at $foundPath');
+      await _mappingService.updateMapping(foundPath, game.id);
+    } else {
+      debugPrint('[RomScanner] Single Sync: ${game.name} not found on disk.');
+    }
+  }
+
   /// Clean a name for fuzzy matching by removing tags in [] or () and special characters
   String _cleanName(String name) {
     return name.toLowerCase()
diff --git a/lib/providers/romm_provider.dart b/lib/providers/romm_provider.dart
index ed46e9f..66855fc 100644
--- a/lib/providers/romm_provider.dart
+++ b/lib/providers/romm_provider.dart
@@ -189,9 +189,13 @@ final romMappingServiceProvider = FutureProvider<RomMappingService>((ref) async
 final romScannerServiceProvider = Provider<RomScannerService?>((ref) {
   final rommService = ref.watch(rommServiceProvider);
   final mappingServiceAsync = ref.watch(romMappingServiceProvider);
+  final directoryServiceAsync = ref.watch(directoryServiceProvider);
   
-  if (rommService != null && mappingServiceAsync.hasValue) {
-    return RomScannerService(rommService, mappingServiceAsync.value!);
+  final mappingService = mappingServiceAsync.asData?.value;
+  final directoryService = directoryServiceAsync.asData?.value;
+
+  if (rommService != null && mappingService != null && directoryService != null) {
+    return RomScannerService(rommService, mappingService, directoryService);
   }
   return null;
 });
diff --git a/lib/ui/screens/game_detail_screen.dart b/lib/ui/screens/game_detail_screen.dart
index 7266fac..77ee52b 100644
--- a/lib/ui/screens/game_detail_screen.dart
+++ b/lib/ui/screens/game_detail_screen.dart
@@ -60,10 +60,21 @@ class _GameDetailScreenState extends ConsumerState<GameDetailScreen> {
     _isDownloaded = widget.isDownloaded;
     _syncStateWithGame(_currentGame);
     _checkDownloadStatus();
+    // Targeted Lazy Sync: Ensure this game is mapped if it exists on disk
+    _lazySync();
     // Initial refresh to get latest notes and status
     _refreshGame();
   }
 
+  Future<void> _lazySync() async {
+    final scanner = ref.read(romScannerServiceProvider);
+    if (scanner != null) {
+      await scanner.syncSingleGame(_currentGame);
+      // Re-check status after sync to update the "Play" button if found
+      _checkDownloadStatus();
+    }
+  }
+
   void _syncStateWithGame(Game game) {
     _backlogged = game.backlogged;
     _nowPlaying = game.nowPlaying;

Clone this wiki locally