Skip to content

Commit

Permalink
feat: Add list of custom Proton versions
Browse files Browse the repository at this point in the history
  • Loading branch information
ashuntu committed Oct 8, 2024
1 parent 184a0ae commit f284696
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Flutter app for system and game tweaks and information.

## Development

*At the moment, this app requires you to have the Steam snap installed and
opened at least once.*

1. Install [Flutter](https://docs.flutter.dev/get-started/install/linux/desktop)
and [Melos](https://melos.invertase.dev/~melos-latest/getting-started)
- This repository uses [FVM](https://fvm.app/) for maintaining Flutter versions
Expand Down
2 changes: 2 additions & 0 deletions packages/game_center/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"steamEnableProton": "Enable Steam Play (Proton) for all titles",
"steamEnableMangoHUD": "Enable MangoHUD for all titles",
"steamEnableGameMode": "Enable GameMode for all titles",
"steamProtonTitle": "Proton Versions",
"steamNoProtonVersions": "None",

"settingsPageLabel": "Settings",

Expand Down
47 changes: 47 additions & 0 deletions packages/game_center/lib/steam/proton_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'dart:io';

import 'package:game_center/steam/steam_data.dart';
import 'package:path/path.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:watcher/watcher.dart';

part 'proton_model.g.dart';

@riverpod
class ProtonModel extends _$ProtonModel {
late String installLocation;
late List<String> protonVersions;

Future<List<String>> build({String? install}) async {
// default install location
if (install == null) {
final home = Platform.environment['SNAP_REAL_HOME'] ??
Platform.environment['HOME'];
if (home == null) {
throw StateError('Home directory not found.');
}
install = '$home/snap/steam/common';
}

installLocation = install;

// directory isn't created by Steam by default, so ensure it exists
final protonDir = Directory(protonDirectory(installLocation));
protonDir.create(recursive: true);

await updateProtonVersions();

final fileSystem = FileWatcher(protonDirectory(installLocation));
fileSystem.events.listen((event) async => await updateProtonVersions());

return protonVersions;
}

Future<void> updateProtonVersions() async {
final protonDir = Directory(protonDirectory(installLocation));
final fileStream = await protonDir.list().toList();
protonVersions = fileStream.map((x) => basename(x.path)).toList();

state = AsyncData(protonVersions);
}
}
21 changes: 21 additions & 0 deletions packages/game_center/lib/steam/steam_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Directory within Steam's install path where actual Steam data is found.
const steamDataDir = '.steam/steam';

/// Directory where Steam expects 3rd party Proton versions to be.
String protonDirectory(String installLocation) {
return '$installLocation/$steamDataDir/compatibilitytools.d';
}

/// Steam's global settings file path.
String steamGlobalConfig(String installLocation) {
return '$installLocation/$steamDataDir/config/config.vdf';
}

/// Steam user settings *(not to be confused with the Linux user)* file path.
///
/// Most users of Steam will only have 1 account per Linux user. However, it is
/// possible to log in to multiple Steam accounts from a single Linux user so a
/// `userID` must be provided.
String steamUserConfig(String installLocation, String userID) {
return '$installLocation/$steamDataDir/userdata/$userID/config/localconfig.vdf';
}
19 changes: 1 addition & 18 deletions packages/game_center/lib/steam/steam_model.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';

import 'package:game_center/steam/steam_data.dart';
import 'package:game_center/util.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:vdf/vdf.dart';
Expand All @@ -8,29 +9,11 @@ import 'package:path/path.dart' as path;

part 'steam_model.g.dart';

const steamDataDir = '.steam/steam';

/// Steam's global settings
String steamGlobalConfig(String installLocation) {
return '$installLocation/$steamDataDir/config/config.vdf';
}

/// Steam user settings *(not to be confused with the Linux user)*.
///
/// Most users of Steam will only have 1 account per Linux user. However, it is
/// possible to log in to multiple Steam accounts from a single Linux user.
String steamUserConfig(String installLocation, String userID) {
return '$installLocation/$steamDataDir/userdata/$userID/config/localconfig.vdf';
}

typedef Config = ({
Map<String, dynamic> globalConfig,
Map<String, Map<String, dynamic>> userConfigs,
SteamUser activeUser,
});
// typedef SteamUser = ({
// String id,
// });

class SteamUser {
SteamUser({
Expand Down
36 changes: 36 additions & 0 deletions packages/game_center/lib/steam/steam_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:game_center/layout.dart';
import 'package:game_center/steam/proton_model.dart';
import 'package:game_center/steam/steam_model.dart';
import 'package:game_center/widgets/expandable_page_section.dart';
import 'package:vdf/vdf.dart';
Expand Down Expand Up @@ -46,6 +47,13 @@ class SteamPage extends ConsumerWidget {
ExpandablePageSection(
title: l10n.advancedTitle,
children: [
Text(
l10n.steamProtonTitle,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: kPagePadding),
_SteamProtonVersions(),
const SizedBox(height: kPagePadding),
Text(
l10n.steamGlobalConfigTitle,
style: Theme.of(context).textTheme.titleLarge,
Expand Down Expand Up @@ -126,6 +134,34 @@ class _SteamSimpleSettings extends ConsumerWidget {
}
}

class _SteamProtonVersions extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context);
final proton = ref.watch(protonModelProvider());

return proton.when(
data: (data) => Column(
children: [
if (data.isEmpty)
Text(l10n.steamNoProtonVersions)
else
for (final version in data)
YaruTile(
title: Text(version),
),
],
),
error: (error, trace) => Center(
child: Text(error.toString()),
),
loading: () => Center(
child: Text(l10n.loadingLabel),
),
);
}
}

class _SteamGlobalConfigText extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
Expand Down
18 changes: 18 additions & 0 deletions packages/game_center/test/steam/proton_model_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dart:io';

import 'package:flutter_test/flutter_test.dart';
import 'package:game_center/steam/proton_model.dart';

import 'test_utils.dart';

void main() {
test('build', () async {
final container = createContainer();
final provider = protonModelProvider();
container.read(provider.future);
final model = container.read(provider.notifier);

final directory = Directory(model.installLocation);
expect(await directory.exists(), isTrue);
});
}

0 comments on commit f284696

Please sign in to comment.