import 'dart:io'; import 'package:car_provider_app/config/provider_dependencies.dart'; import 'package:flutter/services.dart'; import 'package:mc_common_app/repositories/items_repo.dart'; import 'package:mc_common_app/repositories/schedule_repo.dart'; import 'package:car_provider_app/view_models/items_view_model.dart'; import 'package:car_provider_app/view_models/schedule_view_model.dart'; import 'package:mc_common_app/repositories/setting_options_repo.dart'; import 'package:mc_common_app/repositories/shipping_repo.dart'; import 'package:mc_common_app/services/ad_deep_link_service.dart'; import 'package:mc_common_app/services/firebase_service.dart'; import 'package:mc_common_app/utils/location/Location.dart'; import 'package:mc_common_app/view_models/dashboard_view_model_provider.dart'; import 'package:mc_common_app/view_models/service_view_model.dart'; import 'package:mc_common_app/views/splash/splash_page.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:mc_common_app/classes/app_state.dart'; import 'package:mc_common_app/config/dependency_injection.dart'; import 'package:mc_common_app/config/routes.dart'; import 'package:mc_common_app/models/general_models/post_params_model.dart'; import 'package:mc_common_app/repositories/ads_repo.dart'; import 'package:mc_common_app/repositories/appointment_repo.dart'; import 'package:mc_common_app/repositories/branch_repo.dart'; import 'package:mc_common_app/repositories/chat_repo.dart'; import 'package:mc_common_app/repositories/common_repo.dart'; import 'package:mc_common_app/repositories/payments_repo.dart'; import 'package:mc_common_app/repositories/request_repo.dart'; import 'package:mc_common_app/repositories/subscription_repo.dart'; import 'package:mc_common_app/repositories/user_repo.dart'; import 'package:mc_common_app/services/common_services.dart'; import 'package:mc_common_app/services/payments_service.dart'; import 'package:mc_common_app/theme/app_theme.dart'; import 'package:mc_common_app/utils/enums.dart'; import 'package:mc_common_app/view_models/ad_view_model.dart'; import 'package:mc_common_app/view_models/appointments_view_model.dart'; import 'package:mc_common_app/view_models/base_view_model.dart'; import 'package:mc_common_app/view_models/chat_view_model.dart'; import 'package:mc_common_app/view_models/payment_view_model.dart'; import 'package:mc_common_app/view_models/requests_view_model.dart'; import 'package:mc_common_app/view_models/setting_options_view_model.dart'; import 'package:mc_common_app/view_models/shipping_management_view_model.dart'; import 'package:mc_common_app/view_models/subscriptions_view_model.dart'; import 'package:mc_common_app/view_models/user_view_model.dart'; import 'package:mc_common_app/widgets/extensions/extensions_widget.dart'; import 'package:provider/provider.dart'; import 'package:sizer/sizer.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:toastification/toastification.dart'; import 'config/provider_routes.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); if (Platform.isAndroid) { await Firebase.initializeApp( options: const FirebaseOptions( apiKey: 'AIzaSyD1WNNGrbBiCNvCrI31d3DV5AOgToq-Lus', appId: '1:294636898500:android:e93b7e5d1cc15ae6b0e191', messagingSenderId: '294636898500', projectId: 'mowater-2c81a', ), ); } else { await Firebase.initializeApp(); } ProviderAppDependencies.addDependencies(); injector.get().initializeNotifications().whenComplete(() { injector.get().handleLocationPermission(); }); ProviderAppRoutes.routes.addAll(AppRoutes.routes); runApp(MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => BaseVM()), ChangeNotifierProvider( create: (_) => DashboardVMProvider(userRepo: injector.get(), commonServices: injector.get()), ), ChangeNotifierProvider( create: (_) => UserVM( userRepo: injector.get(), commanServices: injector.get(), ), ), ChangeNotifierProvider( create: (_) => ServiceVM( branchRepo: injector.get(), commonServices: injector.get(), commonRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => SubscriptionsVM(subscriptionRepo: injector.get()), ), ChangeNotifierProvider( create: (_) => ItemsVM( itemsRepo: injector.get(), commonServices: injector.get(), ), ), ChangeNotifierProvider( create: (_) => ScheduleVM( scheduleRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => AdVM( commonServices: injector.get(), adsRepo: injector.get(), commonRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => RequestsVM( commonServices: injector.get(), commonRepo: injector.get(), requestRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => AppointmentsVM( appointmentRepo: injector.get(), commonServices: injector.get(), commonRepo: injector.get(), branchRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => ChatVM( chatRepo: injector.get(), requestRepo: injector.get(), commonServices: injector.get(), ), ), ChangeNotifierProvider( create: (_) => PaymentVM( paymentService: injector.get(), paymentRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => ShippingManagementVM( shippingRepo: injector.get(), commonRepo: injector.get(), ), ), ChangeNotifierProvider( create: (_) => SettingOptionsVM( settingOptionsRepo: injector.get(), ), ), ], child: const MyApp(), ).setupLocale()); } // todo terminal command to genertate translation files // flutter pub run easy_localization:generate --source-dir ./assets/langs // todo terminal command to genertate translation keys // flutter pub run easy_localization:generate --source-dir ./assets/langs -f keys -o locale_keys.g.dart // command to generate languages data from json class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { AdDeepLinkService.init(); }); } @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); return Sizer( builder: (context, orientation, deviceType) { injector.get().setAppType(AppType.provider); AppState().setPostParamsModel( PostParamsModel(languageID: EasyLocalization.of(context)?.locale.languageCode == "ar" ? 1 : 2), ); // ThemeData data = AppTheme.getTheme(isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar"); return ToastificationWrapper( child: MaterialApp( theme: AppTheme.getTheme(isArabic: EasyLocalization.of(context)?.locale.languageCode == "ar"), debugShowCheckedModeBanner: false, navigatorKey: navigatorKey, localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, locale: context.locale, initialRoute: AppRoutes.initialRoute, routes: ProviderAppRoutes.routes, navigatorObservers: [AdDeepLinkService.routeObserver], // Confirmed on a real device, two different unknown-route cases land here: // 1) Cold-start restoration can try to regenerate a bare "/" instead of // respecting initialRoute -- uncaught, that's a "Could not find a generator // for route" crash before AdDeepLinkService ever runs. Splash is a real, // correct landing page for this one. // 2) On an ALREADY-RUNNING app, Android's Flutter embedding auto-forwards the // incoming deep-link intent's path as its own route push (e.g. "/1541" from // mowaterprovider://ad/1541) independently of app_links/AdDeepLinkService, // which already handles that same uri correctly. Since "/1541" isn't a real // route, it used to fall into case 1 and push Splash right over whatever // screen (e.g. the dashboard) was already showing -- looking exactly like the // app had restarted. Anything other than bare "/" must be a no-op here: push // something inert that removes itself immediately instead of a real page. onUnknownRoute: (settings) { if (settings.name == '/') { return MaterialPageRoute(builder: (_) => const SplashPage()); } // Remove THIS specific route once inserted, not just "whatever is on top" -- // AdDeepLinkService's own (legitimate) push can land after this one, and a // plain Navigator.pop() would close that instead of this inert placeholder. late final PageRoute route; route = PageRouteBuilder( settings: const RouteSettings(name: AdDeepLinkService.ignoredPlaceholderRouteName), opaque: false, transitionDuration: Duration.zero, reverseTransitionDuration: Duration.zero, pageBuilder: (context, __, ___) { WidgetsBinding.instance.addPostFrameCallback((_) { if (route.isActive) route.navigator?.removeRoute(route); }); return const SizedBox.shrink(); }, ); return route; }, ), ); }, ); } }