From b81dc86bffaa6cfc4118aa9e82a2b697c1e6e559 Mon Sep 17 00:00:00 2001 From: ashuntu Date: Fri, 20 Sep 2024 16:55:22 -0500 Subject: [PATCH] Add toggles for enabling MangoHUD and Gamemode for all titles This implementation is very slow and triggers a lot of unnecessary file operations. Optimization to come in a subsequent commit. --- packages/game_center/lib/l10n/app_en.arb | 2 + .../game_center/lib/steam/steam_model.dart | 95 +++++++++++++++++-- .../game_center/lib/steam/steam_page.dart | 45 ++++++++- 3 files changed, 134 insertions(+), 8 deletions(-) diff --git a/packages/game_center/lib/l10n/app_en.arb b/packages/game_center/lib/l10n/app_en.arb index 5ed8305..5fc1b03 100644 --- a/packages/game_center/lib/l10n/app_en.arb +++ b/packages/game_center/lib/l10n/app_en.arb @@ -11,6 +11,8 @@ "steamGlobalConfigTitle": "Steam Global Config", "steamUserConfigTitle": "Steam User Configs", "steamEnableProton": "Enable Steam Play (Proton) for all titles", + "steamEnableMangoHUD": "Enable MangoHUD for all titles", + "steamEnableGameMode": "Enable GameMode for all titles", "settingsPageLabel": "Settings", diff --git a/packages/game_center/lib/steam/steam_model.dart b/packages/game_center/lib/steam/steam_model.dart index b9e27c8..05be5b8 100644 --- a/packages/game_center/lib/steam/steam_model.dart +++ b/packages/game_center/lib/steam/steam_model.dart @@ -26,13 +26,36 @@ String steamUserConfig(String installLocation, String userID) { typedef Config = ({ Map globalConfig, Map> userConfigs, + SteamUser activeUser, }); +// typedef SteamUser = ({ +// String id, +// }); + +class SteamUser { + SteamUser({ + required this.id, + required this.name, + }); + + factory SteamUser.fromConfig(Map config) { + final id = config['UserLocalConfigStore']['friends'].keys.first; + return SteamUser( + id: id, + name: config['UserLocalConfigStore']['friends'][id]['NameHistory']['0'], + ); + } + + late final String id; + late final String name; +} @riverpod class SteamModel extends _$SteamModel { late String installLocation; late Map globalConfig; late Map> userConfigs; + late SteamUser activeUser; @override Future build({String? install}) async { @@ -76,9 +99,12 @@ class SteamModel extends _$SteamModel { }); } + activeUser = SteamUser.fromConfig(userConfigs.values.first); + return ( globalConfig: globalConfig, userConfigs: userConfigs, + activeUser: activeUser, ); } @@ -96,6 +122,7 @@ class SteamModel extends _$SteamModel { state = AsyncData(( globalConfig: globalConfig, userConfigs: userConfigs, + activeUser: activeUser, )); } @@ -105,6 +132,16 @@ class SteamModel extends _$SteamModel { state = AsyncData(( globalConfig: globalConfig, userConfigs: userConfigs, + activeUser: activeUser, + )); + } + + Future setActiveUser(String newActiveUserID) async { + activeUser = SteamUser.fromConfig(userConfigs[newActiveUserID]!); + state = AsyncData(( + globalConfig: globalConfig, + userConfigs: userConfigs, + activeUser: activeUser, )); } @@ -165,24 +202,41 @@ class SteamModel extends _$SteamModel { } /// Get a map of installed Steam apps for the given user. - Future> listApps({required String steamID}) async { + Map listApps({required String steamID}) { Map config = Map.from(userConfigs[steamID]!); var apps = config['UserLocalConfigStore']['Software']['Valve']['Steam'] ['apps'] as Map; return apps.cast(); } - Future getGameLaunchOptions({ + bool allGamesHaveOption({ + required String steamID, + required String option, + }) { + final apps = listApps(steamID: steamID); + for (final app in apps.keys) { + final launchOptions = getGameLaunchOptions(steamID: steamID, appID: app); + List options = + launchOptions.isEmpty ? [] : launchOptions.split(RegExp(r'\s+')); + if (!options.contains(option)) { + return false; + } + } + + return true; + } + + String getGameLaunchOptions({ required String steamID, required String appID, - }) async { + }) { Map config = Map.from(userConfigs[steamID]!); - String launchOptions = config['UserLocalConfigStore']['Software']['Valve'] + String? launchOptions = config['UserLocalConfigStore']['Software']['Valve'] ['Steam']['apps'][appID]['LaunchOptions']; - return launchOptions; + return launchOptions ?? ''; } - /// Set the raw launch options for a specific app. + /// Set the raw launch options for a specific app.checked Future setGameLaunchOptions({ required String steamID, required String appID, @@ -196,6 +250,34 @@ class SteamModel extends _$SteamModel { await updateUserConfig(steamID); } + Future addAllGameLaunchOption({ + required String steamID, + required String option, + }) async { + final apps = await listApps(steamID: steamID); + for (final app in apps.keys) { + await addGameLaunchOption( + steamID: steamID, + appID: app, + option: option, + ); + } + } + + Future removeAllGameLaunchOption({ + required String steamID, + required String option, + }) async { + final apps = await listApps(steamID: steamID); + for (final app in apps.keys) { + await removeGameLaunchOption( + steamID: steamID, + appID: app, + option: option, + ); + } + } + // Adds an option to a game's launch options. This function does nothing if // the option already exists for the game. Future addGameLaunchOption({ @@ -236,7 +318,6 @@ class SteamModel extends _$SteamModel { List options = launchOptions.isEmpty ? [] : launchOptions.split(RegExp(r'\s+')); options.remove(option); - print(options); await setGameLaunchOptions( steamID: steamID, appID: appID, diff --git a/packages/game_center/lib/steam/steam_page.dart b/packages/game_center/lib/steam/steam_page.dart index 750424c..60f6728 100644 --- a/packages/game_center/lib/steam/steam_page.dart +++ b/packages/game_center/lib/steam/steam_page.dart @@ -18,6 +18,7 @@ class SteamPage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); final steam = ref.watch(steamModelProvider()); + final notifier = ref.watch(steamModelProvider().notifier); return steam.when( data: (data) => AppScrollView( @@ -27,6 +28,16 @@ class SteamPage extends ConsumerWidget { style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: kPagePadding), + YaruPopupMenuButton( + child: Text(data.activeUser.name), + itemBuilder: (context) => data.userConfigs.values.map((id) { + var user = SteamUser.fromConfig(id); + return PopupMenuItem( + child: Text(user.name), + onTap: () => notifier.setActiveUser(user.id), + ); + }).toList(), + ), _SteamSimpleSettings(), const SizedBox(height: kPagePadding), Text( @@ -48,7 +59,7 @@ class SteamPage extends ConsumerWidget { child: Text(l10n.loadingLabel), ), error: (error, stackTrace) => Center( - child: Text(error.toString()), + child: Text('${error.toString()}\n${stackTrace.toString()}'), ), ); } @@ -70,6 +81,38 @@ class _SteamSimpleSettings extends ConsumerWidget { await steam.enableSteamPlay(enable: value); }, ), + YaruSwitchListTile( + title: Text(l10n.steamEnableMangoHUD), + value: steam.allGamesHaveOption( + steamID: steam.activeUser.id, option: 'mangohud'), + onChanged: (value) async { + value + ? await steam.addAllGameLaunchOption( + steamID: steam.activeUser.id, + option: 'mangohud', + ) + : await steam.removeAllGameLaunchOption( + steamID: steam.activeUser.id, + option: 'mangohud', + ); + }, + ), + YaruSwitchListTile( + title: Text(l10n.steamEnableGameMode), + value: steam.allGamesHaveOption( + steamID: steam.activeUser.id, option: 'gamemode'), + onChanged: (value) async { + value + ? await steam.addAllGameLaunchOption( + steamID: steam.activeUser.id, + option: 'gamemode', + ) + : await steam.removeAllGameLaunchOption( + steamID: steam.activeUser.id, + option: 'gamemode', + ); + }, + ), ], ); }