amoriai/lib/main.dart

201 lines
6.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'core/config/app_config.dart';
import 'core/theme/app_theme.dart';
// import 'services/firebase_service.dart'; // Not needed for direct Firebase initialization
import 'services/gemini_service.dart';
import 'services/dialog_service.dart';
// TODO: Import models when Hive adapters are generated
import 'models/user_model.dart';
import 'models/menu_model.dart';
import 'models/recommendation_model.dart';
import 'screens/splash_screen.dart';
import 'core/constants/app_constants.dart';
import 'firebase_options.dart';
// Background message handler
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// Only initialize if not already initialized
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
debugPrint('Handling a background message: ${message.messageId}');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Set system UI overlay style
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
// Set preferred orientations
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
try {
// Initialize Hive
await Hive.initFlutter();
// Register Hive adapters
Hive.registerAdapter(UserModelAdapter());
Hive.registerAdapter(UserPreferencesAdapter());
Hive.registerAdapter(MenuModelAdapter());
Hive.registerAdapter(RecommendationModelAdapter());
Hive.registerAdapter(MenuRecommendationAdapter());
// Open Hive boxes
await Future.wait([
Hive.openBox<UserModel>(AppConstants.userPreferencesBox),
Hive.openBox<RecommendationModel>(AppConstants.recommendationsBox),
Hive.openBox<MenuModel>(AppConstants.menusBox),
]);
// Initialize Firebase (handle duplicate app error gracefully)
try {
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
debugPrint('✅ Firebase initialized');
} catch (e) {
if (e.toString().contains('duplicate-app')) {
debugPrint('⚠️ Firebase already initialized, using existing instance');
} else {
rethrow;
}
}
// Set up background message handler
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// Initialize Gemini service
try {
await GeminiService().initialize();
debugPrint('✅ Gemini service initialized');
} catch (e) {
debugPrint('⚠️ Gemini service initialization failed: $e');
debugPrint('💡 Users can set their own API key in settings');
}
// Print configuration in debug mode
AppConfig.printConfig();
runApp(const ProviderScope(child: AmoriMenuRecommenderApp()));
} catch (e) {
debugPrint('Initialization error: $e');
runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
const Text(
'Gagal menginisialisasi aplikasi',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Error: $e',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
// Restart app
main();
},
child: const Text('Coba Lagi'),
),
],
),
),
),
),
);
}
}
class AmoriMenuRecommenderApp extends ConsumerWidget {
const AmoriMenuRecommenderApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
title: AppConstants.appName,
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: ThemeMode.system,
// Global Keys for DialogService
navigatorKey: DialogService().navigatorKey,
scaffoldMessengerKey: DialogService().scaffoldMessengerKey,
home: const SplashScreen(),
builder: (context, child) {
// Handle global errors
ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red),
const SizedBox(height: 16),
const Text(
'Terjadi kesalahan',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
if (AppConfig.isDebugMode)
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
errorDetails.exception.toString(),
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
// Navigate back or restart
Navigator.of(context).pop();
},
child: const Text('Kembali'),
),
],
),
),
);
};
return child!;
},
);
}
}