import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:worker/app.dart'; import 'package:worker/core/database/hive_initializer.dart'; /// Main entry point of the Worker Mobile App /// /// Initializes core dependencies: /// - Hive database with adapters and boxes /// - SharedPreferences for simple key-value storage /// - Riverpod ProviderScope for state management /// - Error handling boundaries /// - System UI customization void main() async { // Ensure Flutter is initialized before async operations WidgetsFlutterBinding.ensureInitialized(); // Set preferred device orientations await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); // Initialize app with error handling await _initializeApp(); } /// Initialize all app dependencies with comprehensive error handling Future _initializeApp() async { // Set up error handlers before anything else _setupErrorHandlers(); try { // Initialize core dependencies in parallel for faster startup await Future.wait([ _initializeHive(), _initializeSharedPreferences(), ]); // Run the app with Riverpod ProviderScope runApp( const ProviderScope( child: WorkerApp(), ), ); } catch (error, stackTrace) { // Critical initialization error - show error screen debugPrint('Failed to initialize app: $error'); debugPrint('StackTrace: $stackTrace'); // Run minimal error app runApp(_buildErrorApp(error, stackTrace)); } } /// Initialize Hive database /// /// Sets up local database with: /// - Type adapters for all models /// - All required boxes (user, cart, products, etc.) /// - Cache cleanup for expired data /// - Encryption for sensitive data (in production) Future _initializeHive() async { try { debugPrint('Initializing Hive database...'); await HiveInitializer.initialize( enableEncryption: kReleaseMode, // Enable encryption in release builds verbose: kDebugMode, // Verbose logging in debug mode ); debugPrint('Hive database initialized successfully'); } catch (error, stackTrace) { debugPrint('Failed to initialize Hive: $error'); debugPrint('StackTrace: $stackTrace'); rethrow; } } /// Initialize SharedPreferences /// /// Used for simple key-value storage like: /// - Last sync timestamp /// - User preferences (language, theme) /// - App settings /// - Feature flags Future _initializeSharedPreferences() async { try { debugPrint('Initializing SharedPreferences...'); // Pre-initialize SharedPreferences instance await SharedPreferences.getInstance(); debugPrint('SharedPreferences initialized successfully'); } catch (error, stackTrace) { debugPrint('Failed to initialize SharedPreferences: $error'); debugPrint('StackTrace: $stackTrace'); rethrow; } } /// Set up global error handlers /// /// Captures and logs all Flutter framework errors and uncaught exceptions void _setupErrorHandlers() { // Handle Flutter framework errors FlutterError.onError = (FlutterErrorDetails details) { FlutterError.presentError(details); // Log to console in debug mode if (kDebugMode) { debugPrint('Flutter Error: ${details.exceptionAsString()}'); debugPrint('StackTrace: ${details.stack}'); } // In production, you would send to crash analytics service // Example: FirebaseCrashlytics.instance.recordFlutterError(details); }; // Handle errors outside of Flutter framework PlatformDispatcher.instance.onError = (error, stackTrace) { if (kDebugMode) { debugPrint('Platform Error: $error'); debugPrint('StackTrace: $stackTrace'); } // In production, you would send to crash analytics service // Example: FirebaseCrashlytics.instance.recordError(error, stackTrace); return true; // Return true to indicate error was handled }; // Handle zone errors (async errors not caught by Flutter) runZonedGuarded( () { // App will run in this zone }, (error, stackTrace) { if (kDebugMode) { debugPrint('Zone Error: $error'); debugPrint('StackTrace: $stackTrace'); } // In production, you would send to crash analytics service // Example: FirebaseCrashlytics.instance.recordError(error, stackTrace); }, ); } /// Build minimal error app when initialization fails /// /// Shows a user-friendly error screen instead of crashing Widget _buildErrorApp(Object error, StackTrace stackTrace) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( backgroundColor: const Color(0xFFF5F5F5), body: SafeArea( child: Center( child: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Error icon const Icon( Icons.error_outline, size: 80, color: Color(0xFFDC3545), ), const SizedBox(height: 24), // Error title const Text( 'Không thể khởi động ứng dụng', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xFF212529), ), textAlign: TextAlign.center, ), const SizedBox(height: 16), // Error message const Text( 'Đã xảy ra lỗi khi khởi động ứng dụng. ' 'Vui lòng thử lại sau hoặc liên hệ hỗ trợ.', style: TextStyle( fontSize: 16, color: Color(0xFF6C757D), ), textAlign: TextAlign.center, ), const SizedBox(height: 32), // Error details (debug mode only) if (kDebugMode) ...[ Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFFFFF3CD), borderRadius: BorderRadius.circular(8), border: Border.all( color: const Color(0xFFFFECB5), width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Debug Information:', style: TextStyle( fontWeight: FontWeight.bold, color: Color(0xFF856404), ), ), const SizedBox(height: 8), Text( error.toString(), style: const TextStyle( fontSize: 12, color: Color(0xFF856404), fontFamily: 'monospace', ), ), ], ), ), const SizedBox(height: 16), ], // Restart button ElevatedButton.icon( onPressed: () { // Restart app _initializeApp(); }, icon: const Icon(Icons.refresh), label: const Text('Thử lại'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF005B9A), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 32, vertical: 16, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), ], ), ), ), ), ), ); }