import 'dart:async'; import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'app/injection_container.dart'; import 'app/app.dart'; import 'core/constants/app_constants.dart'; import 'core/utils/init_guard.dart'; @pragma('vm:entry-point') Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); } Future main() async { await runZonedGuarded( () async { WidgetsFlutterBinding.ensureInitialized(); _installGlobalErrorUi(); await AppConstants.clearServerUrl(); if (!kIsWeb) { final firebaseApp = await ignoreInitFailure( () => Firebase.initializeApp(), label: 'Firebase init', ); if (firebaseApp != null) { FirebaseMessaging.onBackgroundMessage( _firebaseMessagingBackgroundHandler, ); } } try { await initDependencies(); } catch (error, stackTrace) { debugPrint('WalkGuide startup failed: $error\n$stackTrace'); runApp(WalkGuideFatalApp(error: error, stackTrace: stackTrace)); return; } runApp(const WalkGuideApp()); }, (error, stackTrace) { debugPrint('WalkGuide uncaught error: $error\n$stackTrace'); runApp(WalkGuideFatalApp(error: error, stackTrace: stackTrace)); }, ); } void _installGlobalErrorUi() { FlutterError.onError = (details) { FlutterError.presentError(details); debugPrint('WalkGuide Flutter error: ${details.exceptionAsString()}'); }; PlatformDispatcher.instance.onError = (error, stackTrace) { debugPrint('WalkGuide platform error: $error\n$stackTrace'); return true; }; ErrorWidget.builder = (details) { return WalkGuideErrorPanel( title: 'WalkGuide UI Error', message: 'A screen failed to render. Please report this message to the developer.', details: details.exceptionAsString(), ); }; } class WalkGuideFatalApp extends StatelessWidget { final Object error; final StackTrace? stackTrace; const WalkGuideFatalApp({ super.key, required this.error, this.stackTrace, }); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: WalkGuideErrorPanel( title: 'WalkGuide Startup Error', message: 'The app could not finish startup. Please report this screen to the developer.', details: error.toString(), stackTrace: stackTrace?.toString(), ), ); } } class WalkGuideErrorPanel extends StatelessWidget { final String title; final String message; final String details; final String? stackTrace; const WalkGuideErrorPanel({ super.key, required this.title, required this.message, required this.details, this.stackTrace, }); @override Widget build(BuildContext context) { final textTheme = Theme.of(context).textTheme; return Scaffold( backgroundColor: const Color(0xFFF8FAFC), body: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 520), child: DecoratedBox( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFFE2E8F0)), boxShadow: const [ BoxShadow( blurRadius: 24, offset: Offset(0, 12), color: Color(0x1A0F172A), ), ], ), child: Padding( padding: const EdgeInsets.all(22), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon( Icons.error_outline, color: Color(0xFFDC2626), size: 42, ), const SizedBox(height: 16), Text( title, style: textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.w800, color: const Color(0xFF0F172A), ), ), const SizedBox(height: 8), Text( message, style: textTheme.bodyMedium?.copyWith( color: const Color(0xFF475569), ), ), const SizedBox(height: 18), Container( width: double.infinity, padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(10), border: Border.all(color: const Color(0xFFE2E8F0)), ), child: SelectableText( _formatDetails(), style: const TextStyle( fontFamily: 'monospace', fontSize: 12, color: Color(0xFF334155), ), ), ), const SizedBox(height: 16), const Text( 'Tip: close the app and open it again after fixing the configuration.', style: TextStyle( color: Color(0xFF64748B), fontSize: 12, ), ), ], ), ), ), ), ), ), ), ); } String _formatDetails() { final stack = stackTrace; if (stack == null || stack.isEmpty) return details; final shortStack = stack.split('\n').take(8).join('\n'); return '$details\n\n$shortStack'; } }