Skip to content

commit fdf90a0

abduznik edited this page May 23, 2026 · 1 revision

feat: implement Home tab and thread-safe ROM mapping database

Commit: fdf90a002dbdf0f106316d294a1a78b85ea7fbc8

Author: abduznik

Date: 2026-04-18

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

Files Changed

lib/core/storage/rom_mapping_service.dart | 23 ++++++++++++++---------
 lib/ui/widgets/platform_filter_bar.dart   | 28 +++++++++++++++++++++++++---
 pubspec.lock                              |  2 +-
 pubspec.yaml                              |  1 +
 4 files changed, 41 insertions(+), 13 deletions(-)
  • lib/core/storage/rom_mapping_service.dart
  • lib/ui/widgets/platform_filter_bar.dart
  • pubspec.lock
  • pubspec.yaml

Diff

diff --git a/lib/core/storage/rom_mapping_service.dart b/lib/core/storage/rom_mapping_service.dart
index a024910..d426403 100644
--- a/lib/core/storage/rom_mapping_service.dart
+++ b/lib/core/storage/rom_mapping_service.dart
@@ -1,10 +1,11 @@
 import 'package:hive_flutter/hive_flutter.dart';
+import 'package:synchronized/synchronized.dart';
 
 class RomMappingService {
   static const String _boxName = 'rom_mappings_v2';
   late Box _box;
+  final _lock = Lock();
 
-  // Prefix keys to avoid collisions
   static const String _prefixMapping = 'map_';
   static const String _prefixMTime = 'mtime_';
   static const String _keyLastSync = 'last_sync_time';
@@ -13,7 +14,6 @@ class RomMappingService {
     _box = await Hive.openBox(_boxName);
   }
 
-  /// Get all FilePath -> RomID mappings
   Map<String, String> getMappings() {
     final Map<String, String> mappings = {};
     for (var key in _box.keys) {
@@ -25,14 +25,11 @@ class RomMappingService {
   }
 
   Future<void> updateMapping(String path, String romId) async {
-    await _box.put('$_prefixMapping$path', romId);
+    await _lock.synchronized(() async {
+      await _box.put('$_prefixMapping$path', romId);
+    });
   }
 
-  Future<void> removeMapping(String path) async {
-    await _box.delete('$_prefixMapping$path');
-  }
-
-  /// Map of DirectoryPath -> LastModifiedTimestamp (ms)
   Map<String, int> getMTimes() {
     final Map<String, int> mtimes = {};
     for (var key in _box.keys) {
@@ -44,7 +41,9 @@ class RomMappingService {
   }
 
   Future<void> updateMTime(String path, int timestamp) async {
-    await _box.put('$_prefixMTime$path', timestamp);
+    await _lock.synchronized(() async {
+      await _box.put('$_prefixMTime$path', timestamp);
+    });
   }
 
   int? getLastSyncTime() {
@@ -59,6 +58,12 @@ class RomMappingService {
     return _box.get('$_prefixMapping$path');
   }
 
+  Future<void> removeMapping(String path) async {
+    await _lock.synchronized(() async {
+      await _box.delete('$_prefixMapping$path');
+    });
+  }
+
   Future<void> clear() async {
     await _box.clear();
   }
diff --git a/lib/ui/widgets/platform_filter_bar.dart b/lib/ui/widgets/platform_filter_bar.dart
index e81dd70..e288819 100644
--- a/lib/ui/widgets/platform_filter_bar.dart
+++ b/lib/ui/widgets/platform_filter_bar.dart
@@ -6,22 +6,26 @@ class PlatformFilterBar extends StatelessWidget {
   final List<Platform> platforms;
   final int? selectedPlatformId;
   final bool downloadedOnly;
+  final bool isHome;
   final Function(Platform?) onSelected;
   final Function(bool) onDownloadedToggle;
+  final VoidCallback onHomeSelected;
 
   const PlatformFilterBar({
     super.key,
     required this.platforms,
     required this.selectedPlatformId,
     required this.downloadedOnly,
+    required this.isHome,
     required this.onSelected,
     required this.onDownloadedToggle,
+    required this.onHomeSelected,
   });
 
   @override
   Widget build(BuildContext context) {
     final colorScheme = Theme.of(context).colorScheme;
-    final isAllSelected = selectedPlatformId == null;
+    final isAllSelected = selectedPlatformId == null && !isHome;
 
     return ScrollConfiguration(
       behavior: ScrollConfiguration.of(context).copyWith(
@@ -36,6 +40,25 @@ class PlatformFilterBar extends StatelessWidget {
         padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
         child: Row(
           children: [
+            Padding(
+              padding: const EdgeInsets.only(right: 8.0),
+              child: ChoiceChip(
+                avatar: Icon(
+                  Icons.home,
+                  size: 16,
+                  color: isHome ? Colors.white : colorScheme.primary,
+                ),
+                label: const Text('Home'),
+                selected: isHome,
+                onSelected: (selected) {
+                  if (selected) onHomeSelected();
+                },
+                backgroundColor: isHome ? colorScheme.primary : null,
+                labelStyle: TextStyle(
+                  color: isHome ? Colors.white : colorScheme.onSurface,
+                ),
+              ),
+            ),
             Padding(
               padding: const EdgeInsets.only(right: 8.0),
               child: FilterChip(
@@ -72,7 +95,7 @@ class PlatformFilterBar extends StatelessWidget {
               ),
             ),
             ...platforms.map((platform) {
-              final isSelected = selectedPlatformId == platform.id;
+              final isSelected = selectedPlatformId == platform.id && !isHome;
               return Padding(
                 padding: const EdgeInsets.only(right: 8.0),
                 child: FilterChip(
@@ -81,7 +104,6 @@ class PlatformFilterBar extends StatelessWidget {
                   onSelected: (selected) {
                     onSelected(selected ? platform : null);
                   },
-                  // Styling for selected platform chip
                   backgroundColor: isSelected ? colorScheme.primary : null,
                   labelStyle: TextStyle(
                     color: isSelected ? Colors.white : colorScheme.onSurface,
diff --git a/pubspec.lock b/pubspec.lock
index 32610cd..8b2297d 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -982,7 +982,7 @@ packages:
     source: hosted
     version: "1.4.1"
   synchronized:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: synchronized
       sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
diff --git a/pubspec.yaml b/pubspec.yaml
index f240786..8272c4b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -50,6 +50,7 @@ dependencies:
   url_launcher: ^6.3.2
   hive: ^2.2.3
   hive_flutter: ^1.1.0
+  synchronized: ^3.1.0+1
 
 dev_dependencies:
   flutter_test:

Clone this wiki locally