import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:go_router/go_router.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:timezone/data/latest_all.dart' as tz; import 'core/constants/app_colors.dart'; import 'core/constants/app_constants.dart'; import 'core/services/notification_service.dart'; import 'core/utils/ad_helper.dart'; import 'domain/entities/restaurant.dart'; import 'domain/entities/visit_record.dart'; import 'domain/entities/recommendation_record.dart'; import 'domain/entities/user_settings.dart'; import 'presentation/pages/splash/splash_screen.dart'; import 'presentation/pages/main/main_screen.dart'; import 'data/sample/sample_data_initializer.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize timezone (동기, 빠름) tz.initializeTimeZones(); // 광고 SDK와 Hive 초기화를 병렬 처리 await Future.wait([ if (AdHelper.isMobilePlatform) MobileAds.instance.initialize(), _initializeHive(), ]); // Hive 초기화 후 병렬 처리 가능한 작업들 await Future.wait([ SampleDataInitializer.seedInitialData(), _initializeNotifications(), AdaptiveTheme.getThemeMode(), ]).then((results) { final savedThemeMode = results[2] as AdaptiveThemeMode?; runApp(ProviderScope(child: LunchPickApp(savedThemeMode: savedThemeMode))); }); } /// Hive 초기화 및 Box 오픈 Future _initializeHive() async { await Hive.initFlutter(); // Register Hive Adapters Hive.registerAdapter(RestaurantAdapter()); Hive.registerAdapter(DataSourceAdapter()); Hive.registerAdapter(VisitRecordAdapter()); Hive.registerAdapter(RecommendationRecordAdapter()); Hive.registerAdapter(UserSettingsAdapter()); // Open Hive Boxes (병렬 오픈) await Future.wait([ Hive.openBox(AppConstants.restaurantBox), Hive.openBox(AppConstants.visitRecordBox), Hive.openBox(AppConstants.recommendationBox), Hive.openBox(AppConstants.settingsBox), Hive.openBox('user_settings'), ]); } /// 알림 서비스 초기화 (비-웹 플랫폼) Future _initializeNotifications() async { if (kIsWeb) return; final notificationService = NotificationService(); await notificationService.ensureInitialized(requestPermission: true); } class LunchPickApp extends StatelessWidget { final AdaptiveThemeMode? savedThemeMode; const LunchPickApp({super.key, this.savedThemeMode}); @override Widget build(BuildContext context) { return AdaptiveTheme( light: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: AppColors.lightPrimary, brightness: Brightness.light, ), primaryColor: AppColors.lightPrimary, scaffoldBackgroundColor: AppColors.lightBackground, appBarTheme: const AppBarTheme( backgroundColor: AppColors.lightPrimary, foregroundColor: Colors.white, elevation: 0, ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: AppColors.lightPrimary, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), cardTheme: CardThemeData( color: AppColors.lightSurface, elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), dark: ThemeData( useMaterial3: true, colorScheme: ColorScheme.fromSeed( seedColor: AppColors.darkPrimary, brightness: Brightness.dark, ), primaryColor: AppColors.darkPrimary, scaffoldBackgroundColor: AppColors.darkBackground, appBarTheme: const AppBarTheme( backgroundColor: AppColors.darkPrimary, foregroundColor: Colors.white, elevation: 0, ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( backgroundColor: AppColors.darkPrimary, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), cardTheme: CardThemeData( color: AppColors.darkSurface, elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), initial: savedThemeMode ?? AdaptiveThemeMode.light, builder: (theme, darkTheme) => MaterialApp.router( title: AppConstants.appName, theme: theme, darkTheme: darkTheme, routerConfig: _router, debugShowCheckedModeBanner: false, ), ); } } // GoRouter configuration final _router = GoRouter( initialLocation: '/', routes: [ GoRoute(path: '/', builder: (context, state) => const SplashScreen()), GoRoute( path: '/home', builder: (context, state) { final tabParam = state.uri.queryParameters['tab']; int initialTab = 2; // 기본값: 뽑기 탭 if (tabParam != null) { switch (tabParam) { case 'share': initialTab = 0; break; case 'list': initialTab = 1; break; case 'random': initialTab = 2; break; case 'calendar': initialTab = 3; break; case 'settings': initialTab = 4; break; } } return MainScreen(initialTab: initialTab); }, ), ], );