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 0000000..ebe1020 Binary files /dev/null and b/linux/icons/hicolor/128x128/apps/starcitizen_doctor.png differ 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 0000000..2c46670 Binary files /dev/null and b/linux/icons/hicolor/16x16/apps/starcitizen_doctor.png differ 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 0000000..ff79955 Binary files /dev/null and b/linux/icons/hicolor/256x256/apps/starcitizen_doctor.png differ diff --git a/linux/icons/hicolor/32x32/apps/starcitizen_doctor.png b/linux/icons/hicolor/32x32/apps/starcitizen_doctor.png new file mode 100644 index 0000000..139ad45 Binary files /dev/null and b/linux/icons/hicolor/32x32/apps/starcitizen_doctor.png differ 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 0000000..f40a08a Binary files /dev/null and b/linux/icons/hicolor/48x48/apps/starcitizen_doctor.png differ diff --git a/linux/icons/hicolor/64x64/apps/starcitizen_doctor.png b/linux/icons/hicolor/64x64/apps/starcitizen_doctor.png new file mode 100644 index 0000000..3ddde63 Binary files /dev/null and b/linux/icons/hicolor/64x64/apps/starcitizen_doctor.png differ 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