-
-
Notifications
You must be signed in to change notification settings - Fork 14
commit 8203c44
abduznik edited this page May 23, 2026
·
1 revision
Commit: 8203c44e831c7b5226000e810ad86a79d11b837d
Author: abduznik
Date: 2026-04-28
Why: Fixes a bug or regression in the existing codebase.
lib/app.dart | 4 ++
.../linux_strategies/emudeck_strategy.dart | 13 +++++
lib/core/storage/file_sanity_service.dart | 66 ++++++++++++++++++++++
3 files changed, 83 insertions(+)
lib/app.dartlib/core/emulator/linux_strategies/emudeck_strategy.dartlib/core/storage/file_sanity_service.dart
diff --git a/lib/app.dart b/lib/app.dart
index 6b1a6dd..44a3e7f 100644
--- a/lib/app.dart
+++ b/lib/app.dart
@@ -12,6 +12,7 @@ import 'ui/screens/download_screen.dart';
import 'ui/screens/settings_screen.dart';
import 'ui/screens/onboarding_screen.dart';
import 'providers/ui_provider.dart';
+import 'core/storage/file_sanity_service.dart';
class CustomScrollBehavior extends MaterialScrollBehavior {
@override
@@ -74,6 +75,9 @@ class _FreegosyAppState extends ConsumerState<FreegosyApp> {
}
});
+ // Keep the file sanity service alive and running in the background
+ ref.watch(fileSanityServiceProvider);
+
final currentIndex = ref.watch(currentTabIndexProvider);
return ExcludeSemantics(
diff --git a/lib/core/emulator/linux_strategies/emudeck_strategy.dart b/lib/core/emulator/linux_strategies/emudeck_strategy.dart
index 1940bf6..ff0d1cb 100644
--- a/lib/core/emulator/linux_strategies/emudeck_strategy.dart
+++ b/lib/core/emulator/linux_strategies/emudeck_strategy.dart
@@ -13,6 +13,13 @@ class EmuDeckStrategy extends LinuxEnvironmentStrategy {
@override
String getRomsRoot(String home, String? customPath, String? emudeckRoot) {
if (emudeckRoot != null) {
+ // Robustness: if user pointed directly to 'Emulation' or 'Emulation/roms', handle it
+ if (p.basename(emudeckRoot).toLowerCase() == 'roms' && p.basename(p.dirname(emudeckRoot)).toLowerCase() == 'emulation') {
+ return customPath ?? emudeckRoot;
+ }
+ if (p.basename(emudeckRoot).toLowerCase() == 'emulation') {
+ return customPath ?? p.join(emudeckRoot, 'roms');
+ }
return customPath ?? p.join(emudeckRoot, 'Emulation/roms');
}
return customPath ?? p.join(home, 'ROMs');
@@ -21,6 +28,12 @@ class EmuDeckStrategy extends LinuxEnvironmentStrategy {
@override
String getEmulatorsRoot(String home, String? customPath, String? emudeckRoot) {
if (emudeckRoot != null) {
+ if (p.basename(emudeckRoot).toLowerCase() == 'tools' && p.basename(p.dirname(emudeckRoot)).toLowerCase() == 'emulation') {
+ return customPath ?? emudeckRoot;
+ }
+ if (p.basename(emudeckRoot).toLowerCase() == 'emulation') {
+ return customPath ?? p.join(emudeckRoot, 'tools');
+ }
return customPath ?? p.join(emudeckRoot, 'Emulation/tools');
}
return customPath ?? p.join(home, 'Emulators');
diff --git a/lib/core/storage/file_sanity_service.dart b/lib/core/storage/file_sanity_service.dart
new file mode 100644
index 0000000..6b7efd6
--- /dev/null
+++ b/lib/core/storage/file_sanity_service.dart
@@ -0,0 +1,66 @@
+import 'dart:async';
+import 'dart:io' as io;
+import 'package:flutter/foundation.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:freegosy/core/storage/directory_service.dart';
+import 'package:freegosy/core/storage/rom_mapping_service.dart';
+import 'package:freegosy/core/storage/download_cache_service.dart';
+import 'package:freegosy/providers/romm_provider.dart';
+
+class FileSanityService {
+ final RomMappingService _mappingService;
+ final DownloadCacheService _cacheService;
+ Timer? _timer;
+
+ FileSanityService(this._mappingService, this._cacheService);
+
+ void start() {
+ _timer?.cancel();
+ // Run every 10 minutes
+ _timer = Timer.periodic(const Duration(minutes: 10), (_) => pruneStaleEntries());
+ // Also run once immediately
+ pruneStaleEntries();
+ }
+
+ void stop() {
+ _timer?.cancel();
+ }
+
+ Future<void> pruneStaleEntries() async {
+ debugPrint('[Sanity] Checking for stale ROM mappings...');
+ final mappings = _mappingService.getMappings();
+ int removedCount = 0;
+
+ for (final entry in mappings.entries) {
+ final path = entry.key;
+ final file = io.File(path);
+
+ if (!file.existsSync()) {
+ debugPrint('[Sanity] File no longer exists, removing mapping: $path');
+ await _mappingService.removeMapping(path);
+ _cacheService.removeFile(io.File(path).path); // Best effort removal from cache
+ removedCount++;
+ }
+ }
+
+ if (removedCount > 0) {
+ debugPrint('[Sanity] Pruned $removedCount stale entries.');
+ }
+ }
+}
+
+final fileSanityServiceProvider = Provider<FileSanityService?>((ref) {
+ final dirService = ref.watch(directoryServiceProvider).asData?.value;
+ final mappingServiceAsync = ref.watch(romMappingServiceProvider);
+ final cacheService = ref.watch(downloadCacheServiceProvider);
+
+ if (!mappingServiceAsync.hasValue) {
+ return null;
+ }
+
+ final service = FileSanityService(mappingServiceAsync.value!, cacheService);
+ service.start();
+
+ ref.onDispose(() => service.stop());
+ return service;
+});