Files
worker/lib/main.dart
2025-11-07 11:52:06 +07:00

258 lines
8.3 KiB
Dart

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<void> _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<void> _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<void> _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),
),
),
),
],
),
),
),
),
),
);
}