import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:flutter/foundation.dart' show kIsWeb, kDebugMode; import 'package:flutter_localizations/flutter_localizations.dart'; import 'models/subscription_model.dart'; import 'models/category_model.dart'; import 'models/payment_card_model.dart'; import 'providers/subscription_provider.dart'; import 'providers/app_lock_provider.dart'; import 'providers/notification_provider.dart'; import 'providers/navigation_provider.dart'; import 'providers/payment_card_provider.dart'; import 'services/notification_service.dart'; import 'providers/category_provider.dart'; import 'providers/locale_provider.dart'; import 'providers/theme_provider.dart'; import 'l10n/app_localizations.dart'; import 'theme/adaptive_theme.dart'; import 'routes/app_routes.dart'; import 'navigation/app_navigation_observer.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'dart:io' show Platform; import 'dart:async' show unawaited; import 'utils/memory_manager.dart'; import 'utils/logger.dart'; import 'utils/performance_optimizer.dart'; import 'navigator_key.dart'; // AdMob 활성화 플래그 (개발 중 false, 프로덕션 시 true로 변경) const bool enableAdMob = true; Future main() async { WidgetsFlutterBinding.ensureInitialized(); // Android 15 edge-to-edge 모드 활성화 // 콘텐츠가 시스템 바 영역까지 확장됨 SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); // 구글 모바일 광고 SDK 초기화 (웹이 아니고, Android/iOS에서만) if (!kIsWeb && (Platform.isAndroid || Platform.isIOS) && enableAdMob) { unawaited(MobileAds.instance.initialize()); } // 성능 최적화 설정 MemoryManager.optimizeImageCache(); MemoryManager().startAutoCleanup(); // 앱 시작 시 이미지 캐시 관리 try { // 메모리 이미지 캐시는 유지하지만 필요한 경우 삭제할 수 있도록 준비 // 캐시 전체 삭제는 큰 I/O 부하를 유발할 수 있어 비활성화 // 필요 시 환경 플래그로 제어하거나 주기적 백그라운드 정리로 전환하세요. const bool clearCacheOnStartup = bool.fromEnvironment( 'CLEAR_CACHE_ON_STARTUP', defaultValue: false, ); if (clearCacheOnStartup) { await DefaultCacheManager().emptyCache(); } if (kDebugMode) { Log.d('이미지 캐시 관리 초기화 완료'); PerformanceOptimizer.checkConstOptimization(); } } catch (e) { if (kDebugMode) { Log.e('캐시 초기화 오류', e); } } // Hive 초기화 await Hive.initFlutter(); Hive.registerAdapter(SubscriptionModelAdapter()); Hive.registerAdapter(CategoryModelAdapter()); Hive.registerAdapter(PaymentCardModelAdapter()); await Hive.openBox('subscriptions'); await Hive.openBox('categories'); await Hive.openBox('payment_cards'); final appLockBox = await Hive.openBox('app_lock'); // 알림 서비스를 가장 먼저 초기화 await NotificationService.init(); final subscriptionProvider = SubscriptionProvider(); final categoryProvider = CategoryProvider(); final paymentCardProvider = PaymentCardProvider(); final localeProvider = LocaleProvider(); final notificationProvider = NotificationProvider(); final themeProvider = ThemeProvider(); final navigationProvider = NavigationProvider(); await subscriptionProvider.init(); await categoryProvider.init(); await paymentCardProvider.init(); await localeProvider.init(); await notificationProvider.init(); await themeProvider.initialize(); // NotificationProvider에 SubscriptionProvider 연결 (알림 재예약용) // SRP 원칙에 따라 다른 Provider 객체를 명시적으로 주입 notificationProvider.setSubscriptionProvider(subscriptionProvider); // 별도의 비동기 함수로 알림 관련 초기화 오류 처리 Future.delayed(Duration.zero, () { try { if (notificationProvider.isPaymentEnabled) { // 백그라운드에서 비동기적으로 알림 설정 업데이트 NotificationService.reschedulAllNotifications( subscriptionProvider.subscriptions); } } catch (e) { debugPrint('알림 초기 설정 중 오류 발생: $e'); } }); runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => subscriptionProvider), ChangeNotifierProvider(create: (_) => categoryProvider), ChangeNotifierProvider(create: (_) => paymentCardProvider), ChangeNotifierProvider(create: (_) => AppLockProvider(appLockBox)), ChangeNotifierProvider(create: (_) => notificationProvider), ChangeNotifierProvider(create: (_) => localeProvider), ChangeNotifierProvider(create: (_) => themeProvider), ChangeNotifierProvider(create: (_) => navigationProvider), ], child: const SubManagerApp(), ), ); } class SubManagerApp extends StatelessWidget { const SubManagerApp({super.key}); @override Widget build(BuildContext context) { return Consumer2( builder: (context, localeProvider, themeProvider, child) { // 시스템 UI 오버레이 스타일 적용 AdaptiveTheme.applySystemUIOverlay(context); return MaterialApp( key: ValueKey(localeProvider.locale), // Localizations는 MaterialApp 내부에서 초기화되므로 // onGenerateTitle을 사용해 로딩 이후 로컬라이즈된 타이틀을 설정합니다. onGenerateTitle: (ctx) => AppLocalizations.of(ctx).appTitle, debugShowCheckedModeBanner: false, theme: themeProvider.getTheme(context), locale: localeProvider.locale, localizationsDelegates: const [ AppLocalizationsDelegate(), GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en'), Locale('ko'), Locale('ja'), Locale('zh'), ], navigatorKey: navigatorKey, navigatorObservers: [AppNavigationObserver()], initialRoute: AppRoutes.splash, routes: AppRoutes.getRoutes(), onGenerateRoute: AppRoutes.generateRoute, builder: (context, child) { // 성능 최적화 및 메모리 관리 if (kDebugMode) { PerformanceOptimizer().startFrameMonitoring(); } return MediaQuery( data: MediaQuery.of(context).copyWith( textScaler: TextScaler.linear(themeProvider.largeText ? 1.2 : 1.0), disableAnimations: themeProvider.reduceMotion, ), child: child!, ); }, ); }, ); } }