2024-03-10 20:34:38 +08:00
|
|
|
// ignore_for_file: avoid_build_context_in_providers, avoid_public_notifier_properties
|
2024-03-10 16:56:32 +08:00
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
import 'package:fluent_ui/fluent_ui.dart';
|
|
|
|
import 'package:flutter/services.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/common/helper/log_helper.dart';
|
|
|
|
import 'package:starcitizen_doctor/common/utils/base_utils.dart';
|
|
|
|
import 'package:starcitizen_doctor/data/game_performance_data.dart';
|
2024-03-15 00:01:06 +08:00
|
|
|
import 'package:starcitizen_doctor/generated/l10n.dart';
|
2024-03-10 16:56:32 +08:00
|
|
|
import 'package:starcitizen_doctor/ui/home/home_ui_model.dart';
|
|
|
|
|
|
|
|
part 'performance_ui_model.freezed.dart';
|
|
|
|
|
|
|
|
part 'performance_ui_model.g.dart';
|
|
|
|
|
|
|
|
@freezed
|
|
|
|
class HomePerformanceUIState with _$HomePerformanceUIState {
|
2024-03-15 00:01:06 +08:00
|
|
|
factory HomePerformanceUIState({
|
2024-03-10 16:56:32 +08:00
|
|
|
@Default(true) bool showGraphicsPerformanceTip,
|
|
|
|
@Default(false) bool enabled,
|
|
|
|
Map<String, List<GamePerformanceData>>? performanceMap,
|
|
|
|
@Default("") String workingString,
|
|
|
|
}) = _HomePerformanceUIState;
|
|
|
|
}
|
|
|
|
|
|
|
|
@riverpod
|
|
|
|
class HomePerformanceUIModel extends _$HomePerformanceUIModel {
|
|
|
|
String get scPath => ref.read(homeUIModelProvider).scInstalledPath!;
|
|
|
|
|
|
|
|
final customizeCtrl = TextEditingController(text: "");
|
|
|
|
|
|
|
|
final List<String> _inAppKeys = [];
|
|
|
|
|
|
|
|
late final confFile = File("$scPath\\USER.cfg");
|
|
|
|
|
|
|
|
static const _graphicsPerformanceTipVersion = 1;
|
|
|
|
|
|
|
|
@override
|
|
|
|
HomePerformanceUIState build() {
|
2024-03-15 00:01:06 +08:00
|
|
|
state = HomePerformanceUIState();
|
2024-03-10 16:56:32 +08:00
|
|
|
_init();
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _init() async {
|
|
|
|
customizeCtrl.clear();
|
|
|
|
_inAppKeys.clear();
|
|
|
|
final String jsonString =
|
|
|
|
await rootBundle.loadString('assets/performance.json');
|
|
|
|
final list = json.decode(jsonString);
|
|
|
|
|
|
|
|
if (list is List) {
|
|
|
|
final performanceMap = <String, List<GamePerformanceData>>{};
|
|
|
|
for (var element in list) {
|
|
|
|
final item = GamePerformanceData.fromJson(element);
|
|
|
|
if (item.key != "customize") {
|
|
|
|
_inAppKeys.add(item.key ?? "");
|
|
|
|
}
|
|
|
|
performanceMap[item.group!] ??= [];
|
|
|
|
performanceMap[item.group]?.add(item);
|
|
|
|
}
|
|
|
|
state = state.copyWith(performanceMap: performanceMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (await confFile.exists()) {
|
|
|
|
await _readConf();
|
|
|
|
} else {
|
|
|
|
state = state.copyWith(enabled: false);
|
|
|
|
}
|
|
|
|
|
|
|
|
final box = await Hive.openBox("app_conf");
|
|
|
|
final v = box.get("close_graphics_performance_tip", defaultValue: -1);
|
|
|
|
state = state.copyWith(
|
|
|
|
showGraphicsPerformanceTip: v != _graphicsPerformanceTipVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
_readConf() async {
|
|
|
|
if (state.performanceMap == null) return;
|
|
|
|
state = state.copyWith(enabled: true);
|
|
|
|
|
|
|
|
final confString = await confFile.readAsString();
|
|
|
|
for (var value in confString.split("\n")) {
|
|
|
|
final kv = value.split("=");
|
|
|
|
for (var m in state.performanceMap!.entries) {
|
|
|
|
for (var value in m.value) {
|
|
|
|
if (value.key == kv[0].trim()) {
|
|
|
|
final v = int.tryParse(kv[1].trim());
|
|
|
|
if (v != null) value.value = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (kv.length == 2 && !_inAppKeys.contains(kv[0].trim())) {
|
|
|
|
customizeCtrl.text =
|
|
|
|
"${customizeCtrl.text}${kv[0].trim()}=${kv[1].trim()}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
closeTip() async {
|
|
|
|
final box = await Hive.openBox("app_conf");
|
|
|
|
await box.put(
|
|
|
|
"close_graphics_performance_tip", _graphicsPerformanceTipVersion);
|
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
onChangePreProfile(String key) {
|
|
|
|
switch (key) {
|
|
|
|
case "low":
|
|
|
|
state.performanceMap?.forEach((key, v) {
|
2024-03-15 00:01:06 +08:00
|
|
|
if (key.contains(S.current.performance_info_graphics)) {
|
2024-03-10 16:56:32 +08:00
|
|
|
for (var element in v) {
|
|
|
|
element.value = element.min;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "medium":
|
|
|
|
state.performanceMap?.forEach((key, v) {
|
2024-03-15 00:01:06 +08:00
|
|
|
if (key.contains(S.current.performance_info_graphics)) {
|
2024-03-10 16:56:32 +08:00
|
|
|
for (var element in v) {
|
|
|
|
element.value = ((element.max ?? 0) ~/ 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "high":
|
|
|
|
state.performanceMap?.forEach((key, v) {
|
2024-03-15 00:01:06 +08:00
|
|
|
if (key.contains(S.current.performance_info_graphics)) {
|
2024-03-10 16:56:32 +08:00
|
|
|
for (var element in v) {
|
|
|
|
element.value = ((element.max ?? 0) / 1.5).ceil();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "ultra":
|
|
|
|
state.performanceMap?.forEach((key, v) {
|
2024-03-15 00:01:06 +08:00
|
|
|
if (key.contains(S.current.performance_info_graphics)) {
|
2024-03-10 16:56:32 +08:00
|
|
|
for (var element in v) {
|
|
|
|
element.value = element.max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
state = state.copyWith();
|
|
|
|
}
|
|
|
|
|
|
|
|
refresh() async {
|
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
clean(BuildContext context) async {
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_info_delete_config_file);
|
2024-03-10 16:56:32 +08:00
|
|
|
if (await confFile.exists()) {
|
|
|
|
await confFile.delete(recursive: true);
|
|
|
|
}
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_action_clear_shaders);
|
2024-03-10 16:56:32 +08:00
|
|
|
if (!context.mounted) return;
|
|
|
|
await cleanShaderCache(context);
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_info_done);
|
2024-03-10 16:56:32 +08:00
|
|
|
await await Future.delayed(const Duration(milliseconds: 300));
|
|
|
|
await _init();
|
|
|
|
state = state.copyWith(workingString: "");
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanShaderCache(BuildContext? context) async {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
await Future.delayed(const Duration(milliseconds: 300));
|
|
|
|
if (context != null && context.mounted) {
|
2024-03-15 00:01:06 +08:00
|
|
|
showToast(context, S.current.performance_info_shader_clearing_warning);
|
2024-03-10 16:56:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
applyProfile(bool cleanShader) async {
|
|
|
|
if (state.performanceMap == null) return;
|
|
|
|
AnalyticsApi.touch("performance_apply");
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_info_generate_config_file);
|
2024-03-10 16:56:32 +08:00
|
|
|
String conf = "";
|
|
|
|
for (var v in state.performanceMap!.entries) {
|
|
|
|
for (var c in v.value) {
|
|
|
|
if (c.key != "customize") {
|
|
|
|
conf = "$conf${c.key}=${c.value}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (customizeCtrl.text.trim().isNotEmpty) {
|
|
|
|
final lines = customizeCtrl.text.split("\n");
|
|
|
|
for (var value in lines) {
|
|
|
|
final sp = value.split("=");
|
|
|
|
// 忽略无效的配置文件
|
|
|
|
if (sp.length == 2) {
|
|
|
|
conf = "$conf${sp[0].trim()}=${sp[1].trim()}\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_info_write_out_config_file);
|
2024-03-10 16:56:32 +08:00
|
|
|
if (await confFile.exists()) {
|
|
|
|
await confFile.delete();
|
|
|
|
}
|
|
|
|
await confFile.create();
|
|
|
|
await confFile.writeAsString(conf);
|
|
|
|
if (cleanShader) {
|
2024-03-15 00:01:06 +08:00
|
|
|
state = state.copyWith(workingString: S.current.performance_action_clear_shaders);
|
2024-03-10 16:56:32 +08:00
|
|
|
await cleanShaderCache(null);
|
|
|
|
}
|
2024-03-16 17:26:46 +08:00
|
|
|
state = state.copyWith(workingString: "");
|
2024-03-10 16:56:32 +08:00
|
|
|
await await Future.delayed(const Duration(milliseconds: 300));
|
|
|
|
await _init();
|
2024-03-16 17:26:46 +08:00
|
|
|
state = state.copyWith(workingString: "");
|
2024-03-10 16:56:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
updateState() {
|
|
|
|
state = state.copyWith();
|
|
|
|
}
|
2024-03-15 00:01:06 +08:00
|
|
|
}
|