From bba2dbd3608746eeb1fc025c1f7ff5ef8a03b649 Mon Sep 17 00:00:00 2001 From: xkeyC <3334969096@qq.com> Date: Tue, 23 Dec 2025 22:40:05 +0800 Subject: [PATCH] feat: linux support --- lib/common/helper/log_helper.dart | 35 +- lib/common/helper/system_helper.dart | 3 +- lib/common/utils/multi_window_manager.dart | 3 +- lib/provider/unp4kc.dart | 3 +- .../localization/localization_dialog_ui.dart | 516 ++++++++---------- .../localization/localization_ui_model.dart | 33 +- lib/ui/settings/settings_ui_model.dart | 4 +- .../rsi_launcher_enhance_dialog_ui.dart | 272 ++++----- lib/ui/tools/tools_ui_model.dart | 75 +-- linux/CMakeLists.txt | 16 +- linux/com.starcitizen_doctor.desktop | 9 + .../128x128/apps/starcitizen_doctor.png | Bin 0 -> 9365 bytes .../hicolor/16x16/apps/starcitizen_doctor.png | Bin 0 -> 879 bytes .../256x256/apps/starcitizen_doctor.png | Bin 0 -> 19161 bytes .../hicolor/32x32/apps/starcitizen_doctor.png | Bin 0 -> 2003 bytes .../hicolor/48x48/apps/starcitizen_doctor.png | Bin 0 -> 3242 bytes .../hicolor/64x64/apps/starcitizen_doctor.png | Bin 0 -> 4495 bytes linux/my_application.cc | 5 +- rust/src/api/asar_api.rs | 4 +- rust/src/webview/webview_impl.rs | 8 +- 20 files changed, 514 insertions(+), 472 deletions(-) create mode 100644 linux/com.starcitizen_doctor.desktop create mode 100644 linux/icons/hicolor/128x128/apps/starcitizen_doctor.png create mode 100644 linux/icons/hicolor/16x16/apps/starcitizen_doctor.png create mode 100644 linux/icons/hicolor/256x256/apps/starcitizen_doctor.png create mode 100644 linux/icons/hicolor/32x32/apps/starcitizen_doctor.png create mode 100644 linux/icons/hicolor/48x48/apps/starcitizen_doctor.png create mode 100644 linux/icons/hicolor/64x64/apps/starcitizen_doctor.png diff --git a/lib/common/helper/log_helper.dart b/lib/common/helper/log_helper.dart index f6022e9..470993a 100644 --- a/lib/common/helper/log_helper.dart +++ b/lib/common/helper/log_helper.dart @@ -8,7 +8,15 @@ import 'package:starcitizen_doctor/common/utils/log.dart'; class SCLoggerHelper { static Future getLogFilePath() async { - if (!Platform.isWindows) return null; + if (!Platform.isWindows) { + final wineUserPath = await getWineUserPath(); + if (wineUserPath == null) return null; + // /home/xkeyc/Games/star-citizen/drive_c/users/xkeyc/AppData/Roaming/rsilauncher/ + final rsiLauncherPath = "$wineUserPath/AppData/Roaming/rsilauncher"; + dPrint("rsiLauncherPath Wine:$rsiLauncherPath"); + final jsonLogPath = "$rsiLauncherPath/logs/log.log"; + return jsonLogPath; + }; Map envVars = Platform.environment; final appDataPath = envVars["appdata"]; if (appDataPath == null) { @@ -21,6 +29,14 @@ class SCLoggerHelper { } static Future getShaderCachePath() async { + if (!Platform.isWindows) { + final wineUserPath = await getWineUserPath(); + if (wineUserPath == null) return null; + // /home/xkeyc/Games/star-citizen/drive_c/users/xkeyc/AppData/Local/star citizen/ + final scCachePath = "$wineUserPath/AppData/Local/star citizen"; + dPrint("getShaderCachePath Wine === $scCachePath"); + return scCachePath; + } Map envVars = Platform.environment; final appDataPath = envVars["LOCALAPPDATA"]; if (appDataPath == null) { @@ -31,6 +47,23 @@ class SCLoggerHelper { return scCachePath; } + static Future getWineUserPath() async { + // get game path in hiveBox + final confBox = await Hive.openBox("app_conf"); + final path = confBox.get("custom_game_path"); + if (path?.isEmpty ?? true) return null; + // path eg: /home/xkeyc/Games/star-citizen/drive_c/Program Files/Roberts Space Industries/StarCitizen/LIVE/ + // resolve wine c_drive path + final wineCDrivePath = path.toString().split('/drive_c/').first; + // scan wine user path == current_unix_user + final wineUserPath = "$wineCDrivePath/drive_c/users/${Platform.environment['USER']}"; + // check exists + final wineUserDir = Directory(wineUserPath); + if (!await wineUserDir.exists()) return null; + dPrint("getWineUserPath === $wineUserPath"); + return wineUserPath; + } + static Future getLauncherLogList() async { if (!Platform.isWindows) return []; try { diff --git a/lib/common/helper/system_helper.dart b/lib/common/helper/system_helper.dart index 6696366..b1a09d2 100644 --- a/lib/common/helper/system_helper.dart +++ b/lib/common/helper/system_helper.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:hive_ce/hive.dart'; +import 'package:starcitizen_doctor/common/utils/base_utils.dart'; import 'package:starcitizen_doctor/common/utils/log.dart'; import 'package:starcitizen_doctor/common/rust/api/win32_api.dart' as win32; @@ -41,7 +42,7 @@ class SystemHelper { if (path != null && path != "") { if (await File(path).exists()) { if (skipEXE) { - return "${path.toString().replaceAll("\\RSI Launcher.exe", "")}\\"; + return "${path.toString().replaceAll("\\RSI Launcher.exe".platformPath, "")}\\".platformPath; } return path; } diff --git a/lib/common/utils/multi_window_manager.dart b/lib/common/utils/multi_window_manager.dart index 74742de..5b031f7 100644 --- a/lib/common/utils/multi_window_manager.dart +++ b/lib/common/utils/multi_window_manager.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:fluent_ui/fluent_ui.dart'; @@ -112,7 +113,7 @@ class MultiWindowManager { await Window.initialize(); - if (windowAppState.windowsVersion >= 10) { + if (Platform.isWindows && windowAppState.windowsVersion >= 10) { await Window.setEffect(effect: WindowEffect.acrylic); } diff --git a/lib/provider/unp4kc.dart b/lib/provider/unp4kc.dart index 87cecdc..b91b44b 100644 --- a/lib/provider/unp4kc.dart +++ b/lib/provider/unp4kc.dart @@ -10,6 +10,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:starcitizen_doctor/api/analytics.dart'; import 'package:starcitizen_doctor/common/helper/log_helper.dart'; +import 'package:starcitizen_doctor/common/utils/base_utils.dart'; import 'package:starcitizen_doctor/common/utils/log.dart'; import 'package:starcitizen_doctor/data/app_unp4k_p4k_item_data.dart'; import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart'; @@ -80,7 +81,7 @@ class Unp4kCModel extends _$Unp4kCModel { void _init() async { final gamePath = getGamePath(); - final gameP4kPath = "$gamePath\\Data.p4k"; + final gameP4kPath = "$gamePath\\Data.p4k".platformPath; try { state = state.copyWith(endMessage: S.current.tools_unp4k_msg_reading); diff --git a/lib/ui/home/localization/localization_dialog_ui.dart b/lib/ui/home/localization/localization_dialog_ui.dart index 1f71c60..47aec03 100644 --- a/lib/ui/home/localization/localization_dialog_ui.dart +++ b/lib/ui/home/localization/localization_dialog_ui.dart @@ -30,13 +30,9 @@ class LocalizationDialogUI extends HookConsumerWidget { return ContentDialog( title: makeTitle(context, model, state), constraints: BoxConstraints( - maxWidth: MediaQuery - .of(context) - .size - .width * .7, minHeight: MediaQuery - .of(context) - .size - .height * .9), + maxWidth: MediaQuery.of(context).size.width * .7, + minHeight: MediaQuery.of(context).size.height * .9, + ), content: Padding( padding: const EdgeInsets.only(left: 12, right: 12, top: 12), child: SingleChildScrollView( @@ -44,132 +40,128 @@ class LocalizationDialogUI extends HookConsumerWidget { children: [ AnimatedSize( duration: const Duration(milliseconds: 130), - child: state.patchStatus?.key == true && - state.patchStatus?.value == S.current.home_action_info_game_built_in + child: + state.patchStatus?.key == true && + state.patchStatus?.value == S.current.home_action_info_game_built_in ? Padding( - padding: const EdgeInsets.only(bottom: 12), - child: InfoBar( - title: Text(S.current.home_action_info_warning), - content: Text(S.current.localization_info_machine_translation_warning), - severity: InfoBarSeverity.info, - style: InfoBarThemeData(decoration: (severity) { - return const BoxDecoration(color: Color.fromRGBO(155, 7, 7, 1.0)); - }, iconColor: (severity) { - return Colors.white; - }), - ), - ) - : SizedBox( - width: MediaQuery - .of(context) - .size - .width, - ), + padding: const EdgeInsets.only(bottom: 12), + child: InfoBar( + title: Text(S.current.home_action_info_warning), + content: Text(S.current.localization_info_machine_translation_warning), + severity: InfoBarSeverity.info, + style: InfoBarThemeData( + decoration: (severity) { + return const BoxDecoration(color: Color.fromRGBO(155, 7, 7, 1.0)); + }, + iconColor: (severity) { + return Colors.white; + }, + ), + ), + ) + : SizedBox(width: MediaQuery.of(context).size.width), ), makeToolsListContainer(context, model, state), - makeListContainer( - S.current.localization_info_translation, - [ - if (state.patchStatus == null) - makeLoading(context) - else - ...[ - const SizedBox(height: 6), - Row( - children: [ - Center( - child: Text(S.current.localization_info_enabled( - LocalizationUIModel.languageSupport[state.selectedLanguage] ?? "")), - ), - const Spacer(), - ToggleSwitch( - checked: state.patchStatus?.key == true, - onChanged: model.updateLangCfg, - ) - ], + makeListContainer(S.current.localization_info_translation, [ + if (state.patchStatus == null) + makeLoading(context) + else ...[ + const SizedBox(height: 6), + Row( + children: [ + Center( + child: Text( + S.current.localization_info_enabled( + LocalizationUIModel.languageSupport[state.selectedLanguage] ?? "", + ), ), - const SizedBox(height: 12), - Row( + ), + const Spacer(), + ToggleSwitch(checked: state.patchStatus?.key == true, onChanged: model.updateLangCfg), + ], + ), + const SizedBox(height: 12), + Row( + children: [ + Expanded( + child: Row( children: [ - Expanded( - child: Row( - children: [ - Text(S.current.localization_info_installed_version( - "${state.patchStatus?.value ?? ""} ${(state.isInstalledAdvanced ?? false) ? S - .current.home_localization_msg_version_advanced : ""}")), - SizedBox(width: 24), - if (state.installedCommunityInputMethodSupportVersion != null) - Text( - S.current.input_method_community_input_method_support_version( - state.installedCommunityInputMethodSupportVersion ?? "?"), - ) - ], + Text( + S.current.localization_info_installed_version( + "${state.patchStatus?.value ?? ""} ${(state.isInstalledAdvanced ?? false) ? S.current.home_localization_msg_version_advanced : ""}", ), ), - if (state.patchStatus?.value != S.current.home_action_info_game_built_in) - Row( - children: [ - Button( - onPressed: model.goFeedback, - child: Padding( - padding: const EdgeInsets.all(4), - child: Row( - children: [ - const Icon(FluentIcons.feedback), - const SizedBox(width: 6), - Text(S.current.localization_action_translation_feedback), - ], - ), - )), - const SizedBox(width: 16), - Button( - onPressed: model.doDelIniFile(), - child: Padding( - padding: const EdgeInsets.all(4), - child: Row( - children: [ - const Icon(FluentIcons.delete), - const SizedBox(width: 6), - Text(S.current.localization_action_uninstall_translation), - ], - ), - )), - ], + SizedBox(width: 24), + if (state.installedCommunityInputMethodSupportVersion != null) + Text( + S.current.input_method_community_input_method_support_version( + state.installedCommunityInputMethodSupportVersion ?? "?", + ), ), ], ), - const SizedBox(height: 12), - Container( - color: Colors.white.withValues(alpha: .1), - height: 1, - ), - const SizedBox(height: 12), - if (state.apiLocalizationData == null) - makeLoading(context) - else - if (state.apiLocalizationData!.isEmpty) - Center( - child: Text( - S.current.localization_info_no_translation_available, - style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .8)), + ), + if (state.patchStatus?.value != S.current.home_action_info_game_built_in) + Row( + children: [ + Button( + onPressed: model.goFeedback, + child: Padding( + padding: const EdgeInsets.all(4), + child: Row( + children: [ + const Icon(FluentIcons.feedback), + const SizedBox(width: 6), + Text(S.current.localization_action_translation_feedback), + ], + ), ), - ) - else - AlignedGridView.count( - crossAxisCount: 2, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - itemBuilder: (BuildContext context, int index) { - final item = state.apiLocalizationData!.entries.elementAt(index); - return makeRemoteList(context, model, item, state, index); - }, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: state.apiLocalizationData?.length ?? 0, - ) - ], - ], - context), + ), + const SizedBox(width: 16), + Button( + onPressed: model.doDelIniFile(), + child: Padding( + padding: const EdgeInsets.all(4), + child: Row( + children: [ + const Icon(FluentIcons.delete), + const SizedBox(width: 6), + Text(S.current.localization_action_uninstall_translation), + ], + ), + ), + ), + ], + ), + ], + ), + const SizedBox(height: 12), + Container(color: Colors.white.withValues(alpha: .1), height: 1), + const SizedBox(height: 12), + if (state.apiLocalizationData == null) + makeLoading(context) + else if (state.apiLocalizationData!.isEmpty) + Center( + child: Text( + S.current.localization_info_no_translation_available, + style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .8)), + ), + ) + else + AlignedGridView.count( + crossAxisCount: 2, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + itemBuilder: (BuildContext context, int index) { + final item = state.apiLocalizationData!.entries.elementAt(index); + return makeRemoteList(context, model, item, state, index); + }, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: state.apiLocalizationData?.length ?? 0, + ), + ], + ], context), ], ), ), @@ -177,8 +169,13 @@ class LocalizationDialogUI extends HookConsumerWidget { ); } - Widget makeRemoteList(BuildContext context, LocalizationUIModel model, MapEntry item, - LocalizationUIState state, int index) { + Widget makeRemoteList( + BuildContext context, + LocalizationUIModel model, + MapEntry item, + LocalizationUIState state, + int index, + ) { final isWorking = state.workingVersion.isNotEmpty; final isMineWorking = state.workingVersion == item.key; final isInstalled = state.patchStatus?.value == item.key; @@ -207,10 +204,7 @@ class LocalizationDialogUI extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "${item.value.info}", - style: const TextStyle(fontSize: 19), - ), + Text("${item.value.info}", style: const TextStyle(fontSize: 19)), const SizedBox(height: 4), Text( S.current.localization_info_version_number(item.value.versionName ?? ""), @@ -230,40 +224,30 @@ class LocalizationDialogUI extends HookConsumerWidget { ), ), if (isMineWorking) - const Padding( - padding: EdgeInsets.only(right: 12), - child: ProgressRing(), - ) - else - ...[ - Icon( - isInstalled - ? FluentIcons.check_mark - : isItemEnabled - ? FluentIcons.download - : FluentIcons.disable_updates, - color: Colors.white.withValues(alpha: .8), - size: 18, - ), - const SizedBox(width: 6), - Text( - isInstalled - ? S.current.localization_info_installed - : (isItemEnabled - ? S.current.localization_action_install - : S.current.localization_info_unavailable), - style: TextStyle( - color: Colors.white.withValues(alpha: .8), - ), - ), - const SizedBox(width: 6), - if ((!isInstalled) && isItemEnabled) - Icon( - FluentIcons.chevron_right, - size: 14, - color: Colors.white.withValues(alpha: .6), - ) - ] + const Padding(padding: EdgeInsets.only(right: 12), child: ProgressRing()) + else ...[ + Icon( + isInstalled + ? FluentIcons.check_mark + : isItemEnabled + ? FluentIcons.download + : FluentIcons.disable_updates, + color: Colors.white.withValues(alpha: .8), + size: 18, + ), + const SizedBox(width: 6), + Text( + isInstalled + ? S.current.localization_info_installed + : (isItemEnabled + ? S.current.localization_action_install + : S.current.localization_info_unavailable), + style: TextStyle(color: Colors.white.withValues(alpha: .8)), + ), + const SizedBox(width: 6), + if ((!isInstalled) && isItemEnabled) + Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)), + ], ], ), if (item.value.note != null) ...[ @@ -272,10 +256,7 @@ class LocalizationDialogUI extends HookConsumerWidget { "${item.value.note}", maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - color: Colors.white.withValues(alpha: .4), - fontSize: 13, - ), + style: TextStyle(color: Colors.white.withValues(alpha: .4), fontSize: 13), ), ], ], @@ -286,16 +267,20 @@ class LocalizationDialogUI extends HookConsumerWidget { ); } - Widget makeListContainer(String title, List children, BuildContext context, - {List actions = const [], bool gridViewMode = false, int gridViewCrossAxisCount = 2}) { + Widget makeListContainer( + String title, + List children, + BuildContext context, { + List actions = const [], + bool gridViewMode = false, + int gridViewCrossAxisCount = 2, + }) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: AnimatedSize( duration: const Duration(milliseconds: 130), child: Container( - decoration: BoxDecoration(color: FluentTheme - .of(context) - .cardColor, borderRadius: BorderRadius.circular(7)), + decoration: BoxDecoration(color: FluentTheme.of(context).cardColor, borderRadius: BorderRadius.circular(7)), child: Padding( padding: const EdgeInsets.only(top: 12, bottom: 12, left: 24, right: 24), child: Column( @@ -303,21 +288,13 @@ class LocalizationDialogUI extends HookConsumerWidget { children: [ Row( children: [ - Text( - title, - style: const TextStyle(fontSize: 22), - ), + Text(title, style: const TextStyle(fontSize: 22)), const Spacer(), if (actions.isNotEmpty) ...actions, ], ), - const SizedBox( - height: 6, - ), - Container( - color: Colors.white.withValues(alpha: .1), - height: 1, - ), + const SizedBox(height: 6), + Container(color: Colors.white.withValues(alpha: .1), height: 1), const SizedBox(height: 12), if (gridViewMode) AlignedGridView.count( @@ -332,7 +309,7 @@ class LocalizationDialogUI extends HookConsumerWidget { itemCount: children.length, ) else - ...children + ...children, ], ), ), @@ -344,55 +321,46 @@ class LocalizationDialogUI extends HookConsumerWidget { Widget makeTitle(BuildContext context, LocalizationUIModel model, LocalizationUIState state) { return Row( children: [ - IconButton( - icon: const Icon( - FluentIcons.back, - size: 22, - ), - onPressed: model.onBack(context)), + IconButton(icon: const Icon(FluentIcons.back, size: 22), onPressed: model.onBack(context)), const SizedBox(width: 12), Text(S.current.home_action_localization_management), const SizedBox(width: 24), - Text( - "${model.getScInstallPath()}", - style: const TextStyle(fontSize: 13), + Expanded( + child: Text( + "${model.getScInstallPath()}", + style: const TextStyle(fontSize: 13), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), ), - const Spacer(), + SizedBox(width: 24), SizedBox( height: 36, child: Row( children: [ - Text( - S.current.localization_info_language, - style: const TextStyle(fontSize: 16), - ), + Text(S.current.localization_info_language, style: const TextStyle(fontSize: 16)), const SizedBox(width: 12), ComboBox( value: state.selectedLanguage, items: [ for (final lang in LocalizationUIModel.languageSupport.entries) - ComboBoxItem( - value: lang.key, - child: Text(lang.value), - ) + ComboBoxItem(value: lang.key, child: Text(lang.value)), ], onChanged: state.workingVersion.isNotEmpty ? null : (v) { - if (v == null) return; - model.selectLang(v); - }, - ) + if (v == null) return; + model.selectLang(v); + }, + ), ], ), ), const SizedBox(width: 12), Button( - onPressed: model.doRefresh(), - child: const Padding( - padding: EdgeInsets.all(6), - child: Icon(FluentIcons.refresh), - )), + onPressed: model.doRefresh(), + child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.refresh)), + ), ], ); } @@ -400,85 +368,77 @@ class LocalizationDialogUI extends HookConsumerWidget { Widget makeToolsListContainer(BuildContext context, LocalizationUIModel model, LocalizationUIState state) { final toolsMenu = { "launcher_mod": ( - const Icon(FluentIcons.c_plus_plus, size: 24), - (S.current.home_localization_action_rsi_launcher_localization), - ), - "advanced": ( - const Icon(FluentIcons.queue_advanced, size: 24), - (S.current.home_localization_action_advanced), + const Icon(FluentIcons.c_plus_plus, size: 24), + (S.current.home_localization_action_rsi_launcher_localization), ), + "advanced": (const Icon(FluentIcons.queue_advanced, size: 24), (S.current.home_localization_action_advanced)), "custom_files": ( - const Icon(FluentIcons.custom_activity, size: 24), - (S.current.home_localization_action_install_customize), + const Icon(FluentIcons.custom_activity, size: 24), + (S.current.home_localization_action_install_customize), ), }; final enableTap = state.workingVersion.isEmpty; return makeListContainer( - S.current.home_localization_title_localization_tools, - [ - for (final item in toolsMenu.entries) - Tilt( - disable: !enableTap, - shadowConfig: const ShadowConfig(maxIntensity: .3), - borderRadius: BorderRadius.circular(7), - child: GestureDetector( - onTap: enableTap - ? () async { - switch (item.key) { - case "launcher_mod": - ToolsUIModel.rsiEnhance(context); - break; - case "advanced": - context.push("/index/advanced_localization"); - break; - case "custom_files": - final sb = await showDialog( - context: context, - builder: (BuildContext context) => const LocalizationFromFileDialogUI(), - ); - if (sb is (StringBuffer, bool)) { - if (!context.mounted) return; - await model.installFormString( - sb.$1, - S.current.localization_info_custom_files, - isEnableCommunityInputMethod: sb.$2, - context: context, - ); + S.current.home_localization_title_localization_tools, + [ + for (final item in toolsMenu.entries) + Tilt( + disable: !enableTap, + shadowConfig: const ShadowConfig(maxIntensity: .3), + borderRadius: BorderRadius.circular(7), + child: GestureDetector( + onTap: enableTap + ? () async { + switch (item.key) { + case "launcher_mod": + ToolsUIModel.rsiEnhance(context); + break; + case "advanced": + context.push("/index/advanced_localization"); + break; + case "custom_files": + final sb = await showDialog( + context: context, + builder: (BuildContext context) => const LocalizationFromFileDialogUI(), + ); + if (sb is (StringBuffer, bool)) { + if (!context.mounted) return; + await model.installFormString( + sb.$1, + S.current.localization_info_custom_files, + isEnableCommunityInputMethod: sb.$2, + context: context, + ); + } + break; } - break; - } - } - : null, - child: Container( - decoration: BoxDecoration( - color: FluentTheme - .of(context) - .cardColor, - borderRadius: BorderRadius.circular(7), - ), - padding: const EdgeInsets.all(12), - child: Row( - children: [ - item.value.$1, - const SizedBox(width: 12), - Text(item.value.$2), - const SizedBox(width: 12), - const Spacer(), - Icon( - FluentIcons.chevron_right, - size: 14, - color: Colors.white.withValues(alpha: .6), - ) - ], - ), + } + : null, + child: Container( + decoration: BoxDecoration( + color: FluentTheme.of(context).cardColor, + borderRadius: BorderRadius.circular(7), + ), + padding: const EdgeInsets.all(12), + child: Row( + children: [ + item.value.$1, + const SizedBox(width: 12), + Text(item.value.$2), + const SizedBox(width: 12), + const Spacer(), + Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)), + ], ), ), ), - ], - context, - gridViewMode: true, - gridViewCrossAxisCount: 3); + ), + ], + context, + gridViewMode: true, + gridViewCrossAxisCount: 3, + ); } } diff --git a/lib/ui/home/localization/localization_ui_model.dart b/lib/ui/home/localization/localization_ui_model.dart index 949c9bf..a54f796 100644 --- a/lib/ui/home/localization/localization_ui_model.dart +++ b/lib/ui/home/localization/localization_ui_model.dart @@ -48,13 +48,12 @@ abstract class LocalizationUIState with _$LocalizationUIState { class LocalizationUIModel extends _$LocalizationUIModel { static const languageSupport = {"chinese_(simplified)": NoL10n.langZHS, "chinese_(traditional)": NoL10n.langZHT}; - Directory get _downloadDir => Directory("${appGlobalState.applicationSupportDir}\\Localizations"); + Directory get _downloadDir => Directory("${appGlobalState.applicationSupportDir}\\Localizations".platformPath); Directory getDownloadDir() => _downloadDir; - Directory get _scDataDir => Directory("${ref.read(homeUIModelProvider).scInstalledPath}\\data"); - - File get _cfgFile => File("${_scDataDir.absolute.path}\\system.cfg"); + Directory get _scDataDir => Directory("${ref.read(homeUIModelProvider).scInstalledPath}\\data".platformPath); + File get _cfgFile => File("${_scDataDir.absolute.path}\\system.cfg".platformPath); StreamSubscription? _customizeDirListenSub; @@ -155,7 +154,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { } void checkUserCfg(BuildContext context) async { - final userCfgFile = File("$_scInstallPath\\USER.cfg"); + final userCfgFile = File("$_scInstallPath\\USER.cfg".platformPath); if (await userCfgFile.exists()) { final cfgString = await userCfgFile.readAsString(); if (cfgString.contains("g_language") && !cfgString.contains("g_language=${state.selectedLanguage}")) { @@ -241,7 +240,9 @@ class LocalizationUIModel extends _$LocalizationUIModel { VoidCallback? doDelIniFile() { return () async { - final iniFile = File("${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"); + final iniFile = File( + "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath, + ); if (await iniFile.exists()) await iniFile.delete(); await updateLangCfg(false); await _updateStatus(); @@ -249,7 +250,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { } String getCustomizeFileName(String path) { - return path.split("\\").last; + return path.split("\\".platformPath).last; } Future installFormString( @@ -261,7 +262,9 @@ class LocalizationUIModel extends _$LocalizationUIModel { BuildContext? context, }) async { dPrint("LocalizationUIModel -> installFormString $versionName"); - final iniFile = File("${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"); + final iniFile = File( + "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath, + ); if (versionName.isNotEmpty) { if (!globalIni.toString().endsWith("\n")) { globalIni.write("\n"); @@ -323,7 +326,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { } Future?> getCommunityInputMethodSupportData() async { - final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"; + final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath; final iniFile = File(iniPath); if (!await iniFile.exists()) { return {}; @@ -351,7 +354,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { } Future<(String, String)> getIniContentWithoutCommunityInputMethodSupportData() async { - final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"; + final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath; final iniFile = File(iniPath); if (!await iniFile.exists()) { return ("", ""); @@ -383,7 +386,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { }) async { AnalyticsApi.touch("install_localization"); - final savePath = File("${_downloadDir.absolute.path}\\${value.versionName}.sclang"); + final savePath = File("${_downloadDir.absolute.path}\\${value.versionName}.sclang".platformPath); try { state = state.copyWith(workingVersion: value.versionName!); if (!await savePath.exists()) { @@ -488,7 +491,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { } Future _updateStatus() async { - final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini"; + final iniPath = "${_scDataDir.absolute.path}\\Localization\\${state.selectedLanguage}\\global.ini".platformPath; final patchStatus = MapEntry( await _getLangCfgEnableLang(lang: state.selectedLanguage!), await _getInstalledIniVersion(iniPath), @@ -535,7 +538,7 @@ class LocalizationUIModel extends _$LocalizationUIModel { if (gamePath.isEmpty) { gamePath = _scInstallPath; } - final cfgFile = File("${_scDataDir.absolute.path}\\system.cfg"); + final cfgFile = File("${_scDataDir.absolute.path}\\system.cfg".platformPath); if (!await cfgFile.exists()) return false; final str = (await cfgFile.readAsString()).replaceAll(" ", ""); return str.contains("sys_languages=$lang") && @@ -573,13 +576,13 @@ class LocalizationUIModel extends _$LocalizationUIModel { for (var scInstallPath in homeState.scInstallPaths) { // 读取游戏安装文件夹 - final scDataDir = Directory("$scInstallPath\\data\\Localization"); + final scDataDir = Directory("$scInstallPath\\data\\Localization".platformPath); // 扫描目录确认已安装的语言 final dirList = await scDataDir.list().toList(); for (var element in dirList) { for (var lang in languageSupport.keys) { if (element.path.contains(lang) && await _getLangCfgEnableLang(lang: lang, gamePath: scInstallPath)) { - final installedVersion = await _getInstalledIniVersion("${element.path}\\global.ini"); + final installedVersion = await _getInstalledIniVersion("${element.path}\\global.ini".platformPath); if (installedVersion == S.current.home_action_info_game_built_in || installedVersion == S.current.localization_info_custom_files) { continue; diff --git a/lib/ui/settings/settings_ui_model.dart b/lib/ui/settings/settings_ui_model.dart index 798f90d..df0c1b5 100644 --- a/lib/ui/settings/settings_ui_model.dart +++ b/lib/ui/settings/settings_ui_model.dart @@ -104,11 +104,11 @@ class SettingsUIModel extends _$SettingsUIModel { final fileName = r.files.first.path!.platformPath; dPrint(fileName); final fileNameRegExp = RegExp( - r'^(.*\\StarCitizen\\.*\\)Bin64\\StarCitizen\.exe$'.platformPath, + r'^(.*[/\\]starcitizen[/\\].*[/\\])bin64[/\\]starcitizen\.exe$', caseSensitive: false, ); if (fileNameRegExp.hasMatch(fileName)) { - RegExp pathRegex = RegExp(r'\\[^\\]+\\Bin64\\StarCitizen\.exe$'.platformPath, caseSensitive: false); + RegExp pathRegex = RegExp(r'[/\\][^/\\]+[/\\]bin64[/\\]starcitizen\.exe$', caseSensitive: false); String extractedPath = fileName.replaceFirst(pathRegex, ''); await _saveCustomPath("custom_game_path", extractedPath); if (!context.mounted) return; diff --git a/lib/ui/tools/dialogs/rsi_launcher_enhance_dialog_ui.dart b/lib/ui/tools/dialogs/rsi_launcher_enhance_dialog_ui.dart index 11a800e..ff75f56 100644 --- a/lib/ui/tools/dialogs/rsi_launcher_enhance_dialog_ui.dart +++ b/lib/ui/tools/dialogs/rsi_launcher_enhance_dialog_ui.dart @@ -70,8 +70,11 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { workingText.value = S.current.tools_rsi_launcher_enhance_working_msg1; if ((await SystemHelper.getPID("RSI Launcher")).isNotEmpty) { if (!context.mounted) return; - showToast(context, S.current.tools_action_info_rsi_launcher_running_warning, - constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .35)); + showToast( + context, + S.current.tools_action_info_rsi_launcher_running_warning, + constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .35), + ); workingText.value = ""; return; } @@ -92,16 +95,16 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { return ContentDialog( constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .48), - title: Row(children: [ - IconButton( - icon: const Icon( - FluentIcons.back, - size: 22, - ), - onPressed: workingText.value.isEmpty ? Navigator.of(context).pop : null), - const SizedBox(width: 12), - Text(S.current.tools_rsi_launcher_enhance_title), - ]), + title: Row( + children: [ + IconButton( + icon: const Icon(FluentIcons.back, size: 22), + onPressed: workingText.value.isEmpty ? Navigator.of(context).pop : null, + ), + const SizedBox(width: 12), + Text(S.current.tools_rsi_launcher_enhance_title), + ], + ), content: AnimatedSize( duration: const Duration(milliseconds: 130), child: Column( @@ -112,17 +115,16 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { InfoBar( title: const SizedBox(), content: Text(S.current.home_localization_action_rsi_launcher_no_game_path_msg), - style: InfoBarThemeData(decoration: (severity) { - return BoxDecoration( - color: Colors.orange, - ); - }, iconColor: (severity) { - return Colors.white; - }), - ), - const SizedBox( - height: 12, + style: InfoBarThemeData( + decoration: (severity) { + return BoxDecoration(color: Colors.orange); + }, + iconColor: (severity) { + return Colors.white; + }, + ), ), + const SizedBox(height: 12), ], if (workingText.value.isNotEmpty) ...[ Center( @@ -144,19 +146,17 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { Expanded( child: Text( S.current.tools_rsi_launcher_enhance_msg_version(assarState.value?.version ?? ""), - style: TextStyle( - color: Colors.white.withValues(alpha: .6), - ), + style: TextStyle(color: Colors.white.withValues(alpha: .6)), ), ), Text( - S.current.tools_rsi_launcher_enhance_msg_patch_status((assarState.value?.isPatchInstalled ?? false) - ? S.current.localization_info_installed - : S.current.tools_action_info_not_installed), - style: TextStyle( - color: Colors.white.withValues(alpha: .6), + S.current.tools_rsi_launcher_enhance_msg_patch_status( + (assarState.value?.isPatchInstalled ?? false) + ? S.current.localization_info_installed + : S.current.tools_action_info_not_installed, ), - ) + style: TextStyle(color: Colors.white.withValues(alpha: .6)), + ), ], ), if (assarState.value?.serverData.isEmpty ?? true) ...[ @@ -165,6 +165,84 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { const SizedBox(height: 24), if (assarState.value?.enabledLocalization != null) Container( + padding: const EdgeInsets.all(12), + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + color: FluentTheme.of(context).cardColor, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(S.current.tools_rsi_launcher_enhance_title_localization), + const SizedBox(height: 3), + Text( + S.current.tools_rsi_launcher_enhance_subtitle_localization, + style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .6)), + ), + ], + ), + ), + ComboBox( + items: [ + for (final key in supportLocalizationMap.keys) + ComboBoxItem(value: key, child: Text(supportLocalizationMap[key]!)), + ], + value: assarState.value?.enabledLocalization, + onChanged: (v) { + assarState.value = assarState.value!.copyWith(enabledLocalization: v); + }, + ), + ], + ), + ), + const SizedBox(height: 3), + if (assarState.value?.enableDownloaderBoost != null) ...[ + IconButton( + icon: Padding( + padding: const EdgeInsets.only(top: 3, bottom: 3), + child: Row( + children: [ + Expanded( + child: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(expandEnhance.value ? FluentIcons.chevron_up : FluentIcons.chevron_down), + const SizedBox(width: 12), + Text( + expandEnhance.value + ? S.current.tools_rsi_launcher_enhance_action_fold + : S.current.tools_rsi_launcher_enhance_action_expand, + ), + ], + ), + ), + ), + ], + ), + ), + onPressed: () async { + if (!expandEnhance.value) { + final userOK = await showConfirmDialogs( + context, + S.current.tools_rsi_launcher_enhance_note_title, + Column( + mainAxisSize: MainAxisSize.min, + children: [Text(S.current.tools_rsi_launcher_enhance_note_msg)], + ), + constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55), + ); + if (!userOK) return; + } + expandEnhance.value = !expandEnhance.value; + }, + ), + if (expandEnhance.value) + Container( padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( @@ -174,111 +252,38 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { child: Row( children: [ Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(S.current.tools_rsi_launcher_enhance_title_localization), - const SizedBox(height: 3), - Text( - S.current.tools_rsi_launcher_enhance_subtitle_localization, - style: TextStyle( - fontSize: 13, - color: Colors.white.withValues(alpha: .6), - ), - ), - ], - )), - ComboBox( - items: [ - for (final key in supportLocalizationMap.keys) - ComboBoxItem(value: key, child: Text(supportLocalizationMap[key]!)) - ], - value: assarState.value?.enabledLocalization, - onChanged: (v) { - assarState.value = assarState.value!.copyWith(enabledLocalization: v); - }, - ), - ], - )), - const SizedBox(height: 3), - if (assarState.value?.enableDownloaderBoost != null) ...[ - IconButton( - icon: Padding( - padding: const EdgeInsets.only(top: 3, bottom: 3), - child: Row( - children: [ - Expanded( - child: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(expandEnhance.value ? FluentIcons.chevron_up : FluentIcons.chevron_down), - const SizedBox(width: 12), - Text(expandEnhance.value - ? S.current.tools_rsi_launcher_enhance_action_fold - : S.current.tools_rsi_launcher_enhance_action_expand), - ], - ))), - ], - ), - ), - onPressed: () async { - if (!expandEnhance.value) { - final userOK = await showConfirmDialogs( - context, - S.current.tools_rsi_launcher_enhance_note_title, - Column( - mainAxisSize: MainAxisSize.min, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(S.current.tools_rsi_launcher_enhance_note_msg), + Text(S.current.tools_rsi_launcher_enhance_title_download_booster), + const SizedBox(height: 3), + Text( + S.current.tools_rsi_launcher_enhance_subtitle_download_booster, + style: TextStyle(fontSize: 13, color: Colors.white.withValues(alpha: .6)), + ), ], ), - constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55)); - if (!userOK) return; - } - expandEnhance.value = !expandEnhance.value; - }, - ), - if (expandEnhance.value) - Container( - padding: const EdgeInsets.all(12), - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: FluentTheme.of(context).cardColor, - borderRadius: BorderRadius.circular(12), - ), - child: Row(children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(S.current.tools_rsi_launcher_enhance_title_download_booster), - const SizedBox(height: 3), - Text( - S.current.tools_rsi_launcher_enhance_subtitle_download_booster, - style: TextStyle( - fontSize: 13, - color: Colors.white.withValues(alpha: .6), - ), - ), - ], - )), + ), ToggleSwitch( onChanged: (value) { assarState.value = assarState.value?.copyWith(enableDownloaderBoost: value); }, checked: assarState.value?.enableDownloaderBoost ?? false, - ) - ])), + ), + ], + ), + ), ], const SizedBox(height: 12), Center( - child: FilledButton( - onPressed: doInstall, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), - child: Text(S.current.tools_rsi_launcher_enhance_action_install), - ))), + child: FilledButton( + onPressed: doInstall, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + child: Text(S.current.tools_rsi_launcher_enhance_action_install), + ), + ), + ), ], const SizedBox(height: 16), Text( @@ -300,7 +305,7 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { return null; } dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherPath ==== $lPath"); - final dataPath = "${lPath}resources\\app.asar"; + final dataPath = "${lPath}resources\\app.asar".platformPath; dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherDataPath ==== $dataPath"); try { final data = await asar_api.getRsiLauncherAsarData(asarPath: dataPath); @@ -333,7 +338,10 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { } Future _loadEnhanceData( - BuildContext context, WidgetRef ref, ValueNotifier assarState) async { + BuildContext context, + WidgetRef ref, + ValueNotifier assarState, + ) async { final globalModel = ref.read(appGlobalModelProvider); final enhancePath = "${globalModel.applicationSupportDir}/launcher_enhance_data"; @@ -418,11 +426,13 @@ class RsiLauncherEnhanceDialogUI extends HookConsumerWidget { for (final line in serverScriptLines) { final lineTrim = line.trim(); if (lineTrim.startsWith(SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START)) { - scriptBuffer - .writeln("$SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START\"${assarState.value!.enabledLocalization}\";"); + scriptBuffer.writeln( + "$SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START\"${assarState.value!.enabledLocalization}\";", + ); } else if (lineTrim.startsWith(SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START)) { - scriptBuffer - .writeln("$SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START${assarState.value!.enableDownloaderBoost};"); + scriptBuffer.writeln( + "$SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START${assarState.value!.enableDownloaderBoost};", + ); } else { scriptBuffer.writeln(line); } diff --git a/lib/ui/tools/tools_ui_model.dart b/lib/ui/tools/tools_ui_model.dart index d373909..ce92fd0 100644 --- a/lib/ui/tools/tools_ui_model.dart +++ b/lib/ui/tools/tools_ui_model.dart @@ -72,13 +72,14 @@ class ToolsUIModel extends _$ToolsUIModel { } try { items = [ - ToolsItemData( - "systemnfo", - S.current.tools_action_view_system_info, - S.current.tools_action_info_view_critical_system_info, - const Icon(FluentIcons.system, size: 24), - onTap: () => _showSystemInfo(context), - ), + if (Platform.isWindows) + ToolsItemData( + "systemnfo", + S.current.tools_action_view_system_info, + S.current.tools_action_info_view_critical_system_info, + const Icon(FluentIcons.system, size: 24), + onTap: () => _showSystemInfo(context), + ), ]; // 年度报告入口 logic @@ -108,13 +109,14 @@ class ToolsUIModel extends _$ToolsUIModel { if (!context.mounted) return; items.add(await _addP4kCard(context)); items.addAll([ - ToolsItemData( - "hosts_booster", - S.current.tools_action_hosts_acceleration_experimental, - S.current.tools_action_info_hosts_acceleration_experimental_tip, - const Icon(FluentIcons.virtual_network, size: 24), - onTap: () => _doHostsBooster(context), - ), + if (Platform.isWindows) + ToolsItemData( + "hosts_booster", + S.current.tools_action_hosts_acceleration_experimental, + S.current.tools_action_info_hosts_acceleration_experimental_tip, + const Icon(FluentIcons.virtual_network, size: 24), + onTap: () => _doHostsBooster(context), + ), ToolsItemData( "log_analyze", S.current.log_analyzer_title, @@ -129,20 +131,22 @@ class ToolsUIModel extends _$ToolsUIModel { const Icon(FluentIcons.c_plus_plus, size: 24), onTap: () => rsiEnhance(context), ), - ToolsItemData( - "reinstall_eac", - S.current.tools_action_reinstall_easyanticheat, - S.current.tools_action_info_reinstall_eac, - const Icon(FluentIcons.game, size: 24), - onTap: () => _reinstallEAC(context), - ), - ToolsItemData( - "rsilauncher_admin_mode", - S.current.tools_action_rsi_launcher_admin_mode, - S.current.tools_action_info_run_rsi_as_admin, - const Icon(FluentIcons.admin, size: 24), - onTap: () => _adminRSILauncher(context), - ), + if (Platform.isWindows) + ToolsItemData( + "reinstall_eac", + S.current.tools_action_reinstall_easyanticheat, + S.current.tools_action_info_reinstall_eac, + const Icon(FluentIcons.game, size: 24), + onTap: () => _reinstallEAC(context), + ), + if (Platform.isWindows) + ToolsItemData( + "rsilauncher_admin_mode", + S.current.tools_action_rsi_launcher_admin_mode, + S.current.tools_action_info_run_rsi_as_admin, + const Icon(FluentIcons.admin, size: 24), + onTap: () => _adminRSILauncher(context), + ), ToolsItemData( "unp4kc", S.current.tools_action_unp4k, @@ -169,8 +173,10 @@ class ToolsUIModel extends _$ToolsUIModel { if (!context.mounted) return; items.add(await _addPhotographyCard(context)); state = state.copyWith(items: items); - if (!context.mounted) return; - items.addAll(await _addNvmePatchCard(context)); + if (Platform.isWindows) { + if (!context.mounted) return; + items.addAll(await _addNvmePatchCard(context)); + } state = state.copyWith(items: items, isItemLoading: false); } catch (e) { if (!context.mounted) return; @@ -250,7 +256,10 @@ class ToolsUIModel extends _$ToolsUIModel { Future _addShaderCard(BuildContext context) async { final gameShaderCachePath = await SCLoggerHelper.getShaderCachePath(); final shaderSize = - ((await SystemHelper.getDirLen(gameShaderCachePath ?? "", skipPath: ["$gameShaderCachePath\\Crashes"])) / + ((await SystemHelper.getDirLen( + gameShaderCachePath ?? "", + skipPath: ["$gameShaderCachePath\\Crashes".platformPath], + )) / 1024 / 1024) .toStringAsFixed(4); @@ -300,7 +309,8 @@ class ToolsUIModel extends _$ToolsUIModel { // 使用最新版本 final latestVersion = versions.first; - final settingsPath = "$gameShaderCachePath\\starcitizen_$latestVersion\\GraphicsSettings\\GraphicsSettings.json"; + final settingsPath = + "$gameShaderCachePath\\starcitizen_$latestVersion\\GraphicsSettings\\GraphicsSettings.json".platformPath; final file = File(settingsPath); if (!await file.exists()) return (-1, latestVersion); @@ -627,6 +637,7 @@ class ToolsUIModel extends _$ToolsUIModel { final result = await showDialog( context: context, builder: (dialogContext) => ContentDialog( + constraints: BoxConstraints(maxWidth: 380), title: Text(S.current.tools_shader_clean_dialog_title), content: Column( mainAxisSize: MainAxisSize.min, diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index b99d63d..38f31c6 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -4,10 +4,10 @@ project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. -set(BINARY_NAME "app") +set(BINARY_NAME "starcitizen_doctor") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.app") +set(APPLICATION_ID "com.starcitizen_doctor") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. @@ -53,6 +53,7 @@ add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GDK_PIXBUF REQUIRED IMPORTED_TARGET gdk-pixbuf-2.0) add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") @@ -73,6 +74,7 @@ apply_standard_settings(${BINARY_NAME}) # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GDK_PIXBUF) # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) @@ -143,3 +145,13 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() + +# Install application icons +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/icons/hicolor" + DESTINATION "share/icons" + COMPONENT Runtime) + +# Install desktop file +install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/com.starcitizen_doctor.desktop" + DESTINATION "share/applications" + COMPONENT Runtime) diff --git a/linux/com.starcitizen_doctor.desktop b/linux/com.starcitizen_doctor.desktop new file mode 100644 index 0000000..f9bdfe7 --- /dev/null +++ b/linux/com.starcitizen_doctor.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Application +Name=SC汉化盒子 +Comment=Star Citizen Tool Box for Chinese players +Exec=starcitizen_doctor +Icon=starcitizen_doctor +Categories=Utility;Game; +Terminal=false +StartupNotify=true diff --git a/linux/icons/hicolor/128x128/apps/starcitizen_doctor.png b/linux/icons/hicolor/128x128/apps/starcitizen_doctor.png new file mode 100644 index 0000000000000000000000000000000000000000..ebe102041e1a05f9048e5595576a79d437af2327 GIT binary patch literal 9365 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 P00000NkvXXu0mjf&jEcp literal 0 HcmV?d00001 diff --git a/linux/icons/hicolor/16x16/apps/starcitizen_doctor.png b/linux/icons/hicolor/16x16/apps/starcitizen_doctor.png new file mode 100644 index 0000000000000000000000000000000000000000..2c466709d5d38720f62f981d79a20859acdb4e33 GIT binary patch literal 879 zcmV-#1CacQP)gn-n@Ki65FJ$X&Vg)EhyFsDkzFtrMhyV zAYE8ckm9N?)s2FJ?%cZZgHkLaEvQu&YAUFx;KC18N~N|<(wJXO)4aTw_Zja?K?GM0 z%wlHlopa7T_c8zy>WkTc!2c`;Ch>4%1Ut5Gx5uA6@kitFZbQ@LLiQ&Z{S^#{AuHSo zgkG(pyjX<96@;3bnQd8>Tq^mI$2vN2dT0n==aUBp&tJMf{rM9f-n@?B>L|AD*$c1V z4@qLkq|^BDastdSu>aU`FwXVi%NI6sVq)921w+@A%-k&0$}-k$?t!g%0at|d=+orz9-r>oI8ICZEejM=syEPts>ak3d^!#c!>qo zg*&LGWz@HAnGP*NG3ir-0!_lA0y0+L^~1`|pI&fWpg;?`Tpq)B?;)8=U4j#L z`O-CV$U@1G5b(IMv{)d{5=>o#ZCc<&hpDRS^7(vqyWYKf56&HjR=P5)xe#h;#p-qi zQ(rzqmMED3O|r69t$;_Gno@oHde1(1_+Yo9xcdyR2df%`$mM?_5RM?)*$ICjglswm zuUo<4L%Ybvafq7kXajGHMwbWrk6wA2crm-@NPk};vw+#}Q}B1h(9yXb+~q;7W#_`=nKR*bUTg23M01}C-0f2>B8mqO0DsAFbxyxYqGJi5iZATNv325L3+(X9%bs4 zc=uK?S#~skfdJ;dO(v+fPgq7xDHjVs@(1#BKPaEqi|G_iTPjf^N9pb@M(tlx zmr64{m(PjOu`wDxEB$kR=H}nys%O*x&ak0F%T)eM^lzNDf4}7N89V?0002ovPDHLk FV1jk4n_vI{ literal 0 HcmV?d00001 diff --git a/linux/icons/hicolor/256x256/apps/starcitizen_doctor.png b/linux/icons/hicolor/256x256/apps/starcitizen_doctor.png new file mode 100644 index 0000000000000000000000000000000000000000..ff79955a9c10c643084005621fc85e64c52e5536 GIT binary patch literal 19161 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 z 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 literal 0 HcmV?d00001 diff --git a/linux/icons/hicolor/48x48/apps/starcitizen_doctor.png b/linux/icons/hicolor/48x48/apps/starcitizen_doctor.png new file mode 100644 index 0000000000000000000000000000000000000000..f40a08a31d7c4035a190914c6cfa466b85a76cd7 GIT binary patch literal 3242 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 literal 0 HcmV?d00001 diff --git a/linux/my_application.cc b/linux/my_application.cc index 0b13577..10d77af 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -4,6 +4,7 @@ #ifdef GDK_WINDOWING_X11 #include #endif +#include #include "flutter/generated_plugin_registrant.h" @@ -42,11 +43,11 @@ static void my_application_activate(GApplication* application) { if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "app"); + gtk_header_bar_set_title(header_bar, "SC汉化盒子"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { - gtk_window_set_title(window, "app"); + gtk_window_set_title(window, "SC汉化盒子"); } gtk_window_set_default_size(window, 1280, 720); diff --git a/rust/src/api/asar_api.rs b/rust/src/api/asar_api.rs index 4cad6e7..f0f5ad4 100644 --- a/rust/src/api/asar_api.rs +++ b/rust/src/api/asar_api.rs @@ -71,8 +71,8 @@ pub async fn get_rsi_launcher_asar_data(asar_path: &str) -> anyhow::Result = Vec::new(); asar.files().iter().for_each(|v| { let (path, file) = v; - let path_string = path.clone().into_os_string().into_string().unwrap(); - if path_string.starts_with("app\\static\\js\\main.") && path_string.ends_with(".js") { + let path_string = path.clone().into_os_string().into_string().unwrap().replace("\\", "/"); + if path_string.starts_with("app/static/js/main.") && path_string.ends_with(".js") { main_js_path = path_string; main_js_content = file.data().to_vec(); } diff --git a/rust/src/webview/webview_impl.rs b/rust/src/webview/webview_impl.rs index 525c688..977d503 100644 --- a/rust/src/webview/webview_impl.rs +++ b/rust/src/webview/webview_impl.rs @@ -12,12 +12,16 @@ use tao::dpi::{LogicalPosition, LogicalSize}; use tao::event::{Event, WindowEvent}; use tao::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use tao::platform::run_return::EventLoopExtRunReturn; + use tao::window::{Icon, Window, WindowBuilder}; use wry::{NewWindowResponse, PageLoadEvent, WebView, WebViewBuilder}; #[cfg(target_os = "windows")] use tao::platform::windows::EventLoopBuilderExtWindows; +#[cfg(target_os = "linux")] +use tao::platform::unix::EventLoopBuilderExtUnix; + use crate::api::webview_api::{ WebViewCommand, WebViewConfiguration, WebViewEvent, WebViewNavigationState, }; @@ -263,14 +267,10 @@ fn run_webview_loop( is_closed: Arc, ) { // Create event loop with any_thread support for non-main thread execution - #[cfg(target_os = "windows")] let mut event_loop: EventLoop = EventLoopBuilder::with_user_event() .with_any_thread(true) .build(); - #[cfg(not(target_os = "windows"))] - let mut event_loop: EventLoop = EventLoopBuilder::with_user_event().build(); - let proxy = event_loop.create_proxy(); // Load window icon from embedded ICO file