Files
worker/lib/main.dart
Phuoc Nguyen e3632d4445 add sentry
2025-12-11 13:44:26 +07:00

273 lines
8.8 KiB
Dart

import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
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/app_settings_box.dart';
import 'package:worker/core/database/hive_initializer.dart';
import 'package:worker/core/services/onesignal_service.dart';
import 'package:worker/core/services/sentry_service.dart';
import 'package:worker/firebase_options.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();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Set preferred device orientations
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// Initialize app with error handling
await _initializeApp();
// Enable verbose logging for debugging (remove in production)
}
/// Initialize all app dependencies with comprehensive error handling
Future<void> _initializeApp() async {
// Initialize Sentry first to capture any initialization errors
// Sentry wraps the app runner to capture errors during startup
await SentryService.init(
appRunner: () async {
// Set up error handlers
_setupErrorHandlers();
try {
// Initialize core dependencies in parallel for faster startup
await Future.wait([_initializeHive(), _initializeSharedPreferences()]);
// Initialize OneSignal push notifications
await OneSignalService.init();
// Run the app with Riverpod ProviderScope
runApp(const ProviderScope(child: WorkerApp()));
} catch (error, stackTrace) {
// Critical initialization error - capture and show error screen
debugPrint('Failed to initialize app: $error');
debugPrint('StackTrace: $stackTrace');
// Report to Sentry
await SentryService.captureException(error, 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
);
// Initialize AppSettingsBox for app settings (theme, language, etc.)
await AppSettingsBox.init();
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.
/// Reports errors to Sentry for crash analytics.
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}');
}
// Report to Sentry
SentryService.captureException(
details.exception,
stackTrace: details.stack,
);
};
// Handle errors outside of Flutter framework
PlatformDispatcher.instance.onError = (error, stackTrace) {
if (kDebugMode) {
debugPrint('Platform Error: $error');
debugPrint('StackTrace: $stackTrace');
}
// Report to Sentry
SentryService.captureException(error, stackTrace: stackTrace);
return true; // Return true to indicate error was handled
};
}
/// 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),
),
),
),
],
),
),
),
),
),
);
}