2024-03-09 21:53:37 +08:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:dart_rss/domain/rss_item.dart';
|
2024-03-10 12:07:30 +08:00
|
|
|
|
import 'package:desktop_webview_window/desktop_webview_window.dart';
|
2024-03-09 21:53:37 +08:00
|
|
|
|
import 'package:fluent_ui/fluent_ui.dart';
|
|
|
|
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
|
|
|
import 'package:hive/hive.dart';
|
|
|
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/api/analytics.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/api/api.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/api/rss.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/helper/log_helper.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/io/rs_http.dart';
|
2024-03-10 21:25:03 +08:00
|
|
|
|
import 'package:starcitizen_doctor/common/utils/async.dart';
|
2024-03-09 21:53:37 +08:00
|
|
|
|
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/data/app_placard_data.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart';
|
|
|
|
|
import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart';
|
2024-03-10 13:25:13 +08:00
|
|
|
|
import 'package:starcitizen_doctor/ui/home/dialogs/home_game_login_dialog_ui.dart';
|
2024-03-09 21:53:37 +08:00
|
|
|
|
import 'package:url_launcher/url_launcher_string.dart';
|
|
|
|
|
import 'package:html/parser.dart' as html;
|
|
|
|
|
import 'package:html/dom.dart' as html_dom;
|
2024-03-10 21:25:03 +08:00
|
|
|
|
import 'package:windows_ui/windows_ui.dart';
|
2024-03-09 21:53:37 +08:00
|
|
|
|
|
2024-03-10 12:07:30 +08:00
|
|
|
|
import '../webview/webview.dart';
|
2024-03-10 21:25:03 +08:00
|
|
|
|
import 'localization/localization_ui_model.dart';
|
2024-03-10 12:07:30 +08:00
|
|
|
|
|
2024-03-09 21:53:37 +08:00
|
|
|
|
part 'home_ui_model.freezed.dart';
|
|
|
|
|
|
|
|
|
|
part 'home_ui_model.g.dart';
|
|
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
|
class HomeUIModelState with _$HomeUIModelState {
|
|
|
|
|
factory HomeUIModelState({
|
|
|
|
|
AppPlacardData? appPlacardData,
|
|
|
|
|
@Default(false) bool isFixing,
|
|
|
|
|
@Default("") String isFixingString,
|
|
|
|
|
String? scInstalledPath,
|
|
|
|
|
@Default([]) List<String> scInstallPaths,
|
|
|
|
|
AppWebLocalizationVersionsData? webLocalizationVersionsData,
|
|
|
|
|
@Default("") String lastScreenInfo,
|
|
|
|
|
List<RssItem>? rssVideoItems,
|
|
|
|
|
List<RssItem>? rssTextItems,
|
|
|
|
|
MapEntry<String, bool>? localizationUpdateInfo,
|
|
|
|
|
List? scServerStatus,
|
|
|
|
|
List<CountdownFestivalItemData>? countdownFestivalListData,
|
2024-03-10 13:25:13 +08:00
|
|
|
|
@Default({}) Map<String, bool> isGameRunning,
|
2024-03-09 21:53:37 +08:00
|
|
|
|
}) = _HomeUIModelState;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 13:25:13 +08:00
|
|
|
|
extension HomeUIModelStateEx on HomeUIModelState {
|
|
|
|
|
bool get isCurGameRunning => isGameRunning[scInstalledPath] ?? false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 21:53:37 +08:00
|
|
|
|
@riverpod
|
|
|
|
|
class HomeUIModel extends _$HomeUIModel {
|
|
|
|
|
@override
|
|
|
|
|
HomeUIModelState build() {
|
|
|
|
|
state = HomeUIModelState();
|
|
|
|
|
_init();
|
|
|
|
|
_loadData();
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
closePlacard() async {
|
|
|
|
|
final box = await Hive.openBox("app_conf");
|
|
|
|
|
await box.put("close_placard", state.appPlacardData?.version);
|
|
|
|
|
state = state.copyWith(appPlacardData: null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> reScanPath() async {
|
|
|
|
|
state = state.copyWith(
|
2024-03-15 00:01:06 +08:00
|
|
|
|
scInstalledPath: "not_install",
|
|
|
|
|
lastScreenInfo: S.current.home_action_info_scanning);
|
2024-03-09 21:53:37 +08:00
|
|
|
|
try {
|
|
|
|
|
final listData = await SCLoggerHelper.getLauncherLogList();
|
|
|
|
|
if (listData == null) {
|
|
|
|
|
state = state.copyWith(scInstalledPath: "not_install");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final scInstallPaths = await SCLoggerHelper.getGameInstallPath(listData,
|
|
|
|
|
withVersion: ["LIVE", "PTU", "EPTU"], checkExists: true);
|
|
|
|
|
String? scInstalledPath;
|
|
|
|
|
if (scInstallPaths.isNotEmpty) {
|
|
|
|
|
scInstalledPath = scInstallPaths.first;
|
|
|
|
|
}
|
|
|
|
|
final lastScreenInfo = "扫描完毕,共找到 ${scInstallPaths.length} 个有效安装目录";
|
|
|
|
|
state = state.copyWith(
|
|
|
|
|
scInstalledPath: scInstalledPath,
|
|
|
|
|
scInstallPaths: scInstallPaths,
|
|
|
|
|
lastScreenInfo: lastScreenInfo);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
state = state.copyWith(
|
2024-03-15 00:01:06 +08:00
|
|
|
|
scInstalledPath: "not_install",
|
|
|
|
|
lastScreenInfo: S.current.home_action_info_log_file_parse_fail);
|
2024-03-09 21:53:37 +08:00
|
|
|
|
AnalyticsApi.touch("error_launchLogs");
|
|
|
|
|
// showToast(context!,
|
2024-03-15 00:01:06 +08:00
|
|
|
|
// "${S.current.home_action_info_log_file_parse_fail} \n请关闭游戏,退出RSI启动器后重试,若仍有问题,请使用工具箱中的 RSI Launcher log 修复。");
|
2024-03-09 21:53:37 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getRssImage(RssItem item) {
|
|
|
|
|
final h = html.parse(item.description ?? "");
|
|
|
|
|
if (h.body == null) return "";
|
|
|
|
|
for (var node in h.body!.nodes) {
|
|
|
|
|
if (node is html_dom.Element) {
|
|
|
|
|
if (node.localName == "img") {
|
|
|
|
|
return node.attributes["src"]?.trim() ?? "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String handleTitle(String? title) {
|
|
|
|
|
if (title == null) return "";
|
|
|
|
|
title = title.replaceAll("【", "[ ");
|
|
|
|
|
title = title.replaceAll("】", " ] ");
|
|
|
|
|
return title;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 12:07:30 +08:00
|
|
|
|
// ignore: avoid_build_context_in_providers
|
|
|
|
|
Future<void> goWebView(BuildContext context, String title, String url,
|
|
|
|
|
{bool useLocalization = false,
|
|
|
|
|
bool loginMode = false,
|
|
|
|
|
RsiLoginCallback? rsiLoginCallback}) async {
|
|
|
|
|
if (useLocalization) {
|
|
|
|
|
const tipVersion = 2;
|
|
|
|
|
final box = await Hive.openBox("app_conf");
|
|
|
|
|
final skip =
|
|
|
|
|
await box.get("skip_web_localization_tip_version", defaultValue: 0);
|
|
|
|
|
if (skip != tipVersion) {
|
|
|
|
|
if (!context.mounted) return;
|
|
|
|
|
final ok = await showConfirmDialogs(
|
|
|
|
|
context,
|
2024-03-15 00:01:06 +08:00
|
|
|
|
S.current.home_action_title_star_citizen_website_localization,
|
2024-03-10 12:07:30 +08:00
|
|
|
|
const Text(
|
|
|
|
|
"本插功能件仅供大致浏览使用,不对任何有关本功能产生的问题负责!在涉及账号操作前请注意确认网站的原本内容!"
|
|
|
|
|
"\n\n\n使用此功能登录账号时请确保您的 SC汉化盒子 是从可信任的来源下载。",
|
|
|
|
|
style: TextStyle(fontSize: 16),
|
|
|
|
|
),
|
|
|
|
|
constraints: BoxConstraints(
|
|
|
|
|
maxWidth: MediaQuery.of(context).size.width * .6));
|
|
|
|
|
if (!ok) {
|
|
|
|
|
if (loginMode) {
|
|
|
|
|
rsiLoginCallback?.call(null, false);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await box.put("skip_web_localization_tip_version", tipVersion);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!await WebviewWindow.isWebviewAvailable()) {
|
|
|
|
|
if (!context.mounted) return;
|
2024-03-15 00:01:06 +08:00
|
|
|
|
showToast(context,
|
|
|
|
|
S.current.home_login_action_title_need_webview2_runtime);
|
2024-03-10 12:07:30 +08:00
|
|
|
|
launchUrlString(
|
|
|
|
|
"https://developer.microsoft.com/en-us/microsoft-edge/webview2/");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!context.mounted) return;
|
|
|
|
|
final webViewModel = WebViewModel(context,
|
|
|
|
|
loginMode: loginMode, loginCallback: rsiLoginCallback);
|
|
|
|
|
if (useLocalization) {
|
2024-03-15 00:01:06 +08:00
|
|
|
|
state = state.copyWith(
|
|
|
|
|
isFixing: true,
|
|
|
|
|
isFixingString:
|
|
|
|
|
S.current.home_action_info_initializing_resources);
|
2024-03-10 12:07:30 +08:00
|
|
|
|
try {
|
|
|
|
|
await webViewModel.initLocalization(state.webLocalizationVersionsData!);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (!context.mounted) return;
|
|
|
|
|
showToast(context, "初始化网页汉化资源失败!$e");
|
|
|
|
|
}
|
|
|
|
|
state = state.copyWith(isFixingString: "", isFixing: false);
|
|
|
|
|
}
|
|
|
|
|
await webViewModel.initWebView(
|
|
|
|
|
title: title,
|
|
|
|
|
applicationSupportDir: appGlobalState.applicationSupportDir!,
|
|
|
|
|
appVersionData: appGlobalState.networkVersionData!,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
|
|
|
await webViewModel.launch(url, appGlobalState.networkVersionData!);
|
|
|
|
|
}
|
2024-03-09 21:53:37 +08:00
|
|
|
|
|
|
|
|
|
bool isRSIServerStatusOK(Map map) {
|
|
|
|
|
return (map["status"] == "ok" || map["status"] == "operational");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Timer? _serverUpdateTimer;
|
|
|
|
|
Timer? _appUpdateTimer;
|
|
|
|
|
|
|
|
|
|
void _init() {
|
|
|
|
|
reScanPath();
|
|
|
|
|
_serverUpdateTimer = Timer.periodic(
|
|
|
|
|
const Duration(minutes: 10),
|
|
|
|
|
(timer) {
|
|
|
|
|
_updateSCServerStatus();
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
_appUpdateTimer = Timer.periodic(const Duration(minutes: 30), (timer) {
|
2024-03-10 21:25:03 +08:00
|
|
|
|
checkLocalizationUpdate();
|
2024-03-09 21:53:37 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ref.onDispose(() {
|
|
|
|
|
_serverUpdateTimer?.cancel();
|
|
|
|
|
_serverUpdateTimer = null;
|
|
|
|
|
_appUpdateTimer?.cancel();
|
|
|
|
|
_appUpdateTimer = null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _loadData() async {
|
|
|
|
|
if (appGlobalState.networkVersionData == null) return;
|
|
|
|
|
try {
|
|
|
|
|
final r = await Api.getAppPlacard();
|
|
|
|
|
final box = await Hive.openBox("app_conf");
|
|
|
|
|
final version = box.get("close_placard", defaultValue: "");
|
|
|
|
|
if (r.enable == true) {
|
|
|
|
|
if (r.alwaysShow != true && version == r.version) {
|
|
|
|
|
} else {
|
|
|
|
|
state = state.copyWith(appPlacardData: r);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final appWebLocalizationVersionsData =
|
|
|
|
|
AppWebLocalizationVersionsData.fromJson(json.decode(
|
|
|
|
|
(await RSHttp.getText(
|
|
|
|
|
"${URLConf.webTranslateHomeUrl}/versions.json"))));
|
|
|
|
|
final countdownFestivalListData = await Api.getFestivalCountdownList();
|
|
|
|
|
state = state.copyWith(
|
|
|
|
|
webLocalizationVersionsData: appWebLocalizationVersionsData,
|
|
|
|
|
countdownFestivalListData: countdownFestivalListData);
|
|
|
|
|
_updateSCServerStatus();
|
|
|
|
|
_loadRRS();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
dPrint(e);
|
|
|
|
|
}
|
|
|
|
|
// check Localization update
|
2024-03-10 21:25:03 +08:00
|
|
|
|
checkLocalizationUpdate();
|
2024-03-09 21:53:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _updateSCServerStatus() async {
|
|
|
|
|
try {
|
|
|
|
|
final s = await Api.getScServerStatus();
|
|
|
|
|
dPrint("updateSCServerStatus===$s");
|
|
|
|
|
state = state.copyWith(scServerStatus: s);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
dPrint(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future _loadRRS() async {
|
|
|
|
|
try {
|
2024-03-10 12:54:34 +08:00
|
|
|
|
final rssVideoItems = await RSSApi.getRssVideo();
|
2024-03-10 14:21:36 +08:00
|
|
|
|
state = state.copyWith(rssVideoItems: rssVideoItems);
|
2024-03-10 12:54:34 +08:00
|
|
|
|
final rssTextItems = await RSSApi.getRssText();
|
2024-03-10 14:21:36 +08:00
|
|
|
|
state = state.copyWith(rssTextItems: rssTextItems);
|
2024-03-09 21:53:37 +08:00
|
|
|
|
dPrint("RSS update Success !");
|
|
|
|
|
} catch (e) {
|
|
|
|
|
dPrint("_loadRRS Error:$e");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-10 21:25:03 +08:00
|
|
|
|
Future<void> checkLocalizationUpdate({bool skipReload = false}) async {
|
|
|
|
|
dPrint("_checkLocalizationUpdate");
|
|
|
|
|
final updates = await (ref.read(localizationUIModelProvider.notifier))
|
|
|
|
|
.checkLangUpdate(skipReload: skipReload)
|
|
|
|
|
.unwrap<List<String>>();
|
|
|
|
|
if (updates == null || updates.isEmpty) {
|
|
|
|
|
state = state.copyWith(localizationUpdateInfo: null);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
state =
|
|
|
|
|
state.copyWith(localizationUpdateInfo: MapEntry(updates.first, true));
|
|
|
|
|
if (_appUpdateTimer != null) {
|
|
|
|
|
_appUpdateTimer?.cancel();
|
|
|
|
|
_appUpdateTimer = null;
|
|
|
|
|
// 发送通知
|
2024-03-15 00:01:06 +08:00
|
|
|
|
final toastNotifier = ToastNotificationManager.createToastNotifierWithId(
|
|
|
|
|
S.current.home_title_app_name);
|
2024-03-10 21:25:03 +08:00
|
|
|
|
if (toastNotifier != null) {
|
|
|
|
|
final toastContent = ToastNotificationManager.getTemplateContent(
|
|
|
|
|
ToastTemplateType.toastText02);
|
|
|
|
|
if (toastContent != null) {
|
|
|
|
|
final xmlNodeList = toastContent.getElementsByTagName('text');
|
2024-03-15 00:01:06 +08:00
|
|
|
|
final title = S.current.home_localization_new_version_available;
|
2024-03-10 21:25:03 +08:00
|
|
|
|
final content = '您在 ${updates.first} 安装的汉化有新版本啦!';
|
|
|
|
|
xmlNodeList.item(0)?.appendChild(toastContent.createTextNode(title));
|
|
|
|
|
xmlNodeList
|
|
|
|
|
.item(1)
|
|
|
|
|
?.appendChild(toastContent.createTextNode(content));
|
|
|
|
|
final toastNotification =
|
|
|
|
|
ToastNotification.createToastNotification(toastContent);
|
|
|
|
|
toastNotifier.show(toastNotification);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-09 21:53:37 +08:00
|
|
|
|
|
|
|
|
|
// ignore: avoid_build_context_in_providers
|
|
|
|
|
launchRSI(BuildContext context) async {
|
|
|
|
|
if (state.scInstalledPath == "not_install") {
|
2024-03-15 00:01:06 +08:00
|
|
|
|
showToast(context, S.current.home_info_valid_installation_required);
|
2024-03-09 21:53:37 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ConstConf.isMSE) {
|
|
|
|
|
if (state.isCurGameRunning) {
|
|
|
|
|
await Process.run(
|
|
|
|
|
SystemHelper.powershellPath, ["ps \"StarCitizen\" | kill"]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AnalyticsApi.touch("gameLaunch");
|
2024-03-10 13:25:13 +08:00
|
|
|
|
showDialog(
|
|
|
|
|
context: context,
|
|
|
|
|
dismissWithEsc: false,
|
|
|
|
|
builder: (context) => const HomeGameLoginDialogUI());
|
2024-03-09 21:53:37 +08:00
|
|
|
|
} else {
|
|
|
|
|
final ok = await showConfirmDialogs(
|
|
|
|
|
context,
|
2024-03-15 00:01:06 +08:00
|
|
|
|
S.current.home_info_one_click_launch_warning,
|
2024-03-09 21:53:37 +08:00
|
|
|
|
const Text("为确保账户安全,一键启动功能已在开发版中禁用,我们将在微软商店版本中提供此功能。"
|
|
|
|
|
"\n\n微软商店版由微软提供可靠的分发下载与数字签名,可有效防止软件被恶意篡改。\n\n提示:您无需使用盒子启动游戏也可使用汉化。"),
|
2024-03-15 00:01:06 +08:00
|
|
|
|
confirm: S.current.home_action_install_microsoft_store_version,
|
|
|
|
|
cancel: S.current.home_action_cancel);
|
2024-03-09 21:53:37 +08:00
|
|
|
|
if (ok == true) {
|
|
|
|
|
await launchUrlString(
|
|
|
|
|
"https://apps.microsoft.com/detail/9NF3SWFWNKL1?launch=true");
|
|
|
|
|
await Future.delayed(const Duration(seconds: 2));
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onChangeInstallPath(String? value) {
|
|
|
|
|
if (value == null) return;
|
|
|
|
|
state = state.copyWith(scInstalledPath: value);
|
|
|
|
|
}
|
2024-03-10 13:25:13 +08:00
|
|
|
|
|
|
|
|
|
doLaunchGame(
|
|
|
|
|
// ignore: avoid_build_context_in_providers
|
|
|
|
|
BuildContext context,
|
|
|
|
|
String launchExe,
|
|
|
|
|
List<String> args,
|
|
|
|
|
String installPath,
|
|
|
|
|
String? processorAffinity) async {
|
|
|
|
|
var runningMap = Map<String, bool>.from(state.isGameRunning);
|
|
|
|
|
runningMap[installPath] = true;
|
|
|
|
|
state = state.copyWith(isGameRunning: runningMap);
|
|
|
|
|
try {
|
|
|
|
|
late ProcessResult result;
|
|
|
|
|
if (processorAffinity == null) {
|
|
|
|
|
result = await Process.run(launchExe, args);
|
|
|
|
|
} else {
|
|
|
|
|
dPrint("set Affinity === $processorAffinity launchExe === $launchExe");
|
|
|
|
|
result = await Process.run("cmd.exe", [
|
|
|
|
|
'/C',
|
|
|
|
|
'Start',
|
|
|
|
|
'"StarCitizen"',
|
|
|
|
|
'/High',
|
|
|
|
|
'/Affinity',
|
|
|
|
|
processorAffinity,
|
|
|
|
|
launchExe,
|
|
|
|
|
...args
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
dPrint('Exit code: ${result.exitCode}');
|
|
|
|
|
dPrint('stdout: ${result.stdout}');
|
|
|
|
|
dPrint('stderr: ${result.stderr}');
|
|
|
|
|
|
|
|
|
|
if (result.exitCode != 0) {
|
|
|
|
|
final logs = await SCLoggerHelper.getGameRunningLogs(installPath);
|
|
|
|
|
MapEntry<String, String>? exitInfo;
|
|
|
|
|
bool hasUrl = false;
|
|
|
|
|
if (logs != null) {
|
|
|
|
|
exitInfo = SCLoggerHelper.getGameRunningLogInfo(logs);
|
|
|
|
|
if (exitInfo!.value.startsWith("https://")) {
|
|
|
|
|
hasUrl = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!context.mounted) return;
|
|
|
|
|
showToast(context,
|
|
|
|
|
"游戏非正常退出\nexitCode=${result.exitCode}\nstdout=${result.stdout ?? ""}\nstderr=${result.stderr ?? ""}\n\n诊断信息:${exitInfo == null ? "未知错误,请通过一键诊断加群反馈。" : exitInfo.key} \n${hasUrl ? "请查看弹出的网页链接获得详细信息。" : exitInfo?.value ?? ""}");
|
|
|
|
|
if (hasUrl) {
|
|
|
|
|
await Future.delayed(const Duration(seconds: 3));
|
|
|
|
|
launchUrlString(exitInfo!.value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final launchFile = File("$installPath\\loginData.json");
|
|
|
|
|
if (await launchFile.exists()) {
|
|
|
|
|
await launchFile.delete();
|
|
|
|
|
}
|
|
|
|
|
} catch (_) {}
|
|
|
|
|
runningMap = Map<String, bool>.from(state.isGameRunning);
|
|
|
|
|
runningMap[installPath] = false;
|
|
|
|
|
state = state.copyWith(isGameRunning: runningMap);
|
|
|
|
|
}
|
2024-03-09 21:53:37 +08:00
|
|
|
|
}
|