feat: linux support

This commit is contained in:
xkeyC 2025-12-23 22:40:05 +08:00
parent 66ead87d47
commit bba2dbd360
20 changed files with 514 additions and 472 deletions

View File

@ -8,7 +8,15 @@ import 'package:starcitizen_doctor/common/utils/log.dart';
class SCLoggerHelper {
static Future<String?> 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<String, String> envVars = Platform.environment;
final appDataPath = envVars["appdata"];
if (appDataPath == null) {
@ -21,6 +29,14 @@ class SCLoggerHelper {
}
static Future<String?> 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<String, String> envVars = Platform.environment;
final appDataPath = envVars["LOCALAPPDATA"];
if (appDataPath == null) {
@ -31,6 +47,23 @@ class SCLoggerHelper {
return scCachePath;
}
static Future<String?> 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<List?> getLauncherLogList() async {
if (!Platform.isWindows) return [];
try {

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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<String, ScLocalizationData> item,
LocalizationUIState state, int index) {
Widget makeRemoteList(
BuildContext context,
LocalizationUIModel model,
MapEntry<String, ScLocalizationData> 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<Widget> children, BuildContext context,
{List<Widget> actions = const [], bool gridViewMode = false, int gridViewCrossAxisCount = 2}) {
Widget makeListContainer(
String title,
List<Widget> children,
BuildContext context, {
List<Widget> 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<String>(
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,
);
}
}

View File

@ -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<void> 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<Map<String, String>?> 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<void> _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;

View File

@ -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;

View File

@ -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<String> _loadEnhanceData(
BuildContext context, WidgetRef ref, ValueNotifier<RSILauncherStateData?> assarState) async {
BuildContext context,
WidgetRef ref,
ValueNotifier<RSILauncherStateData?> 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);
}

View File

@ -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<ToolsItemData> _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<String>(
context: context,
builder: (dialogContext) => ContentDialog(
constraints: BoxConstraints(maxWidth: 380),
title: Text(S.current.tools_shader_clean_dialog_title),
content: Column(
mainAxisSize: MainAxisSize.min,

View File

@ -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)

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -4,6 +4,7 @@
#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#endif
#include <glib.h>
#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);

View File

@ -71,8 +71,8 @@ pub async fn get_rsi_launcher_asar_data(asar_path: &str) -> anyhow::Result<RsiLa
let mut main_js_content: Vec<u8> = 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();
}

View File

@ -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<AtomicBool>,
) {
// Create event loop with any_thread support for non-main thread execution
#[cfg(target_os = "windows")]
let mut event_loop: EventLoop<UserEvent> = EventLoopBuilder::with_user_event()
.with_any_thread(true)
.build();
#[cfg(not(target_os = "windows"))]
let mut event_loop: EventLoop<UserEvent> = EventLoopBuilder::with_user_event().build();
let proxy = event_loop.create_proxy();
// Load window icon from embedded ICO file