app/lib/app.dart

280 lines
9.1 KiB
Dart
Raw Normal View History

2024-03-07 23:01:32 +08:00
import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:go_router/go_router.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/common/conf/const_conf.dart';
import 'package:starcitizen_doctor/common/utils/log.dart';
2024-03-10 16:56:32 +08:00
import 'package:starcitizen_doctor/ui/home/performance/performance_ui.dart';
2024-03-07 23:01:32 +08:00
import 'package:starcitizen_doctor/ui/splash_ui.dart';
import 'package:device_info_plus/device_info_plus.dart';
2024-03-09 20:22:44 +08:00
import 'package:starcitizen_doctor/widgets/widgets.dart';
2024-03-07 23:01:32 +08:00
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
import 'api/analytics.dart';
import 'api/api.dart';
import 'common/helper/system_helper.dart';
import 'common/io/rs_http.dart';
import 'common/rust/frb_generated.dart';
import 'data/app_version_data.dart';
2024-03-10 17:23:28 +08:00
import 'ui/home/downloader/home_downloader_ui.dart';
2024-03-10 14:18:30 +08:00
import 'ui/home/game_doctor/game_doctor_ui.dart';
2024-03-09 20:22:44 +08:00
import 'ui/index_ui.dart';
2024-03-07 23:01:32 +08:00
import 'ui/settings/upgrade_dialog.dart';
part 'app.g.dart';
part 'app.freezed.dart';
@riverpod
GoRouter router(RouterRef ref) {
return GoRouter(
routes: [
GoRoute(
path: '/',
2024-03-09 20:22:44 +08:00
pageBuilder: (context, state) =>
myPageBuilder(context, state, const SplashUI()),
),
GoRoute(
path: '/index',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const IndexUI()),
2024-03-10 14:18:30 +08:00
routes: [
2024-03-10 17:23:28 +08:00
GoRoute(
path: "downloader",
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeDownloaderUI())),
2024-03-10 14:18:30 +08:00
GoRoute(
path: 'game_doctor',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomeGameDoctorUI()),
),
2024-03-10 16:56:32 +08:00
GoRoute(
path: 'performance',
pageBuilder: (context, state) =>
myPageBuilder(context, state, const HomePerformanceUI()),
),
2024-03-10 14:18:30 +08:00
],
2024-03-07 23:01:32 +08:00
),
],
);
}
@riverpod
class AppGlobalModel extends _$AppGlobalModel {
@override
AppGlobalState build() {
return const AppGlobalState();
}
bool _initialized = false;
Future<void> initApp() async {
if (_initialized) return;
// init Data
final userProfileDir = Platform.environment["USERPROFILE"];
final applicationSupportDir =
(await getApplicationSupportDirectory()).absolute.path;
String? applicationBinaryModuleDir;
final logFile = File(
"$applicationSupportDir\\logs\\${DateTime.now().millisecondsSinceEpoch}.log");
await logFile.create(recursive: true);
setDPrintFile(logFile);
if (ConstConf.isMSE && userProfileDir != null) {
applicationBinaryModuleDir =
"$userProfileDir\\AppData\\Local\\Temp\\SCToolbox\\modules";
} else {
applicationBinaryModuleDir = "$applicationSupportDir\\modules";
}
dPrint("applicationSupportDir == $applicationSupportDir");
dPrint("applicationBinaryModuleDir == $applicationBinaryModuleDir");
state = state.copyWith(
applicationSupportDir: applicationSupportDir,
applicationBinaryModuleDir: applicationBinaryModuleDir,
);
// init Hive
try {
Hive.init("$applicationSupportDir/db");
final box = await Hive.openBox("app_conf");
if (box.get("install_id", defaultValue: "") == "") {
await box.put("install_id", const Uuid().v4());
AnalyticsApi.touch("firstLaunch");
}
final deviceUUID = box.get("install_id", defaultValue: "");
state = state.copyWith(deviceUUID: deviceUUID);
} catch (e) {
exit(1);
}
// init Rust bridge
await RustLib.init();
await RSHttp.init();
dPrint("---- rust bridge inited -----");
// init powershell
await SystemHelper.initPowershellPath();
// get windows info
WindowsDeviceInfo? windowsDeviceInfo;
try {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
windowsDeviceInfo = await deviceInfo.windowsInfo;
} catch (e) {
dPrint("DeviceInfo.windowsInfo error: $e");
}
// init windows
windowManager.waitUntilReadyToShow().then((_) async {
await windowManager.setSize(const Size(1280, 810));
await windowManager.setMinimumSize(const Size(1280, 810));
await windowManager.setSkipTaskbar(false);
await windowManager.show();
await Window.initialize();
await Window.hideWindowControls();
if (windowsDeviceInfo?.productName.contains("Windows 11") ?? false) {
await Window.setEffect(
effect: WindowEffect.acrylic,
);
}
});
_initialized = true;
ref.keepAlive();
}
String getUpgradePath() {
return "${state.applicationSupportDir}/._upgrade";
}
// ignore: avoid_build_context_in_providers
Future<bool> checkUpdate(BuildContext context) async {
if (!ConstConf.isMSE) {
final dir = Directory(getUpgradePath());
if (await dir.exists()) {
dir.delete(recursive: true);
}
}
dynamic checkUpdateError;
try {
final networkVersionData = await Api.getAppVersion();
checkActivityThemeColor(networkVersionData);
if (ConstConf.isMSE) {
dPrint(
"lastVersion=${networkVersionData.mSELastVersion} ${networkVersionData.mSELastVersionCode}");
} else {
dPrint(
"lastVersion=${networkVersionData.lastVersion} ${networkVersionData.lastVersionCode}");
}
state = state.copyWith(networkVersionData: networkVersionData);
} catch (e) {
checkUpdateError = e;
dPrint("_checkUpdate Error:$e");
}
await Future.delayed(const Duration(milliseconds: 100));
if (state.networkVersionData == null) {
if (!context.mounted) return false;
await showToast(context,
"网络异常!\n这可能是您的网络环境存在DNS污染请尝试更换DNS。\n或服务器正在维护或遭受攻击,稍后再试。 \n进入离线模式... \n\n请谨慎在离线模式中使用。 \n当前版本构建日期:${ConstConf.appVersionDate}\n QQ群940696487 \n错误信息:$checkUpdateError");
return false;
}
final lastVersion = ConstConf.isMSE
? state.networkVersionData?.mSELastVersionCode
: state.networkVersionData?.lastVersionCode;
if ((lastVersion ?? 0) > ConstConf.appVersionCode) {
// need update
if (!context.mounted) return false;
final r = await showDialog(
dismissWithEsc: false,
context: context,
builder: (context) => const UpgradeDialogUI());
if (r != true) {
if (!context.mounted) return false;
2024-03-09 20:22:44 +08:00
await showToast(context, "获取更新信息失败,请稍后重试。");
2024-03-07 23:01:32 +08:00
return false;
}
return true;
}
return false;
}
Timer? _activityThemeColorTimer;
checkActivityThemeColor(AppVersionData networkVersionData) {
if (_activityThemeColorTimer != null) {
_activityThemeColorTimer?.cancel();
_activityThemeColorTimer = null;
}
final startTime = networkVersionData.activityColors?.startTime;
final endTime = networkVersionData.activityColors?.endTime;
if (startTime == null || endTime == null) return;
final now = DateTime.now().millisecondsSinceEpoch;
dPrint("now == $now start == $startTime end == $endTime");
if (now < startTime) {
_activityThemeColorTimer = Timer(Duration(milliseconds: startTime - now),
() => checkActivityThemeColor(networkVersionData));
dPrint("start Timer ....");
} else if (now >= startTime && now <= endTime) {
dPrint("update Color ....");
// update Color
final colorCfg = networkVersionData.activityColors;
state = state.copyWith(
themeConf: ThemeConf(
backgroundColor:
HexColor(colorCfg?.background ?? "#132431").withOpacity(.75),
menuColor: HexColor(colorCfg?.menu ?? "#132431").withOpacity(.95),
micaColor: HexColor(colorCfg?.mica ?? "#0A3142"),
),
);
// wait for end
_activityThemeColorTimer = Timer(Duration(milliseconds: endTime - now),
() => checkActivityThemeColor(networkVersionData));
} else {
dPrint("reset Color ....");
state = state.copyWith(
themeConf: ThemeConf(
backgroundColor: HexColor("#132431").withOpacity(.75),
menuColor: HexColor("#132431").withOpacity(.95),
micaColor: HexColor("#0A3142"),
),
);
}
}
}
@freezed
class AppGlobalState with _$AppGlobalState {
const factory AppGlobalState({
String? deviceUUID,
String? applicationSupportDir,
String? applicationBinaryModuleDir,
AppVersionData? networkVersionData,
@Default(ThemeConf()) ThemeConf themeConf,
}) = _AppGlobalState;
}
@freezed
class ThemeConf with _$ThemeConf {
const factory ThemeConf({
@Default(Color(0xbf132431)) Color backgroundColor,
@Default(Color(0xf2132431)) Color menuColor,
@Default(Color(0xff0a3142)) Color micaColor,
}) = _ThemeConf;
}