import 'dart:async'; import 'dart:io'; import 'package:Intaleq/app_bindings.dart'; import 'package:Intaleq/controller/functions/crud.dart'; import 'package:Intaleq/views/home/HomePage/contact_us.dart'; import 'package:Intaleq/views/home/HomePage/share_app_page.dart'; import 'package:Intaleq/views/home/my_wallet/passenger_wallet.dart'; import 'package:Intaleq/views/home/profile/passenger_profile_page.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter/services.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; import 'constant/api_key.dart'; import 'constant/info.dart'; import 'controller/local/local_controller.dart'; import 'controller/local/translations.dart'; import 'firebase_options.dart'; import 'models/db_sql.dart'; import 'splash_screen_page.dart'; // -- Global instances for easy access -- final box = GetStorage(); final storage = FlutterSecureStorage(); DbSql sql = DbSql.instance; // Firebase background message handler must be a top-level function. @pragma('vm:entry-point') Future backgroundMessageHandler(RemoteMessage message) async { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); print("Handling a background message: ${message.messageId}"); } void main() { // Use runZonedGuarded to catch all unhandled exceptions in the app. runZonedGuarded>(() async { // --- Step 1: Critical initializations before runApp() --- // These must complete before the UI can be built. WidgetsFlutterBinding.ensureInitialized(); await GetStorage.init(); WakelockPlus.enable(); if (Platform.isAndroid || Platform.isIOS) { await Firebase.initializeApp( options: DefaultFirebaseOptions.currentPlatform); FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler); } // Stripe key initialization is very fast. Stripe.publishableKey = AK.publishableKey; // Lock screen orientation. await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); Get.put(LocaleController()); // --- Step 2: Run the app immediately --- // All heavy initializations are deferred to the SplashScreen. runApp(const MyApp()); }, (error, stack) { // Global error handler. final s = error.toString(); final ignored = s.contains('PERMISSION_DENIED') || s.contains('FormatException') || s.contains('Null check operator used on a null value'); if (!ignored) { CRUD.addError(s, stack.toString(), 'main_zone_guard'); } }); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { // Get.find() is used here because LocaleController is already put in AppBindings. final LocaleController localController = Get.find(); return GetMaterialApp( title: AppInformation.appName, translations: MyTranslation(), debugShowCheckedModeBanner: false, locale: localController.language, theme: localController.appTheme, // --- [CRITICAL] --- // initialBinding tells GetX to run AppBindings once at the start. // This sets up all our controllers (put, lazyPut) for the entire app lifecycle. initialBinding: AppBindings(), initialRoute: '/', getPages: [ GetPage(name: '/', page: () => const SplashScreen()), // These routes are used by QuickActions and other navigation events. GetPage(name: '/shareApp', page: () => ShareAppPage()), GetPage(name: '/wallet', page: () => const PassengerWallet()), GetPage(name: '/profile', page: () => PassengerProfilePage()), GetPage(name: '/contactSupport', page: () => ContactUsPage()), ], ); } }