@@ -28,7 +28,7 @@ import 'package:system_fonts/system_fonts.dart';
2828import 'package:timezone/data/latest.dart' as tz;
2929
3030void main () {
31- void catchError ([ArcheLogger ? logger]) async {
31+ Future < void > catchError ([ArcheLogger ? logger]) async {
3232 var store =
3333 logger ?? ArcheBus .bus.provideof <ArcheLogger >(instance: ArcheLogger ());
3434
@@ -45,79 +45,92 @@ void main() {
4545
4646 runZonedGuarded (
4747 () async {
48- WidgetsFlutterBinding .ensureInitialized ();
49- // Ensure directory is initialized here for faster load
50- await ensurePlatDirectoryValue ();
51-
52- await initializeRust (assignRustSignal);
5348 final logger = ArcheLogger ();
54- final platUserData = await platUserDataDirectory.getValue ();
55-
56- final configPath = platUserData.subPath ("app.config.json" );
57- final config = ArcheConfig .path (configPath);
58- logger.info ("Application Config Stored in `$configPath `" );
59- if (! kDebugMode) {
60- FlutterError .onError = (err) async {
61- logger.error (err.exception);
62- logger.error (err.stack);
63- catchError (logger);
64- };
65- }
49+ try {
50+ WidgetsFlutterBinding .ensureInitialized ();
51+ // Ensure directory is initialized here for faster load
52+ await ensurePlatDirectoryValue ();
53+
54+ await initializeRust (assignRustSignal);
55+ final platUserData = await platUserDataDirectory.getValue ();
56+
57+ final configPath = platUserData.subPath ("app.config.json" );
58+ final config = ArcheConfig .path (configPath);
59+ logger.info ("Application Config Stored in `$configPath `" );
60+ if (! kDebugMode) {
61+ FlutterError .onError = (err) async {
62+ logger.error (err.exception);
63+ logger.error (err.stack);
64+ catchError (logger);
65+ };
66+ }
6667
67- // Calendar
68- tz.initializeTimeZones ();
69- ICalendar .registerField (
70- field: "WEEK" ,
71- function: (value, params, event, lastEvent) {
72- lastEvent['week' ] = value;
73- return lastEvent;
74- },
75- );
68+ // Calendar
69+ tz.initializeTimeZones ();
70+ ICalendar .registerField (
71+ field: "WEEK" ,
72+ function: (value, params, event, lastEvent) {
73+ lastEvent['week' ] = value;
74+ return lastEvent;
75+ },
76+ );
7677
77- var bus = ArcheBus ();
78- var configs = ApplicationConfigs (config);
79- bus.provide (ArcheLogger ()).provide (config).provide (configs);
80- // Cache Background Image in memory for faster load
81- await calendarBackgroundData.update ();
82- // Parse Data for fast load
83- await icalendarParsersData.update ();
84-
85- // Custom Font
86- var customfont = platUserData.subFile ("customfont" );
87- if (await customfont.exists ()) {
88- final loader = FontLoader ("Custom Font" )
89- ..addFont (
90- Future (() async {
91- var data = await customfont.readAsBytes ();
92-
93- return data.buffer.asByteData ();
94- }),
95- );
96- await loader.load ();
97- configs.sysfont.write ("Custom Font" );
98- } else {
99- // Load SystemFont
100- if (Platform .isWindows || Platform .isLinux || Platform .isMacOS) {
101- var font = configs.sysfont.tryGet ();
102- if (font != null ) {
103- await SystemFonts ().loadFont (font);
78+ var bus = ArcheBus ();
79+ var configs = ApplicationConfigs (config);
80+ bus.provide (logger).provide (config).provide (configs);
81+ // Cache Background Image in memory for faster load
82+ await calendarBackgroundData.update ();
83+ // Parse Data for fast load
84+ await icalendarParsersData.update ();
85+
86+ // Custom Font
87+ var customfont = platUserData.subFile ("customfont" );
88+ if (await customfont.exists ()) {
89+ final loader = FontLoader ("Custom Font" )
90+ ..addFont (
91+ Future (() async {
92+ var data = await customfont.readAsBytes ();
93+
94+ return data.buffer.asByteData ();
95+ }),
96+ );
97+ await loader.load ();
98+ configs.sysfont.write ("Custom Font" );
99+ } else {
100+ // Load SystemFont
101+ if (Platform .isWindows || Platform .isLinux || Platform .isMacOS) {
102+ var font = configs.sysfont.tryGet ();
103+ if (font != null ) {
104+ await SystemFonts ().loadFont (font);
105+ }
104106 }
105107 }
106- }
107108
108- logger.info ("Run Application in `main`..." );
109- logger.info ("Try to load `MultiAccountData`" );
109+ logger.info ("Run Application in `main`..." );
110+ logger.info ("Try to load `MultiAccountData`" );
110111
111- if (await MultiAccoutData .hasAccountsFile ()) {
112- bus.provide ((await MultiAccoutData .readAccounts ())! );
113- } else {
114- logger.warn ("Can't find `accounts.json`" );
115- bus.provide (MultiAccoutData .template);
116- }
112+ if (await MultiAccoutData .hasAccountsFile ()) {
113+ bus.provide ((await MultiAccoutData .readAccounts ())! );
114+ } else {
115+ logger.warn ("Can't find `accounts.json`" );
116+ bus.provide (MultiAccoutData .template);
117+ }
117118
118- runApp (
119- MainApplication (key: rootKey),
120- );
119+ runApp (
120+ MainApplication (key: rootKey),
121+ );
122+ } catch (error, stack) {
123+ logger.error (error);
124+ logger.error (stack);
125+ await catchError (logger);
126+ runApp (
127+ FallbackLogApp (
128+ error: error,
129+ stackTrace: stack,
130+ logs: logger.getLogs ().map ((log) => log.toString ()).toList (),
131+ ),
132+ );
133+ }
121134 },
122135 (error, stack) async {
123136 var logger = ArcheBus .bus.provideof (instance: ArcheLogger ());
@@ -478,3 +491,64 @@ class MainViewState extends State<MainView> with RefreshMountedStateMixin {
478491 );
479492 }
480493}
494+
495+ class FallbackLogApp extends StatelessWidget {
496+ final Object error;
497+ final StackTrace stackTrace;
498+ final List <String > logs;
499+
500+ const FallbackLogApp ({
501+ super .key,
502+ required this .error,
503+ required this .stackTrace,
504+ required this .logs,
505+ });
506+
507+ @override
508+ Widget build (BuildContext context) {
509+ return MaterialApp (
510+ debugShowCheckedModeBanner: false ,
511+ home: Scaffold (
512+ appBar: AppBar (
513+ title: const Text ("致命错误!应用启动失败😭" ),
514+ ),
515+ body: SafeArea (
516+ child: Padding (
517+ padding: const EdgeInsets .all (16 ),
518+ child: Column (
519+ crossAxisAlignment: CrossAxisAlignment .stretch,
520+ children: [
521+ Text (
522+ "错误: ${error .toString ()}" ,
523+ style: Theme .of (context).textTheme.titleMedium,
524+ ),
525+ const SizedBox (height: 8 ),
526+ Expanded (
527+ child: DecoratedBox (
528+ decoration: BoxDecoration (
529+ border: Border .all (color: Colors .redAccent),
530+ borderRadius: BorderRadius .circular (8 ),
531+ ),
532+ child: SingleChildScrollView (
533+ padding: const EdgeInsets .all (12 ),
534+ child: SelectableText (
535+ ([error.toString (), stackTrace.toString (), ...logs])
536+ .join ("\n " ),
537+ style: const TextStyle (fontFamily: "monospace" ),
538+ ),
539+ ),
540+ ),
541+ ),
542+ const SizedBox (height: 8 ),
543+ const Text (
544+ "请将上述日志反馈给开发者以便排查。" ,
545+ textAlign: TextAlign .center,
546+ ),
547+ ],
548+ ),
549+ ),
550+ ),
551+ ),
552+ );
553+ }
554+ }
0 commit comments