mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-02-04 22:31:12 +00:00
feat: update
This commit is contained in:
parent
6d2bb89c64
commit
79cc157e04
@ -16,9 +16,6 @@ import 'package:starcitizen_doctor/ui/guide/guide_ui.dart';
|
|||||||
import 'package:starcitizen_doctor/ui/home/performance/performance_ui.dart';
|
import 'package:starcitizen_doctor/ui/home/performance/performance_ui.dart';
|
||||||
import 'package:starcitizen_doctor/ui/splash_ui.dart';
|
import 'package:starcitizen_doctor/ui/splash_ui.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
import 'api/analytics.dart';
|
|
||||||
import 'api/api.dart';
|
import 'api/api.dart';
|
||||||
import 'common/conf/url_conf.dart';
|
import 'common/conf/url_conf.dart';
|
||||||
import 'common/helper/system_helper.dart';
|
import 'common/helper/system_helper.dart';
|
||||||
|
|||||||
@ -1883,7 +1883,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
),
|
),
|
||||||
"yearly_report_play_time_value": m89,
|
"yearly_report_play_time_value": m89,
|
||||||
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
||||||
"Presented by SCToolbox",
|
"Presented by SCToolbox | github.com/StarCitizenToolBox/app",
|
||||||
),
|
),
|
||||||
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage(
|
||||||
"Average",
|
"Average",
|
||||||
|
|||||||
@ -1693,7 +1693,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("時間"),
|
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("時間"),
|
||||||
"yearly_report_play_time_value": m89,
|
"yearly_report_play_time_value": m89,
|
||||||
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
||||||
"SCToolbox 提供",
|
"SCToolbox 提供 | github.com/StarCitizenToolBox/app",
|
||||||
),
|
),
|
||||||
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
||||||
"yearly_report_session_date": m90,
|
"yearly_report_session_date": m90,
|
||||||
|
|||||||
@ -1897,7 +1897,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
),
|
),
|
||||||
"yearly_report_play_time_value": m89,
|
"yearly_report_play_time_value": m89,
|
||||||
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
||||||
"Представлено SCToolbox",
|
"Представлено SCToolbox | github.com/StarCitizenToolBox/app",
|
||||||
),
|
),
|
||||||
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage(
|
||||||
"Среднее",
|
"Среднее",
|
||||||
|
|||||||
@ -1621,7 +1621,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("小时"),
|
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("小时"),
|
||||||
"yearly_report_play_time_value": m89,
|
"yearly_report_play_time_value": m89,
|
||||||
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
||||||
"由 SC 汉化盒子为您呈现",
|
"由 SC 汉化盒子为您呈现 | github.com/StarCitizenToolBox/app",
|
||||||
),
|
),
|
||||||
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
||||||
"yearly_report_session_date": m90,
|
"yearly_report_session_date": m90,
|
||||||
|
|||||||
@ -1624,7 +1624,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("小時"),
|
"yearly_report_play_time_unit": MessageLookupByLibrary.simpleMessage("小時"),
|
||||||
"yearly_report_play_time_value": m89,
|
"yearly_report_play_time_value": m89,
|
||||||
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
"yearly_report_powered_by": MessageLookupByLibrary.simpleMessage(
|
||||||
"由 SC工具箱為您呈現",
|
"由 SC工具箱為您呈現 | github.com/StarCitizenToolBox/app",
|
||||||
),
|
),
|
||||||
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
"yearly_report_session_average": MessageLookupByLibrary.simpleMessage("平均"),
|
||||||
"yearly_report_session_date": m90,
|
"yearly_report_session_date": m90,
|
||||||
|
|||||||
@ -6812,10 +6812,10 @@ class S {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `Presented by SCToolbox`
|
/// `Presented by SCToolbox | github.com/StarCitizenToolBox/app`
|
||||||
String get yearly_report_powered_by {
|
String get yearly_report_powered_by {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
'Presented by SCToolbox',
|
'Presented by SCToolbox | github.com/StarCitizenToolBox/app',
|
||||||
name: 'yearly_report_powered_by',
|
name: 'yearly_report_powered_by',
|
||||||
desc: '',
|
desc: '',
|
||||||
args: [],
|
args: [],
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:starcitizen_doctor/app.dart';
|
import 'package:starcitizen_doctor/app.dart';
|
||||||
|
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
import 'package:web/web.dart' as web;
|
import 'package:web/web.dart' as web;
|
||||||
|
|
||||||
@ -65,6 +66,12 @@ class YearlyReportEntryUIRoute extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final globalState = ref.watch(appGlobalModelProvider);
|
final globalState = ref.watch(appGlobalModelProvider);
|
||||||
|
|
||||||
|
// 确保 initApp 被调用,以启动背景图片循环
|
||||||
|
useEffect(() {
|
||||||
|
ref.read(appGlobalModelProvider.notifier).initApp();
|
||||||
|
return null;
|
||||||
|
}, const []);
|
||||||
|
|
||||||
// 使用类似 index_ui.dart 的背景图片布局
|
// 使用类似 index_ui.dart 的背景图片布局
|
||||||
return Container(
|
return Container(
|
||||||
color: const Color(0xFF0a0a12), // 深色背景色作为底色
|
color: const Color(0xFF0a0a12), // 深色背景色作为底色
|
||||||
@ -94,25 +101,16 @@ class YearlyReportEntryUIRoute extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 半透明遮罩,增加可读性
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: [Colors.black.withValues(alpha: .6), Colors.black.withValues(alpha: .75)],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 内容区域
|
// 内容区域
|
||||||
Center(
|
Center(
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxWidth: 1440, maxHeight: 920),
|
constraints: const BoxConstraints(maxWidth: 1440, maxHeight: 920),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
child: BlurOvalWidget(child: const YearlyReportEntryUI()),
|
child: BlurOvalWidget(
|
||||||
|
blurColor: Colors.black.withValues(alpha: .65),
|
||||||
|
child: const YearlyReportEntryUI(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -304,27 +302,31 @@ class YearlyReportEntryUI extends HookConsumerWidget {
|
|||||||
loadingProgress.value = 0;
|
loadingProgress.value = 0;
|
||||||
errorMessage.value = null;
|
errorMessage.value = null;
|
||||||
|
|
||||||
|
dPrint('[YearlyReport] Starting to read log files from directory...');
|
||||||
final contents = await _readLogFilesFromDirectory(loadingMessage, loadingProgress);
|
final contents = await _readLogFilesFromDirectory(loadingMessage, loadingProgress);
|
||||||
|
|
||||||
if (contents.isEmpty) {
|
if (contents.isEmpty) {
|
||||||
|
dPrint('[YearlyReport] No log files found');
|
||||||
errorMessage.value = S.current.yearly_report_web_no_logs_found;
|
errorMessage.value = S.current.yearly_report_web_no_logs_found;
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dPrint('[YearlyReport] Successfully read ${contents.length} log files');
|
||||||
logContents.value = contents;
|
logContents.value = contents;
|
||||||
} catch (e) {
|
} catch (e, stackTrace) {
|
||||||
errorMessage.value = e.toString();
|
dPrint('[YearlyReport] Error reading directory: $e');
|
||||||
|
dPrint('[YearlyReport] Stack trace: $stackTrace');
|
||||||
|
errorMessage.value = 'Error: $e\n\nStack trace:\n$stackTrace';
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isDirectoryPickerSupported() {
|
bool _isDirectoryPickerSupported() {
|
||||||
try {
|
// 在 WASM/Web 环境中,直接返回 true,让实际调用时的错误处理来处理不支持的情况
|
||||||
return true;
|
// 因为 js_interop 的 @JS 注解不能在类方法内部使用
|
||||||
} catch (_) {
|
dPrint('[YearlyReport] Assuming showDirectoryPicker API is available (will handle error if not)');
|
||||||
return false;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> _readLogFilesFromDirectory(
|
Future<List<String>> _readLogFilesFromDirectory(
|
||||||
@ -334,18 +336,26 @@ class YearlyReportEntryUI extends HookConsumerWidget {
|
|||||||
final logContents = <String>[];
|
final logContents = <String>[];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
dPrint('[YearlyReport] Calling showDirectoryPicker...');
|
||||||
final dirHandle = await _showDirectoryPickerWrapper();
|
final dirHandle = await _showDirectoryPickerWrapper();
|
||||||
if (dirHandle == null) return [];
|
if (dirHandle == null) {
|
||||||
|
dPrint('[YearlyReport] User cancelled directory picker');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
dPrint('[YearlyReport] Got directory handle');
|
||||||
|
|
||||||
final dirHandleJS = FileSystemDirectoryHandleJS(dirHandle);
|
final dirHandleJS = FileSystemDirectoryHandleJS(dirHandle);
|
||||||
|
|
||||||
// 尝试获取 LIVE 目录
|
// 尝试获取 LIVE 目录
|
||||||
FileSystemDirectoryHandleJS? liveHandle;
|
FileSystemDirectoryHandleJS? liveHandle;
|
||||||
try {
|
try {
|
||||||
|
dPrint('[YearlyReport] Trying to get LIVE directory...');
|
||||||
final livePromise = dirHandleJS.getDirectoryHandle('LIVE'.toJS);
|
final livePromise = dirHandleJS.getDirectoryHandle('LIVE'.toJS);
|
||||||
final liveResult = await livePromise.toDart;
|
final liveResult = await livePromise.toDart;
|
||||||
liveHandle = FileSystemDirectoryHandleJS(liveResult);
|
liveHandle = FileSystemDirectoryHandleJS(liveResult);
|
||||||
} catch (_) {
|
dPrint('[YearlyReport] Found LIVE directory');
|
||||||
|
} catch (e) {
|
||||||
|
dPrint('[YearlyReport] LIVE directory not found, using selected directory: $e');
|
||||||
liveHandle = dirHandleJS;
|
liveHandle = dirHandleJS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,18 +364,29 @@ class YearlyReportEntryUI extends HookConsumerWidget {
|
|||||||
|
|
||||||
// 读取 Game.log
|
// 读取 Game.log
|
||||||
try {
|
try {
|
||||||
|
dPrint('[YearlyReport] Trying to get Game.log...');
|
||||||
final gameLogPromise = liveHandle.getFileHandle('Game.log'.toJS);
|
final gameLogPromise = liveHandle.getFileHandle('Game.log'.toJS);
|
||||||
final gameLogResult = await gameLogPromise.toDart;
|
final gameLogResult = await gameLogPromise.toDart;
|
||||||
filesToRead.add(FileSystemFileHandleJS(gameLogResult));
|
filesToRead.add(FileSystemFileHandleJS(gameLogResult));
|
||||||
} catch (_) {}
|
dPrint('[YearlyReport] Found Game.log');
|
||||||
|
} catch (e) {
|
||||||
|
dPrint('[YearlyReport] Game.log not found: $e');
|
||||||
|
}
|
||||||
|
|
||||||
// 收集 logbackups 目录中的文件
|
// 收集 logbackups 目录中的文件
|
||||||
try {
|
try {
|
||||||
|
dPrint('[YearlyReport] Trying to get logbackups directory...');
|
||||||
final logbackupsPromise = liveHandle.getDirectoryHandle('logbackups'.toJS);
|
final logbackupsPromise = liveHandle.getDirectoryHandle('logbackups'.toJS);
|
||||||
final logbackupsResult = await logbackupsPromise.toDart;
|
final logbackupsResult = await logbackupsPromise.toDart;
|
||||||
final logbackupsHandle = FileSystemDirectoryHandleJS(logbackupsResult);
|
final logbackupsHandle = FileSystemDirectoryHandleJS(logbackupsResult);
|
||||||
|
dPrint('[YearlyReport] Found logbackups directory');
|
||||||
await _collectLogbackupsFiles(logbackupsHandle, filesToRead);
|
await _collectLogbackupsFiles(logbackupsHandle, filesToRead);
|
||||||
} catch (_) {}
|
dPrint('[YearlyReport] Collected ${filesToRead.length} files from logbackups');
|
||||||
|
} catch (e) {
|
||||||
|
dPrint('[YearlyReport] logbackups directory not found: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
dPrint('[YearlyReport] Total files to read: ${filesToRead.length}');
|
||||||
|
|
||||||
// 依次读取文件,更新进度
|
// 依次读取文件,更新进度
|
||||||
for (var i = 0; i < filesToRead.length; i++) {
|
for (var i = 0; i < filesToRead.length; i++) {
|
||||||
@ -380,12 +401,18 @@ class YearlyReportEntryUI extends HookConsumerWidget {
|
|||||||
final content = await _readFileContent(fileHandle);
|
final content = await _readFileContent(fileHandle);
|
||||||
if (content.isNotEmpty) {
|
if (content.isNotEmpty) {
|
||||||
logContents.add(content);
|
logContents.add(content);
|
||||||
|
dPrint('[YearlyReport] Read file: $fileName (${content.length} chars)');
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (e) {
|
||||||
|
dPrint('[YearlyReport] Error reading file $fileName: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingProgress.value = 1.0;
|
loadingProgress.value = 1.0;
|
||||||
} catch (e) {
|
dPrint('[YearlyReport] Finished reading files, total: ${logContents.length}');
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
dPrint('[YearlyReport] Error in _readLogFilesFromDirectory: $e');
|
||||||
|
dPrint('[YearlyReport] Stack trace: $stackTrace');
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,18 +443,30 @@ class YearlyReportEntryUI extends HookConsumerWidget {
|
|||||||
filesToRead.add(handleJS);
|
filesToRead.add(handleJS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
dPrint('[YearlyReport] Error collecting logbackups files: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<JSObject?> _showDirectoryPickerWrapper() async {
|
Future<JSObject?> _showDirectoryPickerWrapper() async {
|
||||||
try {
|
try {
|
||||||
|
dPrint('[YearlyReport] Calling _showDirectoryPicker JS function...');
|
||||||
final promise = _showDirectoryPicker();
|
final promise = _showDirectoryPicker();
|
||||||
|
dPrint('[YearlyReport] Got promise, awaiting result...');
|
||||||
final result = await promise.toDart;
|
final result = await promise.toDart;
|
||||||
|
dPrint('[YearlyReport] Got result from showDirectoryPicker');
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e, stackTrace) {
|
||||||
|
dPrint('[YearlyReport] Error in _showDirectoryPickerWrapper: $e');
|
||||||
|
dPrint('[YearlyReport] Stack trace: $stackTrace');
|
||||||
if (e.toString().contains('AbortError')) {
|
if (e.toString().contains('AbortError')) {
|
||||||
|
dPrint('[YearlyReport] User aborted the picker');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// 检查是否是 API 不支持的错误
|
||||||
|
if (e.toString().contains('TypeError') || e.toString().contains('undefined')) {
|
||||||
|
throw Exception('${S.current.yearly_report_web_browser_not_supported}\n\nTechnical details: $e');
|
||||||
|
}
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1243,6 +1243,26 @@ class _SummaryPage extends StatelessWidget {
|
|||||||
style: TextStyle(fontSize: 16, color: Colors.white.withValues(alpha: .6)),
|
style: TextStyle(fontSize: 16, color: Colors.white.withValues(alpha: .6)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
FadeInUp(
|
||||||
|
delay: const Duration(milliseconds: 900),
|
||||||
|
child: Button(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrlString("https://github.com/StarCitizenToolBox/app");
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Icon(FontAwesomeIcons.github),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(S.current.support_dev_github_star_button),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:starcitizen_doctor/common/helper/yearly_report_analyzer.dart';
|
import 'package:starcitizen_doctor/common/helper/yearly_report_analyzer.dart';
|
||||||
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
import 'package:starcitizen_doctor/widgets/widgets.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
part 'yearly_report_pages.dart';
|
part 'yearly_report_pages.dart';
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user