mirror of
https://ghfast.top/https://github.com/StarCitizenToolBox/app.git
synced 2025-06-28 13:44:45 +08:00
re init
This commit is contained in:
60
lib/ui/tools/downloader/downloader_dialog_ui.dart
Normal file
60
lib/ui/tools/downloader/downloader_dialog_ui.dart
Normal file
@ -0,0 +1,60 @@
|
||||
import 'package:file_sizes/file_sizes.dart';
|
||||
import 'package:starcitizen_doctor/base/ui.dart';
|
||||
|
||||
import 'downloader_dialog_ui_model.dart';
|
||||
|
||||
class DownloaderDialogUI extends BaseUI<DownloaderDialogUIModel> {
|
||||
@override
|
||||
Widget? buildBody(BuildContext context, DownloaderDialogUIModel model) {
|
||||
return ContentDialog(
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .54),
|
||||
title: const Text("文件下载..."),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text("文件名:${model.fileName}"),
|
||||
const SizedBox(height: 6),
|
||||
Text("保存位置:${model.savePath}"),
|
||||
const SizedBox(height: 6),
|
||||
Text("线程数:${model.threadCount}"),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
"文件大小: ${FileSize.getSize(model.count ?? 0)} / ${FileSize.getSize(model.total ?? 0)}"),
|
||||
const SizedBox(height: 6),
|
||||
Text("下载速度: ${FileSize.getSize(model.speed?.toInt() ?? 0)}/s"),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Text(getStatus(model)),
|
||||
const SizedBox(width: 24),
|
||||
Expanded(
|
||||
child: ProgressBar(
|
||||
value: model.progress == 100 ? null : model.progress,
|
||||
)),
|
||||
const SizedBox(width: 24),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
FilledButton(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
|
||||
child: Text("取消下载"),
|
||||
),
|
||||
onPressed: () => model.doCancel()),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String getUITitle(BuildContext context, DownloaderDialogUIModel model) => "";
|
||||
|
||||
String getStatus(DownloaderDialogUIModel model) {
|
||||
if (model.progress == null && !model.isInMerging) return "准备中...";
|
||||
if (model.isInMerging) return "正在合并文件...";
|
||||
return "${model.progress?.toStringAsFixed(2) ?? "0"}% ";
|
||||
}
|
||||
}
|
100
lib/ui/tools/downloader/downloader_dialog_ui_model.dart
Normal file
100
lib/ui/tools/downloader/downloader_dialog_ui_model.dart
Normal file
@ -0,0 +1,100 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:hyper_thread_downloader/hyper_thread_downloader.dart';
|
||||
import 'package:starcitizen_doctor/base/ui_model.dart';
|
||||
|
||||
class DownloaderDialogUIModel extends BaseUIModel {
|
||||
final String fileName;
|
||||
String savePath;
|
||||
final String downloadUrl;
|
||||
final bool showChangeSavePathDialog;
|
||||
final int threadCount;
|
||||
|
||||
DownloaderDialogUIModel(this.fileName, this.savePath, this.downloadUrl,
|
||||
{this.showChangeSavePathDialog = false, this.threadCount = 1});
|
||||
|
||||
final downloader = HyperDownload();
|
||||
|
||||
int? downloadTaskId;
|
||||
|
||||
bool isInMerging = false;
|
||||
|
||||
double? progress;
|
||||
double? speed;
|
||||
double? remainTime;
|
||||
int? count;
|
||||
int? total;
|
||||
|
||||
@override
|
||||
void initModel() {
|
||||
super.initModel();
|
||||
_initDownload();
|
||||
}
|
||||
|
||||
_initDownload() async {
|
||||
if (showChangeSavePathDialog) {
|
||||
final userSelect = await FilePicker.platform.saveFile(
|
||||
initialDirectory: savePath,
|
||||
fileName: fileName,
|
||||
lockParentWindow: true);
|
||||
if (userSelect == null) {
|
||||
Navigator.pop(context!);
|
||||
return;
|
||||
}
|
||||
final f = File(userSelect);
|
||||
if (await f.exists()) {
|
||||
await f.delete();
|
||||
}
|
||||
savePath = userSelect;
|
||||
dPrint(savePath);
|
||||
notifyListeners();
|
||||
} else {
|
||||
savePath = "$savePath/$fileName";
|
||||
}
|
||||
// start download
|
||||
downloader.startDownload(
|
||||
url: downloadUrl,
|
||||
savePath: savePath,
|
||||
threadCount: threadCount,
|
||||
prepareWorking: (bool done) {},
|
||||
workingMerge: (bool done) {
|
||||
isInMerging = true;
|
||||
progress = null;
|
||||
notifyListeners();
|
||||
},
|
||||
downloadProgress: ({
|
||||
required double progress,
|
||||
required double speed,
|
||||
required double remainTime,
|
||||
required int count,
|
||||
required int total,
|
||||
}) {
|
||||
this.progress = ((progress) * 100);
|
||||
this.speed = speed;
|
||||
this.remainTime = remainTime;
|
||||
this.count = count;
|
||||
this.total = total;
|
||||
notifyListeners();
|
||||
},
|
||||
downloadComplete: () {
|
||||
notifyListeners();
|
||||
Navigator.pop(context!, savePath);
|
||||
},
|
||||
downloadFailed: (String reason) {
|
||||
notifyListeners();
|
||||
showToast(context!, "下载失败! $reason");
|
||||
},
|
||||
downloadTaskId: (int id) {
|
||||
downloadTaskId = id;
|
||||
},
|
||||
downloadingLog: (String log) {});
|
||||
}
|
||||
|
||||
doCancel() {
|
||||
if (downloadTaskId != null) {
|
||||
downloader.stopDownload(id: downloadTaskId!);
|
||||
}
|
||||
Navigator.pop(context!, "cancel");
|
||||
}
|
||||
}
|
235
lib/ui/tools/tools_ui.dart
Normal file
235
lib/ui/tools/tools_ui.dart
Normal file
@ -0,0 +1,235 @@
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'package:starcitizen_doctor/base/ui.dart';
|
||||
|
||||
import 'tools_ui_model.dart';
|
||||
|
||||
class ToolsUI extends BaseUI<ToolsUIModel> {
|
||||
@override
|
||||
Widget? buildBody(BuildContext context, ToolsUIModel model) {
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 22, right: 22),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
makeGameLauncherPathSelect(context, model),
|
||||
const SizedBox(height: 12),
|
||||
makeGamePathSelect(context, model),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Button(
|
||||
onPressed: model.working ? null : model.loadData,
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 32, bottom: 32, left: 12, right: 12),
|
||||
child: Icon(FluentIcons.refresh),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (model.items.isEmpty)
|
||||
const Expanded(
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ProgressRing(),
|
||||
SizedBox(height: 12),
|
||||
Text("正在扫描..."),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: AlignedGridView.count(
|
||||
crossAxisCount: 3,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 12,
|
||||
itemCount: model.items.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) {
|
||||
final item = model.items[index];
|
||||
return Container(
|
||||
width: 300,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: FluentTheme.of(context).cardColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(.2),
|
||||
borderRadius:
|
||||
BorderRadius.circular(1000)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: item.icon,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.name,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
)),
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.infoString,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white.withOpacity(.6)),
|
||||
)),
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(),
|
||||
Button(
|
||||
onPressed: model.working
|
||||
? null
|
||||
: item.onTap == null
|
||||
? null
|
||||
: () {
|
||||
try {
|
||||
item.onTap?.call();
|
||||
} catch (e) {
|
||||
showToast(
|
||||
context, "处理失败!:$e");
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(6),
|
||||
child: Icon(FluentIcons.play),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
if (model.working)
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withAlpha(150),
|
||||
),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ProgressRing(),
|
||||
SizedBox(height: 12),
|
||||
Text("正在处理..."),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeGamePathSelect(BuildContext context, ToolsUIModel model) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("游戏安装位置: "),
|
||||
const SizedBox(width: 6),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 36,
|
||||
child: ComboBox<String>(
|
||||
value: model.scInstalledPath,
|
||||
items: [
|
||||
for (final path in model.scInstallPaths)
|
||||
ComboBoxItem(
|
||||
value: path,
|
||||
child: Text(path),
|
||||
)
|
||||
],
|
||||
onChanged: (v) {
|
||||
model.loadData(skipPathScan: true);
|
||||
model.scInstalledPath = v!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Button(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(FluentIcons.folder_open),
|
||||
),
|
||||
onPressed: () => model.openDir(model.scInstalledPath))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget makeGameLauncherPathSelect(BuildContext context, ToolsUIModel model) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text("RSI启动器位置:"),
|
||||
const SizedBox(width: 6),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 36,
|
||||
child: ComboBox<String>(
|
||||
value: model.rsiLauncherInstalledPath,
|
||||
items: [
|
||||
for (final path in model.rsiLauncherInstallPaths)
|
||||
ComboBoxItem(
|
||||
value: path,
|
||||
child: Text(path),
|
||||
)
|
||||
],
|
||||
onChanged: (v) {
|
||||
model.loadData(skipPathScan: true);
|
||||
model.rsiLauncherInstalledPath = v!;
|
||||
model.notifyListeners();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Button(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Icon(FluentIcons.folder_open),
|
||||
),
|
||||
onPressed: () => model.openDir(model.rsiLauncherInstalledPath))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String getUITitle(BuildContext context, ToolsUIModel model) => "ToolsUI";
|
||||
}
|
334
lib/ui/tools/tools_ui_model.dart
Normal file
334
lib/ui/tools/tools_ui_model.dart
Normal file
@ -0,0 +1,334 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:starcitizen_doctor/base/ui_model.dart';
|
||||
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
|
||||
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
||||
import 'package:starcitizen_doctor/ui/tools/downloader/downloader_dialog_ui_model.dart';
|
||||
|
||||
import 'downloader/downloader_dialog_ui.dart';
|
||||
|
||||
class ToolsUIModel extends BaseUIModel {
|
||||
bool _working = false;
|
||||
|
||||
String scInstalledPath = "";
|
||||
String rsiLauncherInstalledPath = "";
|
||||
|
||||
List<String> scInstallPaths = [];
|
||||
List<String> rsiLauncherInstallPaths = [];
|
||||
|
||||
set working(bool b) {
|
||||
_working = b;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool get working => _working;
|
||||
|
||||
var items = <_ToolsItemData>[];
|
||||
|
||||
@override
|
||||
Future loadData({bool skipPathScan = false}) async {
|
||||
items.clear();
|
||||
notifyListeners();
|
||||
|
||||
if (!skipPathScan) {
|
||||
await reScanPath();
|
||||
}
|
||||
try {
|
||||
final nvmePatchStatus = await SystemHelper.checkNvmePatchStatus();
|
||||
|
||||
final gameShaderCachePath = await SCLoggerHelper.getShaderCachePath();
|
||||
|
||||
double logPathLen = 0;
|
||||
try {
|
||||
logPathLen =
|
||||
(await File(await SCLoggerHelper.getLogFilePath() ?? "").length()) /
|
||||
1024 /
|
||||
1024;
|
||||
} catch (_) {}
|
||||
|
||||
items = [
|
||||
_ToolsItemData(
|
||||
"systeminfo",
|
||||
"查看系统信息",
|
||||
"查看系统关键信息,用于快速问诊 \n\n耗时操作,请耐心等待。",
|
||||
const Icon(FluentIcons.system, size: 28),
|
||||
onTap: _showSystemInfo,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"p4k_downloader",
|
||||
"P4K 分流下载",
|
||||
"使用星际公民中文百科提供的分流下载服务。 \n\n资源有限,请勿滥用。请确保您的硬盘拥有至少大于 200G 的可用空间。",
|
||||
const Icon(FontAwesomeIcons.download, size: 28),
|
||||
onTap: _downloadP4k,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"reinstall_eac",
|
||||
"重装 EasyAntiCheat 反作弊",
|
||||
"若您遇到 EAC 错误,且自动修复无效,请尝试使用此功能重装 EAC。",
|
||||
const Icon(FluentIcons.game, size: 28),
|
||||
onTap: _reinstallEAC,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"rsilauncher_admin_mode",
|
||||
"RSI Launcher 管理员模式",
|
||||
"在某些情况下 RSI启动器 无法正确获得管理员权限,您可尝试使用该功能以管理员模式运行启动器。",
|
||||
const Icon(FluentIcons.admin, size: 28),
|
||||
onTap: _adminRSILauncher,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"clean_shaders",
|
||||
"清理着色器缓存",
|
||||
"若游戏画面出现异常或版本更新后可使用本工具清理过期的着色器(当大于500M时,建议清理) \n\n缓存大小:${((await SystemHelper.getDirLen(gameShaderCachePath ?? "", skipPath: [
|
||||
"$gameShaderCachePath\\Crashes"
|
||||
])) / 1024 / 1024).toStringAsFixed(4)} MB",
|
||||
const Icon(FontAwesomeIcons.shapes, size: 28),
|
||||
onTap: _cleanShaderCache,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"rsilauncher_log_fix",
|
||||
"RSI Launcher Log 修复",
|
||||
"在某些情况下 RSI启动器 的 log 文件会损坏,导致无法完成问题扫描,使用此工具清理损坏的 log 文件。\n\n当前日志文件大小:${(logPathLen.toStringAsFixed(4))} MB",
|
||||
const Icon(FontAwesomeIcons.bookBible, size: 28),
|
||||
onTap: _rsiLogFix,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"rsilauncher_log_select",
|
||||
"RSI Launcher Log 查看",
|
||||
"打开 RSI启动器 Log文件 所在文件夹",
|
||||
const Icon(FontAwesomeIcons.bookBible, size: 28),
|
||||
onTap: _selectLog,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"remove_nvme_settings",
|
||||
"移除 nvme 注册表补丁",
|
||||
"若您使用 nvme 补丁出现问题,请运行此工具。(可能导致游戏 安装/更新 不可用。)\n\n当前补丁状态:${(nvmePatchStatus) ? "已安装" : "未安装"}",
|
||||
const Icon(FluentIcons.hard_drive, size: 28),
|
||||
onTap: nvmePatchStatus
|
||||
? () async {
|
||||
working = true;
|
||||
await SystemHelper.doRemoveNvmePath();
|
||||
working = false;
|
||||
showToast(context!, "已移除,重启生效!");
|
||||
loadData(skipPathScan: true);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
_ToolsItemData(
|
||||
"add_nvme_settings",
|
||||
"写入 nvme 注册表补丁",
|
||||
"手动写入NVM补丁,该功能仅在您知道自己在作什么的情况下使用",
|
||||
const Icon(FontAwesomeIcons.cashRegister, size: 28),
|
||||
onTap: () async {
|
||||
working = true;
|
||||
final r = await SystemHelper.addNvmePatch();
|
||||
if (r == "") {
|
||||
showToast(context!,
|
||||
"修复成功,请尝试重启后继续安装游戏! 若注册表修改操作导致其他软件出现兼容问题,请使用 工具 中的 NVME 注册表清理。");
|
||||
notifyListeners();
|
||||
} else {
|
||||
showToast(context!, "修复失败,$r");
|
||||
}
|
||||
working = false;
|
||||
loadData(skipPathScan: true);
|
||||
},
|
||||
),
|
||||
];
|
||||
} catch (e) {
|
||||
showToast(context!, "初始化失败,请截图报告给开发者。$e");
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> reScanPath() async {
|
||||
scInstallPaths.clear();
|
||||
rsiLauncherInstallPaths.clear();
|
||||
scInstalledPath = "";
|
||||
rsiLauncherInstalledPath = "";
|
||||
try {
|
||||
rsiLauncherInstalledPath = await SystemHelper.getRSILauncherPath();
|
||||
rsiLauncherInstallPaths.add(rsiLauncherInstalledPath);
|
||||
final listData = await SCLoggerHelper.getLauncherLogList();
|
||||
if (listData == null) {
|
||||
return;
|
||||
}
|
||||
scInstallPaths = await SCLoggerHelper.getGameInstallPath(listData,
|
||||
checkExists: false, withVersion: ["LIVE", "PTU", "EPTU"]);
|
||||
if (scInstallPaths.isNotEmpty) {
|
||||
scInstalledPath = scInstallPaths.first;
|
||||
}
|
||||
} catch (e) {
|
||||
showToast(context!, "解析 log 文件失败!\n请尝试使用 RSI Launcher log 修复 工具!");
|
||||
}
|
||||
notifyListeners();
|
||||
|
||||
if (rsiLauncherInstalledPath == "") {
|
||||
showToast(context!,
|
||||
"未找到 RSI 启动器,请尝试重新安装。 \n\n下载链接:https://robertsspaceindustries.com/download");
|
||||
}
|
||||
if (scInstalledPath == "") {
|
||||
showToast(context!, "未找到星际公民游戏安装位置,请至少完成一次游戏启动操作。");
|
||||
}
|
||||
}
|
||||
|
||||
/// 重装EAC
|
||||
Future<void> _reinstallEAC() async {
|
||||
if (scInstalledPath.isEmpty) {
|
||||
showToast(context!, "该功能需要一个有效的游戏安装目录");
|
||||
return;
|
||||
}
|
||||
working = true;
|
||||
try {
|
||||
final eacPath = "$scInstalledPath\\EasyAntiCheat";
|
||||
final eacJsonPath = "$eacPath\\Settings.json";
|
||||
if (await File(eacJsonPath).exists()) {
|
||||
Map<String, String> envVars = Platform.environment;
|
||||
final eacJsonData = await File(eacJsonPath).readAsString();
|
||||
final Map eacJson = json.decode(eacJsonData);
|
||||
final eacID = eacJson["productid"];
|
||||
if (eacID != null) {
|
||||
final eacCacheDir =
|
||||
Directory("${envVars["appdata"]}\\EasyAntiCheat\\$eacID");
|
||||
if (await eacCacheDir.exists()) {
|
||||
await eacCacheDir.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
final dir = Directory(eacPath);
|
||||
if (await dir.exists()) {
|
||||
await dir.delete(recursive: true);
|
||||
}
|
||||
final eacLauncher = File("$scInstalledPath\\StarCitizen_Launcher.exe");
|
||||
if (await eacLauncher.exists()) {
|
||||
await eacLauncher.delete(recursive: true);
|
||||
}
|
||||
showToast(context!,
|
||||
"已为您移除 EAC 文件,接下来将为您打开 RSI 启动器,请您前往 SETTINGS -> VERIFY 重装 EAC。");
|
||||
_adminRSILauncher();
|
||||
} catch (e) {
|
||||
showToast(context!, "出现错误:$e");
|
||||
}
|
||||
working = false;
|
||||
loadData(skipPathScan: true);
|
||||
}
|
||||
|
||||
Future<String> getSystemInfo() async {
|
||||
return "系统:${await SystemHelper.getSystemName()}\n\n"
|
||||
"处理器:${await SystemHelper.getSystemCimInstance("Win32_Processor")}\n\n"
|
||||
"内存大小:${await SystemHelper.getSystemMemorySizeGB()}GB\n\n"
|
||||
"显卡信息:\n${await SystemHelper.getGpuInfo()}\n\n"
|
||||
"硬盘信息:\n${await SystemHelper.getDiskInfo()}\n\n";
|
||||
}
|
||||
|
||||
/// 管理员模式运行 RSI 启动器
|
||||
Future _adminRSILauncher() async {
|
||||
if (rsiLauncherInstalledPath == "") {
|
||||
showToast(context!, "未找到 RSI 启动器目录,请您尝试手动操作。");
|
||||
}
|
||||
handleError(
|
||||
() => SystemHelper.checkAndLaunchRSILauncher(rsiLauncherInstalledPath));
|
||||
}
|
||||
|
||||
Future<void> _rsiLogFix() async {
|
||||
working = true;
|
||||
final path = await SCLoggerHelper.getLogFilePath();
|
||||
if (!await File(path!).exists()) {
|
||||
showToast(
|
||||
context!, "日志文件不存在,请尝试进行一次游戏启动或游戏安装,并退出启动器,若无法解决问题,请尝试将启动器更新至最新版本!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SystemHelper.killRSILauncher();
|
||||
await File(path).delete(recursive: true);
|
||||
showToast(context!, "清理完毕,请完成一次安装 / 游戏启动 操作。");
|
||||
SystemHelper.checkAndLaunchRSILauncher(rsiLauncherInstalledPath);
|
||||
} catch (_) {
|
||||
showToast(context!, "清理失败,请手动移除,文件位置:$path");
|
||||
}
|
||||
working = false;
|
||||
}
|
||||
|
||||
Future<void> _selectLog() async {
|
||||
final path = await SCLoggerHelper.getLogFilePath();
|
||||
if (path == null) return;
|
||||
openDir(path);
|
||||
}
|
||||
|
||||
openDir(path) async {
|
||||
await Process.run("powershell.exe", ["explorer.exe", "/select,\"$path\""]);
|
||||
}
|
||||
|
||||
Future _showSystemInfo() async {
|
||||
working = true;
|
||||
final systemInfo = await getSystemInfo();
|
||||
showDialog<String>(
|
||||
context: context!,
|
||||
builder: (context) => ContentDialog(
|
||||
title: const Text('系统信息'),
|
||||
content: Text(systemInfo),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.of(context).size.width * .65,
|
||||
),
|
||||
actions: [
|
||||
FilledButton(
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.only(top: 2, bottom: 2, left: 8, right: 8),
|
||||
child: Text('关闭'),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
working = false;
|
||||
}
|
||||
|
||||
Future<void> _cleanShaderCache() async {
|
||||
working = true;
|
||||
final gameShaderCachePath = await SCLoggerHelper.getShaderCachePath();
|
||||
final l =
|
||||
await Directory(gameShaderCachePath!).list(recursive: false).toList();
|
||||
for (var value in l) {
|
||||
if (value is Directory) {
|
||||
if (!value.absolute.path.contains("Crashes")) {
|
||||
await value.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
loadData(skipPathScan: true);
|
||||
working = false;
|
||||
}
|
||||
|
||||
Future<void> _downloadP4k() async {
|
||||
const downloadUrl = "https://r2test.citizenwiki.cn/Data.p4k";
|
||||
final r = await showDialog(
|
||||
context: context!,
|
||||
dismissWithEsc: false,
|
||||
builder: (context) {
|
||||
return BaseUIContainer(
|
||||
uiCreate: () => DownloaderDialogUI(),
|
||||
modelCreate: () => DownloaderDialogUIModel(
|
||||
"Data.p4k", scInstalledPath, downloadUrl,
|
||||
showChangeSavePathDialog: true, threadCount: 10));
|
||||
});
|
||||
if (r != null) {
|
||||
if (r == "cancel") {
|
||||
return showToast(context!, "下载已取消,下载进度已保留,如果您无需恢复下载,请手动删除下载临时文件。");
|
||||
}
|
||||
showToast(context!, "下载完毕,文件已保存到:$r");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _ToolsItemData {
|
||||
String key;
|
||||
|
||||
_ToolsItemData(this.key, this.name, this.infoString, this.icon, {this.onTap});
|
||||
|
||||
String name;
|
||||
String infoString;
|
||||
Widget icon;
|
||||
AsyncCallback? onTap;
|
||||
}
|
Reference in New Issue
Block a user