-
-
Notifications
You must be signed in to change notification settings - Fork 14
commit f573f12
abduznik edited this page May 23, 2026
·
1 revision
Commit: f573f12708ef95f5de74ab43bed8238eba5850d8
Author: Yan
Date: 2026年04月11日
Why: Adds a new feature or capability to the application.
lib/core/emulator/emulator_download_service.dart | 12 +++
lib/core/emulator/emulator_registry_data.dart | 34 +++++---
lib/core/emulator/strategies/azahar_strategy.dart | 2 +-
lib/core/emulator/strategies/cemu_strategy.dart | 2 +-
lib/core/emulator/strategies/dolphin_strategy.dart | 2 +-
.../emulator/strategies/duckstation_strategy.dart | 2 +-
lib/core/emulator/strategies/flycast_strategy.dart | 2 +-
lib/core/emulator/strategies/pcsx2_strategy.dart | 2 +-
lib/core/emulator/strategies/rpcs3_strategy.dart | 2 +-
lib/core/emulator/strategies/xemu_strategy.dart | 2 +-
lib/core/save/strategies/azahar_save_strategy.dart | 6 +-
lib/core/save/strategies/cemu_save_strategy.dart | 10 +--
.../save/strategies/dolphin_save_strategy.dart | 6 +-
.../save/strategies/duckstation_save_strategy.dart | 10 +--
lib/core/save/strategies/eden_save_strategy.dart | 8 +-
lib/core/save/strategies/ppsspp_save_strategy.dart | 10 +--
lib/core/save/strategies/rpcs3_save_strategy.dart | 10 +--
lib/core/storage/directory_service.dart | 58 +++++++++++--
lib/ui/screens/settings_screen.dart | 49 +++++++++++
test/unit/firmware_service_test.mocks.dart | 94 +++++++++++++++++++---
test/unit/save_sync_service_test.mocks.dart | 94 +++++++++++++++++++---
test/unit/strategy_registry_test.mocks.dart | 94 +++++++++++++++++++---
test/widgets/library_screen_test.mocks.dart | 94 +++++++++++++++++++---
test/widgets/settings_screen_test.mocks.dart | 94 +++++++++++++++++++---
24 files changed, 590 insertions(+), 109 deletions(-)
lib/core/emulator/emulator_download_service.dartlib/core/emulator/emulator_registry_data.dartlib/core/emulator/strategies/azahar_strategy.dartlib/core/emulator/strategies/cemu_strategy.dartlib/core/emulator/strategies/dolphin_strategy.dartlib/core/emulator/strategies/duckstation_strategy.dartlib/core/emulator/strategies/flycast_strategy.dartlib/core/emulator/strategies/pcsx2_strategy.dartlib/core/emulator/strategies/rpcs3_strategy.dartlib/core/emulator/strategies/xemu_strategy.dartlib/core/save/strategies/azahar_save_strategy.dartlib/core/save/strategies/cemu_save_strategy.dartlib/core/save/strategies/dolphin_save_strategy.dartlib/core/save/strategies/duckstation_save_strategy.dartlib/core/save/strategies/eden_save_strategy.dartlib/core/save/strategies/ppsspp_save_strategy.dartlib/core/save/strategies/rpcs3_save_strategy.dartlib/core/storage/directory_service.dartlib/ui/screens/settings_screen.darttest/unit/firmware_service_test.mocks.darttest/unit/save_sync_service_test.mocks.darttest/unit/strategy_registry_test.mocks.darttest/widgets/library_screen_test.mocks.darttest/widgets/settings_screen_test.mocks.dart
diff --git a/lib/core/emulator/emulator_download_service.dart b/lib/core/emulator/emulator_download_service.dart index 99128c6..1a4d489 100644 --- a/lib/core/emulator/emulator_download_service.dart +++ b/lib/core/emulator/emulator_download_service.dart @@ -178,6 +178,18 @@ class EmulatorDownloadService { status: 'Extracting...', )); await _extractionService.extract(tempFilePath, emulatorDir); + + // Linux specific: ensure binary is executable + if (Platform.isLinux) { + final exeName = definition['linux_executable'] as String?; + if (exeName != null) { + final exePath = await _directoryService.findEmulatorExecutable(emulatorId, exeName); + if (exePath != null) { + await Process.run('chmod', ['+x', exePath]); + } + } + } + controller.add(DownloadProgress( id: emulatorId, gameName: emulatorName, diff --git a/lib/core/emulator/emulator_registry_data.dart b/lib/core/emulator/emulator_registry_data.dart index 112a55b..569857b 100644 --- a/lib/core/emulator/emulator_registry_data.dart +++ b/lib/core/emulator/emulator_registry_data.dart @@ -20,10 +20,14 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ { 'id': 'dolphin', 'name': 'Dolphin', - 'type': 'direct', + 'type': 'github', + 'github_repo': 'dolphin-emu/dolphin', + 'github_asset_required_windows': ['x64', '.7z'], + 'github_asset_required_linux': ['x86_64', '.AppImage'], + 'github_asset_excluded': ['debug', 'symbols'], 'windows_url': 'https://dl.dolphin-emu.org/builds/dolphin-master-latest-x64.7z', 'windows_executable': 'Dolphin.exe', - 'linux_executable': 'dolphin-emu', + 'linux_executable': 'Dolphin.AppImage', 'macos_url': 'https://dl.dolphin-emu.org/releases/2603a/dolphin-2603a-universal.dmg', 'macos_executable': 'Dolphin.app/Contents/MacOS/Dolphin', 'platform_slugs': ['gc', 'gamecube', 'wii', 'ngc'], @@ -35,6 +39,7 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'type': 'direct', 'windows_url': 'https://git.eden-emu.dev/eden-emu/eden/-/releases/permalink/latest/downloads/eden-windows-msvc-install.zip', 'windows_executable': 'eden.exe', + 'linux_url': 'https://git.eden-emu.dev/eden-emu/eden/-/releases/permalink/latest/downloads/eden-linux-x86_64.tar.gz', 'linux_executable': 'eden', 'macos_url': 'https://git.eden-emu.dev/eden-emu/eden/releases/download/v0.2.0-rc2/Eden-macOS-v0.2.0-rc2.tar.gz', 'macos_executable': 'Eden.app/Contents/MacOS/Eden', @@ -49,9 +54,10 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo_macos': 'RPCS3/rpcs3-binaries-mac-arm64', 'github_asset_required': ['win64'], 'github_asset_required_macos': ['macos', 'aarch64', '.7z'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded': ['debug'], 'windows_executable': 'rpcs3.exe', - 'linux_executable': 'rpcs3', + 'linux_executable': 'rpcs3.AppImage', 'macos_executable': 'RPCS3.app/Contents/MacOS/RPCS3', 'platform_slugs': ['ps3', 'playstation-3', 'playstation3'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -63,10 +69,11 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'PCSX2/pcsx2', 'github_asset_required': ['windows', 'Qt'], 'github_asset_required_macos': ['macos', 'Qt'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded': ['debug', 'sse4'], 'github_asset_excluded_windows': ['arm64'], 'windows_executable': 'pcsx2-qt.exe', - 'linux_executable': 'pcsx2-qt', + 'linux_executable': 'pcsx2-qt.AppImage', 'macos_executable': 'PCSX2.app/Contents/MacOS/PCSX2', 'platform_slugs': ['ps2', 'playstation-2', 'playstation2'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -78,10 +85,11 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'azahar-emu/azahar', 'github_asset_required_windows': ['windows', 'msys2'], 'github_asset_required_macos': ['macos', 'arm64'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded_windows': ['debug', 'appimage'], 'github_asset_excluded_macos': ['debug', 'libretro'], 'windows_executable': 'azahar.exe', - 'linux_executable': 'azahar', + 'linux_executable': 'azahar.AppImage', 'macos_executable': 'Azahar.app/Contents/MacOS/Azahar', 'platform_slugs': ['3ds', 'n3ds', 'nintendo-3ds', 'nintendo3ds', 'new-nintendo-3ds', 'new-nintendo-3ds-xl'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -93,11 +101,12 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'cemu-project/Cemu', 'github_asset_required': ['windows', 'x64', '.zip'], 'github_asset_required_macos': ['macos', '.dmg'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded': ['debug', 'symbols'], 'github_asset_excluded_windows': ['linux', 'macos'], 'github_asset_excluded_macos': ['windows', 'linux'], 'windows_executable': 'Cemu.exe', - 'linux_executable': 'cemu', + 'linux_executable': 'Cemu.AppImage', 'macos_executable': 'Cemu.app/Contents/MacOS/Cemu', 'platform_slugs': ['wiiu', 'wii-u', 'nintendo-wii-u', 'nintendo-wiiu'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -109,14 +118,15 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'xemu-project/xemu', 'github_asset_required': ['win', 'x86_64', 'release'], 'github_asset_required_macos': ['macos', 'release'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded': ['dbg', 'pdb', 'arm', 'appimage', 'tar'], 'github_asset_excluded_windows': ['macos'], 'github_asset_excluded_macos': ['win'], 'windows_executable': 'xemu.exe', - 'linux_executable': 'xemu', + 'linux_executable': 'xemu.AppImage', 'macos_executable': 'Xemu.app/Contents/MacOS/xemu', 'platform_slugs': ['xbox'], - 'supported_platforms': ['windows', 'macos'], + 'supported_platforms': ['windows', 'macos', 'linux'], }, { 'id': 'xenia_canary', @@ -137,9 +147,10 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'stenzek/duckstation', 'github_asset_required': ['windows', 'x64'], 'github_asset_required_macos': ['mac', 'release'], + 'github_asset_required_linux': ['x64', '.AppImage'], 'github_asset_excluded': ['nogui', 'debug', 'arm64'], 'windows_executable': 'duckstation-qt-x64-ReleaseLTCG.exe', - 'linux_executable': 'duckstation-qt', + 'linux_executable': 'DuckStation.AppImage', 'macos_executable': 'DuckStation.app/Contents/MacOS/DuckStation', 'platform_slugs': ['ps1', 'playstation', 'psx'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -151,11 +162,12 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'flyinghead/flycast', 'github_asset_required': ['win64', '.zip'], 'github_asset_required_macos': ['macOS', '.zip'], + 'github_asset_required_linux': ['linux', 'x86_64', '.AppImage'], 'github_asset_excluded': ['debug', 'symbols'], 'github_asset_excluded_windows': ['linux', 'macos'], 'github_asset_excluded_macos': ['windows', 'linux'], 'windows_executable': 'flycast.exe', - 'linux_executable': 'flycast', + 'linux_executable': 'flycast.AppImage', 'macos_executable': 'Flycast.app/Contents/MacOS/Flycast', 'platform_slugs': ['dc', 'dreamcast', 'naomi', 'naomi2', 'atomiswave', 'cave', 'hikaru'], 'supported_platforms': ['windows', 'linux', 'macos'], @@ -167,6 +179,7 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'melonDS-emu/melonDS', 'github_asset_required': ['win', '.zip'], 'github_asset_required_macos': ['macos', '.zip'], + 'github_asset_required_linux': ['linux', 'x64', '.tar.gz'], 'github_asset_excluded': ['source', 'debug'], 'github_asset_excluded_macos': ['libretro'], 'windows_executable': 'melonDS.exe', @@ -196,6 +209,7 @@ const List<Map<String, dynamic>> kEmulatorDefinitions = [ 'github_repo': 'mgba-emu/mgba', 'github_asset_required': ['win64', '.7z'], 'github_asset_required_macos': ['macos', '.dmg'], + 'github_asset_required_linux': ['x86_64', '.tar.xz'], 'github_asset_excluded': ['debug', 'symbols', 'source'], 'windows_executable': 'mGBA.exe', 'linux_executable': 'mgba', diff --git a/lib/core/emulator/strategies/azahar_strategy.dart b/lib/core/emulator/strategies/azahar_strategy.dart index 638fe05..2ae7e99 100644 --- a/lib/core/emulator/strategies/azahar_strategy.dart +++ b/lib/core/emulator/strategies/azahar_strategy.dart @@ -27,7 +27,7 @@ class AzaharStrategy extends EmulatorStrategy { String get windowsExecutable => 'azahar.exe'; @override - String get linuxExecutable => 'azahar'; + String get linuxExecutable => 'azahar.AppImage'; @override String get macosExecutable => 'Azahar.app/Contents/MacOS/azahar'; diff --git a/lib/core/emulator/strategies/cemu_strategy.dart b/lib/core/emulator/strategies/cemu_strategy.dart index 338226f..5afc0e7 100644 --- a/lib/core/emulator/strategies/cemu_strategy.dart +++ b/lib/core/emulator/strategies/cemu_strategy.dart @@ -22,7 +22,7 @@ class CemuStrategy extends EmulatorStrategy { String get windowsExecutable => 'Cemu.exe'; @override - String get linuxExecutable => 'cemu'; + String get linuxExecutable => 'Cemu.AppImage'; @override String get macosExecutable => 'Cemu.app/Contents/MacOS/Cemu'; diff --git a/lib/core/emulator/strategies/dolphin_strategy.dart b/lib/core/emulator/strategies/dolphin_strategy.dart index 8cb3155..8dc4b87 100644 --- a/lib/core/emulator/strategies/dolphin_strategy.dart +++ b/lib/core/emulator/strategies/dolphin_strategy.dart @@ -22,7 +22,7 @@ class DolphinStrategy extends EmulatorStrategy { String get windowsExecutable => 'Dolphin.exe'; @override - String get linuxExecutable => 'dolphin-emu'; + String get linuxExecutable => 'Dolphin.AppImage'; @override String get macosExecutable => 'Dolphin.app/Contents/MacOS/Dolphin'; diff --git a/lib/core/emulator/strategies/duckstation_strategy.dart b/lib/core/emulator/strategies/duckstation_strategy.dart index 75b40e8..d96bcc4 100644 --- a/lib/core/emulator/strategies/duckstation_strategy.dart +++ b/lib/core/emulator/strategies/duckstation_strategy.dart @@ -22,7 +22,7 @@ class DuckstationStrategy extends EmulatorStrategy { String get windowsExecutable => 'duckstation-qt-x64-ReleaseLTCG.exe'; @override - String get linuxExecutable => 'duckstation-qt'; + String get linuxExecutable => 'DuckStation.AppImage'; @override String get macosExecutable => 'DuckStation.app/Contents/MacOS/DuckStation'; diff --git a/lib/core/emulator/strategies/flycast_strategy.dart b/lib/core/emulator/strategies/flycast_strategy.dart index 1d897f4..1014266 100644 --- a/lib/core/emulator/strategies/flycast_strategy.dart +++ b/lib/core/emulator/strategies/flycast_strategy.dart @@ -22,7 +22,7 @@ class FlycastStrategy extends EmulatorStrategy { String get windowsExecutable => 'flycast.exe'; @override - String get linuxExecutable => 'flycast'; + String get linuxExecutable => 'flycast.AppImage'; @override String get macosExecutable => 'Flycast.app/Contents/MacOS/Flycast'; diff --git a/lib/core/emulator/strategies/pcsx2_strategy.dart b/lib/core/emulator/strategies/pcsx2_strategy.dart index 4004312..f429e8b 100644 --- a/lib/core/emulator/strategies/pcsx2_strategy.dart +++ b/lib/core/emulator/strategies/pcsx2_strategy.dart @@ -22,7 +22,7 @@ class Pcsx2Strategy extends EmulatorStrategy { String get windowsExecutable => 'pcsx2-qt.exe'; @override - String get linuxExecutable => 'pcsx2-qt'; + String get linuxExecutable => 'pcsx2-qt.AppImage'; @override String get macosExecutable => 'PCSX2.app/Contents/MacOS/PCSX2'; diff --git a/lib/core/emulator/strategies/rpcs3_strategy.dart b/lib/core/emulator/strategies/rpcs3_strategy.dart index 99a4764..2908c77 100644 --- a/lib/core/emulator/strategies/rpcs3_strategy.dart +++ b/lib/core/emulator/strategies/rpcs3_strategy.dart @@ -23,7 +23,7 @@ class Rpcs3Strategy extends EmulatorStrategy { String get windowsExecutable => 'rpcs3.exe'; @override - String get linuxExecutable => 'rpcs3'; + String get linuxExecutable => 'rpcs3.AppImage'; @override String get macosExecutable => 'RPCS3.app/Contents/MacOS/RPCS3'; diff --git a/lib/core/emulator/strategies/xemu_strategy.dart b/lib/core/emulator/strategies/xemu_strategy.dart index 4e09a52..17c6004 100644 --- a/lib/core/emulator/strategies/xemu_strategy.dart +++ b/lib/core/emulator/strategies/xemu_strategy.dart @@ -21,7 +21,7 @@ class XemuStrategy extends EmulatorStrategy { String get windowsExecutable => 'xemu.exe'; @override - String get linuxExecutable => 'xemu'; + String get linuxExecutable => 'xemu.AppImage'; @override bool get supportsSaveSync => false; diff --git a/lib/core/save/strategies/azahar_save_strategy.dart b/lib/core/save/strategies/azahar_save_strategy.dart index 6b97d24..24c23f9 100644 --- a/lib/core/save/strategies/azahar_save_strategy.dart +++ b/lib/core/save/strategies/azahar_save_strategy.dart @@ -32,8 +32,8 @@ class AzaharSaveStrategy extends SaveStrategy { _manualMapping = mapping; } - Future<String> _getAzaharSystemBase() async { - final resolvedPath = await _directoryService.getEmulatorSystemDirectory('azahar'); + Future<String> _getAzaharSystemBase({String? platformSlug}) async { + final resolvedPath = await _directoryService.getEmulatorSystemDirectory('azahar', platformSlug: platformSlug); if (!await io.Directory(resolvedPath).exists()) { throw Exception('Save directory not found for Azahar at $resolvedPath. Please launch Azahar at least once to generate save data.'); } @@ -49,7 +49,7 @@ class AzaharSaveStrategy extends SaveStrategy { 'Please select the save folder manually from the sdmc directory.'); } - final base = await _getAzaharSystemBase(); + final base = await _getAzaharSystemBase(platformSlug: game.platformSlug); // _manualMapping is expected to be the relative path from sdmc final finalPath = p.join(base, 'sdmc', _manualMapping!); diff --git a/lib/core/save/strategies/cemu_save_strategy.dart b/lib/core/save/strategies/cemu_save_strategy.dart index 34cc200..2e80981 100644 --- a/lib/core/save/strategies/cemu_save_strategy.dart +++ b/lib/core/save/strategies/cemu_save_strategy.dart @@ -15,7 +15,7 @@ class CemuSaveStrategy extends SaveStrategy { @override String get strategyId => 'cemu'; - Future<String> _getSaveRoot() async { + Future<String> _getSaveRoot({String? platformSlug}) async { // 1. Check emulator-relative path first (e.g. for Windows portable) final emuDir = await _directoryService.getEmulatorDirectory('cemu'); final portableRoot = p.join(emuDir, 'mlc01', 'usr', 'save'); @@ -24,7 +24,7 @@ class CemuSaveStrategy extends SaveStrategy { } // 2. Dynamic path resolution for macOS/Windows/Linux - final baseDir = await _directoryService.getEmulatorAppSupportDirectory('Cemu'); + final baseDir = await _directoryService.getEmulatorAppSupportDirectory('Cemu', platformSlug: platformSlug); // On macOS, Cemu's save structure might be different in Application Support, // but typically it mirrors the internal folder structure if using the same mlc01 logic. // Actually, Cemu on macOS often puts mlc01 directly in Application Support/Cemu @@ -38,13 +38,13 @@ class CemuSaveStrategy extends SaveStrategy { @override Future<String?> getSaveDir(Game game, String romPath) async { - return await _getSaveRoot(); + return await _getSaveRoot(platformSlug: game.platformSlug); } @override Future<List<io.File>> getSaveFiles(Game game, String romPath, {DateTime? sessionStart, String syncMode = 'both'}) async { - final saveRoot = await _getSaveRoot(); + final saveRoot = await _getSaveRoot(platformSlug: game.platformSlug); final saveBase = io.Directory(p.join(saveRoot, '00050000')); if (!await saveBase.exists()) return []; return [io.File(saveBase.path)]; // Return the directory as a single item @@ -53,7 +53,7 @@ class CemuSaveStrategy extends SaveStrategy { @override Future<bool> restoreSave(Game game, String destPath, Uint8List data, String filename) async { try { - final saveRoot = await _getSaveRoot(); + final saveRoot = await _getSaveRoot(platformSlug: game.platformSlug); await io.Directory(saveRoot).create(recursive: true); if (filename.toLowerCase().endsWith('.zip')) { final archive = ZipDecoder().decodeBytes(data); diff --git a/lib/core/save/strategies/dolphin_save_strategy.dart b/lib/core/save/strategies/dolphin_save_strategy.dart index df8c007..f9ac6ab 100644 --- a/lib/core/save/strategies/dolphin_save_strategy.dart +++ b/lib/core/save/strategies/dolphin_save_strategy.dart @@ -19,7 +19,7 @@ class DolphinSaveStrategy extends SaveStrategy { String get strategyId => 'dolphin'; /// Returns the base user directory for Dolphin. - Future<String> _getUserDir() async { + Future<String> _getUserDir({String? platformSlug}) async { // 1. Check portable mode first — User folder next to exe final exePath = await _directoryService.findEmulatorExecutable( 'dolphin', 'Dolphin.exe'); @@ -35,7 +35,7 @@ class DolphinSaveStrategy extends SaveStrategy { } // 2. Fall back to app support directory - final resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('Dolphin'); + final resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('Dolphin', platformSlug: platformSlug); if (!await io.Directory(resolvedPath).exists()) { throw Exception('Save directory not found for Dolphin at $resolvedPath. Please launch Dolphin at least once to generate save data.'); } @@ -72,7 +72,7 @@ class DolphinSaveStrategy extends SaveStrategy { @override Future<String?> getSaveDir(Game game, String romPath) async { - final userDir = await _getUserDir(); + final userDir = await _getUserDir(platformSlug: game.platformSlug); final isWii = game.platformSlug?.toLowerCase() == 'wii'; diff --git a/lib/core/save/strategies/duckstation_save_strategy.dart b/lib/core/save/strategies/duckstation_save_strategy.dart index 8bd3665..4cfc93d 100644 --- a/lib/core/save/strategies/duckstation_save_strategy.dart +++ b/lib/core/save/strategies/duckstation_save_strategy.dart @@ -16,7 +16,7 @@ class DuckstationSaveStrategy extends SaveStrategy { @override String get strategyId => 'duckstation'; - Future<String> _getBaseDir() async { + Future<String> _getBaseDir({String? platformSlug}) async { // 1. Check portable mode first (Windows) final exePath = await _directoryService.findEmulatorExecutable( 'duckstation', 'duckstation-qt-x64-ReleaseLTCG.exe'); @@ -33,7 +33,7 @@ class DuckstationSaveStrategy extends SaveStrategy { final localAppData = io.Platform.environment['LOCALAPPDATA'] ?? ''; resolvedPath = p.join(localAppData, 'DuckStation'); } else { - resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('DuckStation'); + resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('DuckStation', platformSlug: platformSlug); } if (!await io.Directory(resolvedPath).exists()) { @@ -44,14 +44,14 @@ class DuckstationSaveStrategy extends SaveStrategy { @override Future<String?> getSaveDir(Game game, String romPath) async { - final baseDir = await _getBaseDir(); + final baseDir = await _getBaseDir(platformSlug: game.platformSlug); return p.join(baseDir, 'memcards'); } @override Future<List<File>> getSaveFiles(Game game, String romPath, {DateTime? sessionStart, String syncMode = 'both'}) async { - final baseDir = await _getBaseDir(); + final baseDir = await _getBaseDir(platformSlug: game.platformSlug); final result = <File>[]; final stem = getRomStem(game); @@ -91,7 +91,7 @@ class DuckstationSaveStrategy extends SaveStrategy { Future<bool> restoreSave( Game game, String destPath, Uint8List data, String filename) async { try { - final baseDir = await _getBaseDir(); + final baseDir = await _getBaseDir(platformSlug: game.platformSlug); if (filename.toLowerCase().endsWith('.zip')) { final archive = ZipDecoder().decodeBytes(data); diff --git a/lib/core/save/strategies/eden_save_strategy.dart b/lib/core/save/strategies/eden_save_strategy.dart index b29e3aa..b12c868 100644 --- a/lib/core/save/strategies/eden_save_strategy.dart +++ b/lib/core/save/strategies/eden_save_strategy.dart @@ -441,10 +441,10 @@ class EdenSaveStrategy extends SaveStrategy { // Platform-specific save base path // ═══════════════════════════════════════════════════════════════════════════ - Future<String> _getEdenSaveBase() async { + Future<String> _getEdenSaveBase({String? platformSlug}) async { final String resolvedPath; if (io.Platform.isMacOS || io.Platform.isLinux) { - resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('eden'); + resolvedPath = await _directoryService.getEmulatorAppSupportDirectory('eden', platformSlug: platformSlug); } else if (io.Platform.isWindows) { final appData = io.Platform.environment['APPDATA'] ?? ''; resolvedPath = p.join(appData, 'eden'); @@ -467,7 +467,7 @@ class EdenSaveStrategy extends SaveStrategy { Future<String?> getSaveDir(Game game, String romPath) async { debugPrint('=== EDEN SAVE DIR: ${game.name} ==='); - final base = await _getEdenSaveBase(); + final base = await _getEdenSaveBase(platformSlug: game.platformSlug); final profileId = await _resolveProfileId(base); final titleId = await _resolveTitleId(romPath, game); @@ -547,7 +547,7 @@ class EdenSaveStrategy extends SaveStrategy { try { debugPrint('=== EDEN RESTORE: ${game.name} ==='); - final base = await _getEdenSaveBase(); + final base = await _getEdenSaveBase(platformSlug: game.platformSlug); final profileId = await _resolveProfileId(base); diff --git a/lib/core/save/strategies/ppsspp_save_strategy.dart b/lib/core/save/strategies/ppsspp_save_strategy.dart index 8d69d0c..b654712 100644 --- a/lib/core/save/strategies/ppsspp_save_strategy.dart +++ b/lib/core/save/strategies/ppsspp_save_strategy.dart @@ -17,7 +17,7 @@ class PpssppSaveStrategy extends SaveStrategy { @override String get strategyId => 'ppsspp'; - Future<String> _getPspDir() async { + Future<String> _getPspDir({String? platformSlug}) async { // 1. Check portable mode first (Windows) if (io.Platform.isWindows) { final exePath = await _directoryService.findEmulatorExecutable( @@ -54,7 +54,7 @@ class PpssppSaveStrategy extends SaveStrategy { } // 2. Dynamic path resolution - final baseDir = await _directoryService.getEmulatorAppSupportDirectory('ppsspp'); + final baseDir = await _directoryService.getEmulatorAppSupportDirectory('ppsspp', platformSlug: platformSlug); final pspDir = p.join(baseDir, 'PSP'); if (!await io.Directory(pspDir).exists()) { @@ -124,14 +124,14 @@ class PpssppSaveStrategy extends SaveStrategy { @override Future<String?> getSaveDir(Game game, String romPath) async { - final pspDir = await _getPspDir(); + final pspDir = await _getPspDir(platformSlug: game.platformSlug); return p.join(pspDir, 'SAVEDATA'); } @override Future<List<File>> getSaveFiles(Game game, String romPath, {DateTime? sessionStart, String syncMode = 'both'}) async { - final pspDir = await _getPspDir(); + final pspDir = await _getPspDir(platformSlug: game.platformSlug); final result = <File>[]; // --- Handle SAVEDATA folders --- @@ -215,7 +215,7 @@ class PpssppSaveStrategy extends SaveStrategy { Future<bool> restoreSave( Game game, String destPath, Uint8List data, String filename) async { try { - final pspDir = await _getPspDir(); + final pspDir = await _getPspDir(platformSlug: game.platformSlug); if (filename.toLowerCase().endsWith('.zip')) { final archive = ZipDecoder().decodeBytes(data); diff --git a/lib/core/save/strategies/rpcs3_save_strategy.dart b/lib/core/save/strategies/rpcs3_save_strategy.dart index 34fcc63..35b91ee 100644 --- a/lib/core/save/strategies/rpcs3_save_strategy.dart +++ b/lib/core/save/strategies/rpcs3_save_strategy.dart @@ -83,7 +83,7 @@ class Rpcs3SaveStrategy extends SaveStrategy { } } - Future<String> _getRpcs3SaveRoot() async { + Future<String> _getRpcs3SaveRoot({String? platformSlug}) async { // 1. Check portable mode first (Windows) final exePath = await _directoryService.findEmulatorExecutable( 'rpcs3', 'rpcs3.exe'); @@ -96,7 +96,7 @@ class Rpcs3SaveStrategy extends SaveStrategy { } // 2. Dynamic path resolution - final baseDir = await _directoryService.getEmulatorAppSupportDirectory('rpcs3'); + final baseDir = await _directoryService.getEmulatorAppSupportDirectory('rpcs3', platformSlug: platformSlug); final resolvedPath = p.join(baseDir, 'dev_hdd0', 'home', '00000001', 'savedata'); if (!await io.Directory(resolvedPath).exists()) { @@ -297,7 +297,7 @@ class Rpcs3SaveStrategy extends SaveStrategy { if (_activeFolderOverride != null) { return _activeFolderOverride; } - final saveRoot = await _getRpcs3SaveRoot(); + final saveRoot = await _getRpcs3SaveRoot(platformSlug: game.platformSlug); final dirs = await _findSaveDirs(saveRoot, game); return dirs.isNotEmpty ? dirs.first.path : null; } @@ -305,7 +305,7 @@ class Rpcs3SaveStrategy extends SaveStrategy { @override Future<List<File>> getSaveFiles(Game game, String romPath, {DateTime? sessionStart, String syncMode = 'both'}) async { - final saveRoot = await _getRpcs3SaveRoot(); + final saveRoot = await _getRpcs3SaveRoot(platformSlug: game.platformSlug); // Manual override — wrap single dir List<Directory> saveDirs; @@ -348,7 +348,7 @@ class Rpcs3SaveStrategy extends SaveStrategy { Future<bool> restoreSave( Game game, String destPath, Uint8List data, String filename) async { try { - final saveRoot = await _getRpcs3SaveRoot(); + final saveRoot = await _getRpcs3SaveRoot(platformSlug: game.platformSlug); if (filename.toLowerCase().endsWith('.zip')) { final archive = ZipDecoder().decodeBytes(data); diff --git a/lib/core/storage/directory_service.dart b/lib/core/storage/directory_service.dart index eb665cc..2e54154 100644 --- a/lib/core/storage/directory_service.dart +++ b/lib/core/storage/directory_service.dart @@ -10,6 +10,8 @@ import 'package:freegosy/core/romm/romm_models.dart'; class DirectoryService { static const String _romsRootPathKey = 'romsRootPath'; static const String _emulatorsRootPathKey = 'emulatorsRootPath'; + static const String _linuxSyncPresetKey = 'linuxSyncPreset'; + static const String _emudeckRootPathKey = 'emudeckRootPath'; // Known extensions per platform slug static const Map<String, List<String>> _platformExtensions = { @@ -37,12 +39,17 @@ class DirectoryService { late String romsRootPath; late String emulatorsRootPath; + String linuxSyncPreset = 'default'; + String? emudeckRootPath; final Map<String, String> _emulatorPathOverrides = {}; DirectoryService(); Future<void> initialize() async { final prefs = await SharedPreferences.getInstance(); + linuxSyncPreset = prefs.getString(_linuxSyncPresetKey) ?? 'default'; + emudeckRootPath = prefs.getString(_emudeckRootPathKey); + final String defaultBase; if (defaultTargetPlatform == TargetPlatform.macOS || defaultTargetPlatform == TargetPlatform.linux) { @@ -53,13 +60,40 @@ class DirectoryService { defaultBase = docsDir.path; } - romsRootPath = prefs.getString(_romsRootPathKey) ?? '$defaultBase/ROMs'; - emulatorsRootPath = prefs.getString(_emulatorsRootPathKey) ?? '$defaultBase/Emulators'; + if (defaultTargetPlatform == TargetPlatform.linux && + linuxSyncPreset == 'emudeck' && + emudeckRootPath != null) { + romsRootPath = + prefs.getString(_romsRootPathKey) ?? p.join(emudeckRootPath!, 'Emulation/roms'); + emulatorsRootPath = + prefs.getString(_emulatorsRootPathKey) ?? p.join(emudeckRootPath!, 'Emulation/tools'); + } else { + romsRootPath = prefs.getString(_romsRootPathKey) ?? '$defaultBase/ROMs'; + emulatorsRootPath = + prefs.getString(_emulatorsRootPathKey) ?? '$defaultBase/Emulators'; + } + await _ensureDirectoryExists(romsRootPath); await _ensureDirectoryExists(emulatorsRootPath); await loadEmulatorPathOverrides(); } + Future<void> setLinuxSyncPreset(String preset) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_linuxSyncPresetKey, preset); + linuxSyncPreset = preset; + // Re-initialize to update paths based on new preset + await initialize(); + } + + Future<void> setEmudeckRoot(String path) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_emudeckRootPathKey, path); + emudeckRootPath = path; + // Re-initialize to update paths based on new root + await initialize(); + } + Future<void> loadEmulatorPathOverrides() async { final prefs = await SharedPreferences.getInstance(); for (final key in prefs.getKeys()) { @@ -280,7 +314,7 @@ class DirectoryService { return dirPath; } - Future<String> getEmulatorAppSupportDirectory(String emulatorName) async { + Future<String> getEmulatorAppSupportDirectory(String emulatorName, {String? platformSlug}) async { if (io.Platform.isMacOS) { final appSupport = await getApplicationSupportDirectory(); // On macOS, getApplicationSupportDirectory() returns ~/Library/Application Support/com.example.app @@ -290,21 +324,33 @@ class DirectoryService { final appData = io.Platform.environment['APPDATA'] ?? ''; return p.join(appData, emulatorName); } else if (io.Platform.isLinux) { + if (linuxSyncPreset == 'emudeck' && emudeckRootPath != null) { + // EmuDeck standard saves path: Emulation/saves/[emulator]/[platform] + // If platform is not provided, we might have to guess or return a base + final base = p.join(emudeckRootPath!, 'Emulation', 'saves', emulatorName.toLowerCase()); + if (platformSlug != null) { + return p.join(base, platformSlug); + } + return base; + } final home = io.Platform.environment['HOME'] ?? ''; return p.join(home, '.config', emulatorName); } throw UnsupportedError('Platform not supported for save path resolution'); } - Future<String> getEmulatorBiosDirectory(String emulatorId) async { + Future<String> getEmulatorBiosDirectory(String emulatorId, {String? platformSlug}) async { + if (io.Platform.isLinux && linuxSyncPreset == 'emudeck' && emudeckRootPath != null) { + return p.join(emudeckRootPath!, 'Emulation', 'bios'); + } final emuDir = await getEmulatorDirectory(emulatorId); final dirPath = p.join(emuDir, 'BIOS'); await _ensureDirectoryExists(dirPath); return dirPath; } - Future<String> getEmulatorSystemDirectory(String emulatorId) async { - return await getEmulatorBiosDirectory(emulatorId); + Future<String> getEmulatorSystemDirectory(String emulatorId, {String? platformSlug}) async { + return await getEmulatorBiosDirectory(emulatorId, platformSlug: platformSlug); } Future<void> deleteEmulator(String emulatorId) async { diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart index c02df34..4105015 100644 --- a/lib/ui/screens/settings_screen.dart +++ b/lib/ui/screens/settings_screen.dart @@ -153,6 +153,10 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> { const SizedBox(height: 24), _buildRetroArchSyncModeSection(context, ref), const SizedBox(height: 24), + if (defaultTargetPlatform == TargetPlatform.linux) ...[ + _buildLinuxSettingsSection(context, ref, directoryService), + const SizedBox(height: 24), + ], // Call the extracted emulators section function buildEmulatorsSection( context, // Pass context @@ -424,6 +428,51 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen> { ); } + // --- Linux Settings Section --- + Widget _buildLinuxSettingsSection(BuildContext context, WidgetRef ref, DirectoryService directoryService) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Linux Integration', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), + const SizedBox(height: 8), + const Text('Select sync method for Linux/Steam Deck', style: TextStyle(color: Colors.grey)), + const SizedBox(height: 12), + SegmentedButton<String>( + segments: const [ + ButtonSegment(value: 'default', label: Text('Default')), + ButtonSegment(value: 'emudeck', label: Text('EmuDeck')), + ], + selected: {directoryService.linuxSyncPreset}, + onSelectionChanged: (selection) async { + final value = selection.first; + await directoryService.setLinuxSyncPreset(value); + ref.invalidate(directoryServiceProvider); + if (mounted) setState(() {}); + }, + ), + if (directoryService.linuxSyncPreset == 'emudeck') ...[ + const SizedBox(height: 16), + _buildPathRow( + label: 'EmuDeck Root Path', + currentPath: directoryService.emudeckRootPath ?? 'Not set', + onChanged: (newPath) async { + if (newPath != null) { + await directoryService.setEmudeckRoot(newPath); + ref.invalidate(directoryServiceProvider); + if (mounted) setState(() {}); + } + }, + ), + const SizedBox(height: 8), + const Text( + 'EmuDeck integration will use Emulation/roms and Emulation/tools inside this path.', + style: TextStyle(fontSize: 12, color: Colors.grey, fontStyle: FontStyle.italic), + ), + ], + ], + ); + } + // --- Legal Section --- Widget _buildLegalSection(BuildContext context) { return Column( diff --git a/test/unit/firmware_service_test.mocks.dart b/test/unit/firmware_service_test.mocks.dart index de3e513..8b37d0e 100644 --- a/test/unit/firmware_service_test.mocks.dart +++ b/test/unit/firmware_service_test.mocks.dart @@ -323,6 +323,17 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as String); + @override + String get linuxSyncPreset => + (super.noSuchMethod( + Invocation.getter(#linuxSyncPreset), + returnValue: _i4.dummyValue<String>( + this, + Invocation.getter(#linuxSyncPreset), + ), + ) + as String); + @override set romsRootPath(String? value) => super.noSuchMethod( Invocation.setter(#romsRootPath, value), @@ -335,6 +346,18 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { returnValueForMissingStub: null, ); + @override + set linuxSyncPreset(String? value) => super.noSuchMethod( + Invocation.setter(#linuxSyncPreset, value), + returnValueForMissingStub: null, + ); + + @override + set emudeckRootPath(String? value) => super.noSuchMethod( + Invocation.setter(#emudeckRootPath, value), + returnValueForMissingStub: null, + ); + @override _i5.Future<void> initialize() => (super.noSuchMethod( @@ -344,6 +367,24 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as _i5.Future<void>); + @override + _i5.Future<void> setLinuxSyncPreset(String? preset) => + (super.noSuchMethod( + Invocation.method(#setLinuxSyncPreset, [preset]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + + @override + _i5.Future<void> setEmudeckRoot(String? path) => + (super.noSuchMethod( + Invocation.method(#setEmudeckRoot, [path]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + @override _i5.Future<void> loadEmulatorPathOverrides() => (super.noSuchMethod( @@ -474,41 +515,72 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { as _i5.Future<String>); @override - _i5.Future<String> getEmulatorAppSupportDirectory(String? emulatorName) => + _i5.Future<String> getEmulatorAppSupportDirectory( + String? emulatorName, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorAppSupportDirectory, [emulatorName]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorAppSupportDirectory, [ - emulatorName, - ]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorBiosDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorBiosDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorSystemDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorSystemDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) diff --git a/test/unit/save_sync_service_test.mocks.dart b/test/unit/save_sync_service_test.mocks.dart index dd66357..316f366 100644 --- a/test/unit/save_sync_service_test.mocks.dart +++ b/test/unit/save_sync_service_test.mocks.dart @@ -323,6 +323,17 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as String); + @override + String get linuxSyncPreset => + (super.noSuchMethod( + Invocation.getter(#linuxSyncPreset), + returnValue: _i4.dummyValue<String>( + this, + Invocation.getter(#linuxSyncPreset), + ), + ) + as String); + @override set romsRootPath(String? value) => super.noSuchMethod( Invocation.setter(#romsRootPath, value), @@ -335,6 +346,18 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { returnValueForMissingStub: null, ); + @override + set linuxSyncPreset(String? value) => super.noSuchMethod( + Invocation.setter(#linuxSyncPreset, value), + returnValueForMissingStub: null, + ); + + @override + set emudeckRootPath(String? value) => super.noSuchMethod( + Invocation.setter(#emudeckRootPath, value), + returnValueForMissingStub: null, + ); + @override _i5.Future<void> initialize() => (super.noSuchMethod( @@ -344,6 +367,24 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as _i5.Future<void>); + @override + _i5.Future<void> setLinuxSyncPreset(String? preset) => + (super.noSuchMethod( + Invocation.method(#setLinuxSyncPreset, [preset]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + + @override + _i5.Future<void> setEmudeckRoot(String? path) => + (super.noSuchMethod( + Invocation.method(#setEmudeckRoot, [path]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + @override _i5.Future<void> loadEmulatorPathOverrides() => (super.noSuchMethod( @@ -474,41 +515,72 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { as _i5.Future<String>); @override - _i5.Future<String> getEmulatorAppSupportDirectory(String? emulatorName) => + _i5.Future<String> getEmulatorAppSupportDirectory( + String? emulatorName, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorAppSupportDirectory, [emulatorName]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorAppSupportDirectory, [ - emulatorName, - ]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorBiosDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorBiosDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorSystemDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorSystemDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) diff --git a/test/unit/strategy_registry_test.mocks.dart b/test/unit/strategy_registry_test.mocks.dart index e7fd644..cfaa6cc 100644 --- a/test/unit/strategy_registry_test.mocks.dart +++ b/test/unit/strategy_registry_test.mocks.dart @@ -55,6 +55,17 @@ class MockDirectoryService extends _i1.Mock implements _i2.DirectoryService { ) as String); + @override + String get linuxSyncPreset => + (super.noSuchMethod( + Invocation.getter(#linuxSyncPreset), + returnValue: _i3.dummyValue<String>( + this, + Invocation.getter(#linuxSyncPreset), + ), + ) + as String); + @override set romsRootPath(String? value) => super.noSuchMethod( Invocation.setter(#romsRootPath, value), @@ -67,6 +78,18 @@ class MockDirectoryService extends _i1.Mock implements _i2.DirectoryService { returnValueForMissingStub: null, ); + @override + set linuxSyncPreset(String? value) => super.noSuchMethod( + Invocation.setter(#linuxSyncPreset, value), + returnValueForMissingStub: null, + ); + + @override + set emudeckRootPath(String? value) => super.noSuchMethod( + Invocation.setter(#emudeckRootPath, value), + returnValueForMissingStub: null, + ); + @override _i4.Future<void> initialize() => (super.noSuchMethod( @@ -76,6 +99,24 @@ class MockDirectoryService extends _i1.Mock implements _i2.DirectoryService { ) as _i4.Future<void>); + @override + _i4.Future<void> setLinuxSyncPreset(String? preset) => + (super.noSuchMethod( + Invocation.method(#setLinuxSyncPreset, [preset]), + returnValue: _i4.Future<void>.value(), + returnValueForMissingStub: _i4.Future<void>.value(), + ) + as _i4.Future<void>); + + @override + _i4.Future<void> setEmudeckRoot(String? path) => + (super.noSuchMethod( + Invocation.method(#setEmudeckRoot, [path]), + returnValue: _i4.Future<void>.value(), + returnValueForMissingStub: _i4.Future<void>.value(), + ) + as _i4.Future<void>); + @override _i4.Future<void> loadEmulatorPathOverrides() => (super.noSuchMethod( @@ -206,41 +247,72 @@ class MockDirectoryService extends _i1.Mock implements _i2.DirectoryService { as _i4.Future<String>); @override - _i4.Future<String> getEmulatorAppSupportDirectory(String? emulatorName) => + _i4.Future<String> getEmulatorAppSupportDirectory( + String? emulatorName, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorAppSupportDirectory, [emulatorName]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), returnValue: _i4.Future<String>.value( _i3.dummyValue<String>( this, - Invocation.method(#getEmulatorAppSupportDirectory, [ - emulatorName, - ]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), ), ), ) as _i4.Future<String>); @override - _i4.Future<String> getEmulatorBiosDirectory(String? emulatorId) => + _i4.Future<String> getEmulatorBiosDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i4.Future<String>.value( _i3.dummyValue<String>( this, - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) as _i4.Future<String>); @override - _i4.Future<String> getEmulatorSystemDirectory(String? emulatorId) => + _i4.Future<String> getEmulatorSystemDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i4.Future<String>.value( _i3.dummyValue<String>( this, - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) diff --git a/test/widgets/library_screen_test.mocks.dart b/test/widgets/library_screen_test.mocks.dart index 44ab193..934e5cf 100644 --- a/test/widgets/library_screen_test.mocks.dart +++ b/test/widgets/library_screen_test.mocks.dart @@ -321,6 +321,17 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as String); + @override + String get linuxSyncPreset => + (super.noSuchMethod( + Invocation.getter(#linuxSyncPreset), + returnValue: _i4.dummyValue<String>( + this, + Invocation.getter(#linuxSyncPreset), + ), + ) + as String); + @override set romsRootPath(String? value) => super.noSuchMethod( Invocation.setter(#romsRootPath, value), @@ -333,6 +344,18 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { returnValueForMissingStub: null, ); + @override + set linuxSyncPreset(String? value) => super.noSuchMethod( + Invocation.setter(#linuxSyncPreset, value), + returnValueForMissingStub: null, + ); + + @override + set emudeckRootPath(String? value) => super.noSuchMethod( + Invocation.setter(#emudeckRootPath, value), + returnValueForMissingStub: null, + ); + @override _i5.Future<void> initialize() => (super.noSuchMethod( @@ -342,6 +365,24 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { ) as _i5.Future<void>); + @override + _i5.Future<void> setLinuxSyncPreset(String? preset) => + (super.noSuchMethod( + Invocation.method(#setLinuxSyncPreset, [preset]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + + @override + _i5.Future<void> setEmudeckRoot(String? path) => + (super.noSuchMethod( + Invocation.method(#setEmudeckRoot, [path]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + @override _i5.Future<void> loadEmulatorPathOverrides() => (super.noSuchMethod( @@ -472,41 +513,72 @@ class MockDirectoryService extends _i1.Mock implements _i8.DirectoryService { as _i5.Future<String>); @override - _i5.Future<String> getEmulatorAppSupportDirectory(String? emulatorName) => + _i5.Future<String> getEmulatorAppSupportDirectory( + String? emulatorName, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorAppSupportDirectory, [emulatorName]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorAppSupportDirectory, [ - emulatorName, - ]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorBiosDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorBiosDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorSystemDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorSystemDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) diff --git a/test/widgets/settings_screen_test.mocks.dart b/test/widgets/settings_screen_test.mocks.dart index ad21c9e..03e41e7 100644 --- a/test/widgets/settings_screen_test.mocks.dart +++ b/test/widgets/settings_screen_test.mocks.dart @@ -65,6 +65,17 @@ class MockDirectoryService extends _i1.Mock implements _i3.DirectoryService { ) as String); + @override + String get linuxSyncPreset => + (super.noSuchMethod( + Invocation.getter(#linuxSyncPreset), + returnValue: _i4.dummyValue<String>( + this, + Invocation.getter(#linuxSyncPreset), + ), + ) + as String); + @override set romsRootPath(String? value) => super.noSuchMethod( Invocation.setter(#romsRootPath, value), @@ -77,6 +88,18 @@ class MockDirectoryService extends _i1.Mock implements _i3.DirectoryService { returnValueForMissingStub: null, ); + @override + set linuxSyncPreset(String? value) => super.noSuchMethod( + Invocation.setter(#linuxSyncPreset, value), + returnValueForMissingStub: null, + ); + + @override + set emudeckRootPath(String? value) => super.noSuchMethod( + Invocation.setter(#emudeckRootPath, value), + returnValueForMissingStub: null, + ); + @override _i5.Future<void> initialize() => (super.noSuchMethod( @@ -86,6 +109,24 @@ class MockDirectoryService extends _i1.Mock implements _i3.DirectoryService { ) as _i5.Future<void>); + @override + _i5.Future<void> setLinuxSyncPreset(String? preset) => + (super.noSuchMethod( + Invocation.method(#setLinuxSyncPreset, [preset]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + + @override + _i5.Future<void> setEmudeckRoot(String? path) => + (super.noSuchMethod( + Invocation.method(#setEmudeckRoot, [path]), + returnValue: _i5.Future<void>.value(), + returnValueForMissingStub: _i5.Future<void>.value(), + ) + as _i5.Future<void>); + @override _i5.Future<void> loadEmulatorPathOverrides() => (super.noSuchMethod( @@ -216,41 +257,72 @@ class MockDirectoryService extends _i1.Mock implements _i3.DirectoryService { as _i5.Future<String>); @override - _i5.Future<String> getEmulatorAppSupportDirectory(String? emulatorName) => + _i5.Future<String> getEmulatorAppSupportDirectory( + String? emulatorName, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorAppSupportDirectory, [emulatorName]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorAppSupportDirectory, [ - emulatorName, - ]), + Invocation.method( + #getEmulatorAppSupportDirectory, + [emulatorName], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorBiosDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorBiosDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorBiosDirectory, [emulatorId]), + Invocation.method( + #getEmulatorBiosDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), ) as _i5.Future<String>); @override - _i5.Future<String> getEmulatorSystemDirectory(String? emulatorId) => + _i5.Future<String> getEmulatorSystemDirectory( + String? emulatorId, { + String? platformSlug, + }) => (super.noSuchMethod( - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), returnValue: _i5.Future<String>.value( _i4.dummyValue<String>( this, - Invocation.method(#getEmulatorSystemDirectory, [emulatorId]), + Invocation.method( + #getEmulatorSystemDirectory, + [emulatorId], + {#platformSlug: platformSlug}, + ), ), ), )