feat: Migrate more PowerShell calls to Rust implementation

This commit is contained in:
xkeyC
2025-12-05 11:06:54 +08:00
parent f6676ed3d8
commit 62b8718dbd
16 changed files with 1377 additions and 357 deletions

View File

@@ -9,6 +9,7 @@ import 'package:hive_ce/hive.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/rust/api/win32_api.dart' as win32;
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
@@ -50,14 +51,15 @@ class SettingsUIModel extends _$SettingsUIModel {
Future<void> setGameLaunchECore(BuildContext context) async {
final userBox = await Hive.openBox("app_conf");
final defaultInput =
userBox.get("gameLaunch_eCore_count", defaultValue: "0");
final defaultInput = userBox.get("gameLaunch_eCore_count", defaultValue: "0");
if (!context.mounted) return;
final input = await showInputDialogs(context,
title: S.current.setting_action_info_enter_cpu_core_to_ignore,
content: S.current.setting_action_info_cpu_core_tip,
initialValue: defaultInput,
inputFormatters: [FilteringTextInputFormatter.digitsOnly]);
final input = await showInputDialogs(
context,
title: S.current.setting_action_info_enter_cpu_core_to_ignore,
content: S.current.setting_action_info_cpu_core_tip,
initialValue: defaultInput,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
);
if (input == null) return;
userBox.put("gameLaunch_eCore_count", input);
_initState();
@@ -65,8 +67,7 @@ class SettingsUIModel extends _$SettingsUIModel {
Future _updateGameLaunchECore() async {
final userBox = await Hive.openBox("app_conf");
final inputGameLaunchECore =
userBox.get("gameLaunch_eCore_count", defaultValue: "0");
final inputGameLaunchECore = userBox.get("gameLaunch_eCore_count", defaultValue: "0");
state = state.copyWith(inputGameLaunchECore: inputGameLaunchECore);
}
@@ -102,9 +103,7 @@ class SettingsUIModel extends _$SettingsUIModel {
if (r == null || r.files.firstOrNull?.path == null) return;
final fileName = r.files.first.path!;
dPrint(fileName);
final fileNameRegExp = RegExp(
r"^(.*\\StarCitizen\\.*\\)Bin64\\StarCitizen\.exe$",
caseSensitive: false);
final fileNameRegExp = RegExp(r"^(.*\\StarCitizen\\.*\\)Bin64\\StarCitizen\.exe$", caseSensitive: false);
if (fileNameRegExp.hasMatch(fileName)) {
RegExp pathRegex = RegExp(r"\\[^\\]+\\Bin64\\StarCitizen\.exe$");
String extractedPath = fileName.replaceFirst(pathRegex, '');
@@ -127,8 +126,7 @@ class SettingsUIModel extends _$SettingsUIModel {
final confBox = await Hive.openBox("app_conf");
final customLauncherPath = confBox.get("custom_launcher_path");
final customGamePath = confBox.get("custom_game_path");
state = state.copyWith(
customLauncherPath: customLauncherPath, customGamePath: customGamePath);
state = state.copyWith(customLauncherPath: customLauncherPath, customGamePath: customGamePath);
}
Future<void> delName(String key) async {
@@ -138,24 +136,21 @@ class SettingsUIModel extends _$SettingsUIModel {
}
Future _loadLocationCacheSize() async {
final len1 = await SystemHelper.getDirLen(
"${appGlobalState.applicationSupportDir}/Localizations");
final len2 = await SystemHelper.getDirLen(
"${appGlobalState.applicationSupportDir}/launcher_enhance_data");
final len1 = await SystemHelper.getDirLen("${appGlobalState.applicationSupportDir}/Localizations");
final len2 = await SystemHelper.getDirLen("${appGlobalState.applicationSupportDir}/launcher_enhance_data");
final locationCacheSize = len1 + len2;
state = state.copyWith(locationCacheSize: locationCacheSize);
}
Future<void> cleanLocationCache(BuildContext context) async {
final ok = await showConfirmDialogs(
context,
S.current.setting_action_info_confirm_clear_cache,
Text(S.current.setting_action_info_clear_cache_warning));
context,
S.current.setting_action_info_confirm_clear_cache,
Text(S.current.setting_action_info_clear_cache_warning),
);
if (ok == true) {
final dir1 =
Directory("${appGlobalState.applicationSupportDir}/Localizations");
final dir2 = Directory(
"${appGlobalState.applicationSupportDir}/launcher_enhance_data");
final dir1 = Directory("${appGlobalState.applicationSupportDir}/Localizations");
final dir2 = Directory("${appGlobalState.applicationSupportDir}/launcher_enhance_data");
if (!context.mounted) return;
if (await dir1.exists()) {
if (!context.mounted) return;
@@ -172,36 +167,27 @@ class SettingsUIModel extends _$SettingsUIModel {
Future<void> addShortCut(BuildContext context) async {
if (ConstConf.isMSE) {
showToast(
context, S.current.setting_action_info_microsoft_version_limitation);
showToast(context, S.current.setting_action_info_microsoft_version_limitation);
await Future.delayed(const Duration(seconds: 1));
Process.run("explorer.exe", ["shell:AppsFolder"]);
return;
}
dPrint(Platform.resolvedExecutable);
final shortCuntName = S.current.app_shortcut_name;
final script = """
\$targetPath = "${Platform.resolvedExecutable}";
\$shortcutPath = [System.IO.Path]::Combine([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::DesktopDirectory), "$shortCuntName");
\$shell = New-Object -ComObject WScript.Shell
\$shortcut = \$shell.CreateShortcut(\$shortcutPath)
if (\$shortcut -eq \$null) {
Write-Host "Failed to create shortcut."
} else {
\$shortcut.TargetPath = \$targetPath
\$shortcut.Save()
Write-Host "Shortcut created successfully."
final shortcutName = S.current.app_shortcut_name;
try {
await win32.createDesktopShortcut(targetPath: Platform.resolvedExecutable, shortcutName: shortcutName);
if (!context.mounted) return;
showToast(context, S.current.setting_action_info_shortcut_created);
} catch (e) {
dPrint("createDesktopShortcut error: $e");
if (!context.mounted) return;
showToast(context, "Failed to create shortcut: $e");
}
""";
await Process.run(SystemHelper.powershellPath, [script]);
if (!context.mounted) return;
showToast(context, S.current.setting_action_info_shortcut_created);
}
Future _loadToolSiteMirrorState() async {
final userBox = await Hive.openBox("app_conf");
final isEnableToolSiteMirrors =
userBox.get("isEnableToolSiteMirrors", defaultValue: false);
final isEnableToolSiteMirrors = userBox.get("isEnableToolSiteMirrors", defaultValue: false);
state = state.copyWith(isEnableToolSiteMirrors: isEnableToolSiteMirrors);
}
@@ -213,8 +199,7 @@ class SettingsUIModel extends _$SettingsUIModel {
}
Future<void> showLogs() async {
SystemHelper.openDir(getDPrintFile()?.absolute.path.replaceAll("/", "\\"),
isFile: true);
SystemHelper.openDir(getDPrintFile()?.absolute.path.replaceAll("/", "\\"), isFile: true);
}
void onChangeUseInternalDNS(bool? b) {
@@ -225,8 +210,7 @@ class SettingsUIModel extends _$SettingsUIModel {
Future _loadUseInternalDNS() async {
final userBox = await Hive.openBox("app_conf");
final isUseInternalDNS =
userBox.get("isUseInternalDNS", defaultValue: false);
final isUseInternalDNS = userBox.get("isUseInternalDNS", defaultValue: false);
state = state.copyWith(isUseInternalDNS: isUseInternalDNS);
}
@@ -238,8 +222,7 @@ class SettingsUIModel extends _$SettingsUIModel {
Future _loadOnnxXnnPackState() async {
final userBox = await Hive.openBox("app_conf");
final isEnableOnnxXnnPack =
userBox.get("isEnableOnnxXnnPack", defaultValue: true);
final isEnableOnnxXnnPack = userBox.get("isEnableOnnxXnnPack", defaultValue: true);
state = state.copyWith(isEnableOnnxXnnPack: isEnableOnnxXnnPack);
}
}

View File

@@ -41,7 +41,7 @@ final class SettingsUIModelProvider
}
}
String _$settingsUIModelHash() => r'72947d5ed36290df865cb010b056dc632f5dccec';
String _$settingsUIModelHash() => r'd34b1a2fac69d10f560d9a2e1a7431dd5a7954ca';
abstract class _$SettingsUIModel extends $Notifier<SettingsUIState> {
SettingsUIState build();

View File

@@ -11,6 +11,7 @@ import 'package:starcitizen_doctor/app.dart';
import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/rust/api/win32_api.dart' as win32;
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
import 'package:html/parser.dart' as html_parser;
@@ -44,39 +45,36 @@ class UpgradeDialogUI extends HookConsumerWidget {
return Material(
child: ContentDialog(
title:
Text(S.current.app_upgrade_title_new_version_found(targetVersion)),
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55),
title: Text(S.current.app_upgrade_title_new_version_found(targetVersion)),
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .55),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 24, right: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (description.value == null) ...[
Center(
child: Column(
children: [
const ProgressRing(),
const SizedBox(height: 16),
Text(S.current
.app_upgrade_info_getting_new_version_details)
],
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 24, right: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (description.value == null) ...[
Center(
child: Column(
children: [
const ProgressRing(),
const SizedBox(height: 16),
Text(S.current.app_upgrade_info_getting_new_version_details),
],
),
),
)
] else
...makeMarkdownView(description.value!,
attachmentsUrl: URLConf.giteaAttachmentsUrl),
],
] else
...makeMarkdownView(description.value!, attachmentsUrl: URLConf.giteaAttachmentsUrl),
],
),
),
),
)),
),
if (isUsingDiversion.value) ...[
const SizedBox(height: 24),
GestureDetector(
@@ -84,13 +82,12 @@ class UpgradeDialogUI extends HookConsumerWidget {
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: .1),
borderRadius: BorderRadius.circular(7)),
color: Colors.white.withValues(alpha: .1),
borderRadius: BorderRadius.circular(7),
),
child: Text(
S.current.app_upgrade_info_update_server_tip,
style: TextStyle(
fontSize: 14,
color: Colors.white.withValues(alpha: .7)),
style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: .7)),
),
),
),
@@ -99,14 +96,12 @@ class UpgradeDialogUI extends HookConsumerWidget {
const SizedBox(height: 24),
Row(
children: [
Text(progress.value == 100
? S.current.app_upgrade_info_installing
: S.current.app_upgrade_info_downloading(
progress.value.toStringAsFixed(2))),
Expanded(
child: ProgressBar(
value: progress.value == 100 ? null : progress.value,
)),
Text(
progress.value == 100
? S.current.app_upgrade_info_installing
: S.current.app_upgrade_info_downloading(progress.value.toStringAsFixed(2)),
),
Expanded(child: ProgressBar(value: progress.value == 100 ? null : progress.value)),
],
),
],
@@ -117,38 +112,40 @@ class UpgradeDialogUI extends HookConsumerWidget {
: [
if (downloadUrl.value.isNotEmpty)
FilledButton(
onPressed: () => _doUpgrade(
context,
appState,
isUpgrading,
appModel,
downloadUrl,
description,
isUsingDiversion,
progress),
child: Padding(
padding: const EdgeInsets.only(
top: 4, bottom: 4, left: 8, right: 8),
child: Text(S.current.app_upgrade_action_update_now),
)),
onPressed: () => _doUpgrade(
context,
appState,
isUpgrading,
appModel,
downloadUrl,
description,
isUsingDiversion,
progress,
),
child: Padding(
padding: const EdgeInsets.only(top: 4, bottom: 4, left: 8, right: 8),
child: Text(S.current.app_upgrade_action_update_now),
),
),
if (ConstConf.appVersionCode >= (minVersionCode ?? 0))
Button(
onPressed: () => _doCancel(context),
child: Padding(
padding: const EdgeInsets.only(
top: 4, bottom: 4, left: 8, right: 8),
child: Text(S.current.app_upgrade_action_next_time),
)),
onPressed: () => _doCancel(context),
child: Padding(
padding: const EdgeInsets.only(top: 4, bottom: 4, left: 8, right: 8),
child: Text(S.current.app_upgrade_action_next_time),
),
),
],
),
);
}
Future<void> _getUpdateInfo(
BuildContext context,
String targetVersion,
ValueNotifier<String?> description,
ValueNotifier<String> downloadUrl) async {
BuildContext context,
String targetVersion,
ValueNotifier<String?> description,
ValueNotifier<String> downloadUrl,
) async {
try {
final r = await Api.getAppReleaseDataByVersionName(targetVersion);
description.value = r["body"];
@@ -193,19 +190,19 @@ class UpgradeDialogUI extends HookConsumerWidget {
}
Future<void> _doUpgrade(
BuildContext context,
AppGlobalState appState,
ValueNotifier<bool> isUpgrading,
AppGlobalModel appModel,
ValueNotifier<String> downloadUrl,
ValueNotifier<String?> description,
ValueNotifier<bool> isUsingDiversion,
ValueNotifier<double> progress) async {
BuildContext context,
AppGlobalState appState,
ValueNotifier<bool> isUpgrading,
AppGlobalModel appModel,
ValueNotifier<String> downloadUrl,
ValueNotifier<String?> description,
ValueNotifier<bool> isUsingDiversion,
ValueNotifier<double> progress,
) async {
if (ConstConf.isMSE) {
launchUrlString("ms-windows-store://pdp/?productid=9NF3SWFWNKL1");
await Future.delayed(const Duration(seconds: 3));
if (ConstConf.appVersionCode <
(appState.networkVersionData?.minVersionCode ?? 0)) {
if (ConstConf.appVersionCode < (appState.networkVersionData?.minVersionCode ?? 0)) {
exit(0);
}
if (!context.mounted) return;
@@ -221,10 +218,10 @@ class UpgradeDialogUI extends HookConsumerWidget {
final dio = Dio();
if (diversionDownloadUrl.isNotEmpty) {
try {
final resp = await dio.head(diversionDownloadUrl,
options: Options(
sendTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10)));
final resp = await dio.head(
diversionDownloadUrl,
options: Options(sendTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10)),
);
if (resp.statusCode == 200) {
isUsingDiversion.value = true;
url = diversionDownloadUrl;
@@ -236,10 +233,13 @@ class UpgradeDialogUI extends HookConsumerWidget {
dPrint("diversionDownloadUrl err:$e");
}
}
await dio.download(url, fileName,
onReceiveProgress: (int count, int total) {
progress.value = (count / total) * 100;
});
await dio.download(
url,
fileName,
onReceiveProgress: (int count, int total) {
progress.value = (count / total) * 100;
},
);
} catch (_) {
isUpgrading.value = false;
progress.value = 0;
@@ -249,11 +249,7 @@ class UpgradeDialogUI extends HookConsumerWidget {
}
try {
final r = await (Process.run(
SystemHelper.powershellPath, ["start", fileName, "/SILENT"]));
if (r.stderr.toString().isNotEmpty) {
throw r.stderr;
}
await win32.startProcess(program: fileName, args: ["/SILENT"]);
exit(0);
} catch (_) {
isUpgrading.value = false;