-
-
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},
+ ),
),
),
)