-
-
Notifications
You must be signed in to change notification settings - Fork 14
commit 610c5c2
abduznik edited this page May 23, 2026
·
1 revision
Commit: 610c5c2285ed7d011e16fbb27fa7f994b52a74cc
Author: abduznik
Date: 2026-04-28
Why: Adds a new feature or capability to the application.
lib/core/storage/directory_service.dart | 25 +++++++++---
lib/core/storage/logger_service.dart | 50 +++++++++++++++++++++++
lib/main.dart | 3 ++
lib/ui/screens/settings_screen.dart | 72 +++++++++++++++++++++++++++++++++
4 files changed, 144 insertions(+), 6 deletions(-)
lib/core/storage/directory_service.dartlib/core/storage/logger_service.dartlib/main.dartlib/ui/screens/settings_screen.dart
diff --git a/lib/core/storage/directory_service.dart b/lib/core/storage/directory_service.dart
index b01f152..a070962 100644
--- a/lib/core/storage/directory_service.dart
+++ b/lib/core/storage/directory_service.dart
@@ -87,7 +87,7 @@ class DirectoryService {
'nes': ['.nes', '.zip'],
'psx': ['.bin', '.cue', '.iso', '.img', '.chd'],
'ps2': ['.iso', '.bin', '.chd'],
- 'ps3': ['.pkg', '.iso'],
+ 'ps3': ['.pkg', '.iso', '.bin', '.edat'],
'psp': ['.iso', '.cso', '.pbp'],
'gc': ['.iso', '.gcm', '.rvz', '.wbfs'],
'gamecube': ['.iso', '.gcm', '.rvz', '.wbfs'],
@@ -452,6 +452,8 @@ class DirectoryService {
final romDir = await getRomDirectory(game);
final platformLower = game.platformSlug?.toLowerCase();
+ debugPrint('[Matching] Searching for ${game.name} (Platform: $platformLower) in $romDir');
+
// Names to check (in order of priority)
final namesToCheck = <String>[];
if (game.fsName != null) namesToCheck.add(game.fsName!);
@@ -466,10 +468,14 @@ class DirectoryService {
final lowerName = name.toLowerCase();
// Try exact name match (files)
- if (index.files.containsKey(lowerName)) return index.files[lowerName];
+ if (index.files.containsKey(lowerName)) {
+ debugPrint('[Matching] Index hit (file): $lowerName');
+ return index.files[lowerName];
+ }
// Try name match (dirs)
if (index.dirs.containsKey(lowerName)) {
+ debugPrint('[Matching] Index hit (dir): $lowerName');
final found = await _findMainRomInFolder(game, index.dirs[lowerName]!);
if (found != null) return found;
}
@@ -579,13 +585,18 @@ class DirectoryService {
} catch (_) {}
}
+ debugPrint('[Matching] No match found for ${game.name}');
return null;
}
/// Finds the largest ROM-like file in a folder.
Future<String?> _findMainRomInFolder(Game game, String folderPath) async {
- final isWindowsGame = ['windows', 'pc', 'win'].contains(game.platformSlug?.toLowerCase() ?? '');
- if (isWindowsGame) return p.absolute(folderPath);
+ final platform = game.platformSlug?.toLowerCase() ?? '';
+ final isFolderBased = ['windows', 'pc', 'win', 'ps3', 'switch', 'nintendo-switch'].contains(platform);
+ if (isFolderBased) {
+ // For folder-based platforms, we can often just return the folder path if it's a direct match
+ // But we still try to find a "main" file inside first for better emulator compatibility
+ }
final extensions = _platformExtensions[game.platformSlug?.toLowerCase()] ?? [];
@@ -609,10 +620,12 @@ class DirectoryService {
} catch (_) {}
if (largestFile != null) {
- // If there's only one ROM-like file, or one is significantly larger (e.g. 2x the next one)
- // we can be fairly certain it's the main ROM.
return p.absolute(largestFile.path);
}
+
+ // Fallback for PS3/Switch folders that might not have a "known" extension but are valid
+ if (isFolderBased) return p.absolute(folderPath);
+
return null;
}
diff --git a/lib/core/storage/logger_service.dart b/lib/core/storage/logger_service.dart
new file mode 100644
index 0000000..1689861
--- /dev/null
+++ b/lib/core/storage/logger_service.dart
@@ -0,0 +1,50 @@
+import 'dart:async';
+import 'package:flutter/foundation.dart';
+
+class LogEntry {
+ final DateTime timestamp;
+ final String message;
+ final String? level;
+
+ LogEntry(this.message, {this.level, DateTime? timestamp})
+ : timestamp = timestamp ?? DateTime.now();
+
+ @override
+ String toString() => '[${timestamp.toIso8601String().substring(11, 19)}] ${level != null ? '[$level] ' : ''}$message';
+}
+
+class LoggerService {
+ static final LoggerService _instance = LoggerService._internal();
+ factory LoggerService() => _instance;
+ LoggerService._internal();
+
+ final List<LogEntry> _logs = [];
+ final StreamController<List<LogEntry>> _controller = StreamController<List<LogEntry>>.broadcast();
+
+ List<LogEntry> get logs => List.unmodifiable(_logs);
+ Stream<List<LogEntry>> get logStream => _controller.stream;
+
+ void log(String message, {String? level}) {
+ final entry = LogEntry(message, level: level);
+ _logs.add(entry);
+ if (_logs.length > 500) {
+ _logs.removeAt(0);
+ }
+ _controller.add(logs);
+ }
+
+ void clear() {
+ _logs.clear();
+ _controller.add(logs);
+ }
+
+ static void init() {
+ final originalDebugPrint = debugPrint;
+ debugPrint = (String? message, {int? wrapWidth}) {
+ if (message != null) {
+ LoggerService().log(message);
+ }
+ originalDebugPrint(message, wrapWidth: wrapWidth);
+ };
+ }
+}
diff --git a/lib/main.dart b/lib/main.dart
index 17b12cf..04119c2 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -6,10 +6,13 @@ import 'app.dart';
import 'core/save/backup_entry.dart';
import 'providers/shared_prefs_provider.dart';
+import 'core/storage/logger_service.dart';
+
final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
+ LoggerService.init();
Hive.registerAdapter(BackupEntryAdapter());
await Hive.initFlutter();
await Hive.openBox<List>('freegosy_backups');
diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart
index 3947de2..53e3bac 100644
--- a/lib/ui/screens/settings_screen.dart
+++ b/lib/ui/screens/settings_screen.dart
@@ -12,6 +12,7 @@ import '../../providers/shared_prefs_provider.dart';
import '../../providers/downloaded_games_cache_provider.dart';
import '../../core/romm/romm_service.dart';
import '../../core/romm/romm_models.dart';
+import '../../core/storage/logger_service.dart';
import 'settings_emulators_section.dart';
import 'settings_display_section.dart';
import 'settings_custom_emulators_section.dart';
@@ -365,9 +366,80 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> {
label: Text(isScanning ? 'Scanning...' : 'Force Full ROM Scan'),
);
}),
+ const SizedBox(height: 12),
+ OutlinedButton.icon(
+ onPressed: () => _showLogsDialog(context),
+ icon: const Icon(Icons.receipt_long),
+ label: const Text('View Console Logs'),
+ ),
]);
}
+ void _showLogsDialog(BuildContext context) {
+ showDialog(
+ context: context,
+ builder: (context) => Dialog(
+ child: Container(
+ width: double.infinity,
+ height: MediaQuery.of(context).size.height * 0.8,
+ padding: const EdgeInsets.all(16),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const Text('System Logs', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
+ Row(
+ children: [
+ IconButton(
+ icon: const Icon(Icons.delete_sweep),
+ onPressed: () => LoggerService().clear(),
+ tooltip: 'Clear Logs',
+ ),
+ IconButton(
+ icon: const Icon(Icons.close),
+ onPressed: () => Navigator.pop(context),
+ ),
+ ],
+ ),
+ ],
+ ),
+ const Divider(),
+ Expanded(
+ child: StreamBuilder<List<LogEntry>>(
+ stream: LoggerService().logStream,
+ initialData: LoggerService().logs,
+ builder: (context, snapshot) {
+ final logs = snapshot.data ?? [];
+ return ListView.builder(
+ reverse: true,
+ itemCount: logs.length,
+ itemBuilder: (context, index) {
+ final log = logs[logs.length - 1 - index];
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 2),
+ child: Text(
+ log.toString(),
+ style: const TextStyle(
+ fontFamily: 'monospace',
+ fontSize: 12,
+ color: Colors.white70,
+ ),
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+
Widget _buildPathRow({required String label, required String currentPath, required Function(String?)? onChanged, VoidCallback? onReset}) {
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(label, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),