import 'dart:async'; import 'dart:convert'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:onufitness/constants/api_enum_constant.dart'; import 'package:onufitness/constants/constant.dart'; import 'package:onufitness/constants/data/bindings.dart'; import 'package:onufitness/constants/data_constant.dart'; import 'package:onufitness/environment/app_environment.dart'; import 'package:onufitness/firebase_options.dart'; import 'package:onufitness/routes/app_page_router.dart'; import 'package:onufitness/routes/route_constant.dart'; import 'package:onufitness/services/agora/call_services.dart'; import 'package:onufitness/services/local_storage_services/shared_services.dart'; import 'package:onufitness/services/logger_service/logger_service.dart'; import 'package:onufitness/services/network_service/network_service.dart'; import 'package:onufitness/services/notification_services/navigation_controller.dart'; import 'package:onufitness/services/notification_services/notification_service.dart'; import 'package:onufitness/services/socket/socket_service.dart'; import 'package:onufitness/themes/app_theme.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { //...Maintain the order of the code in main method................................................ WidgetsFlutterBinding.ensureInitialized(); //................................................................................................. // Set Application Environment - Development AppEnvironment.setEnvironment(Environment.production); final logger = LoggerService(); logger.log('App starting in ${AppEnvironment.environmentName} mode'); //................................................................................................. SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( systemNavigationBarColor: Colors.white, statusBarColor: Colors.white, statusBarIconBrightness: Brightness.dark, systemNavigationBarIconBrightness: Brightness.dark, ), ); //................................................................................................. await Future.wait([ SharedPreferences.getInstance().then((value) => preferences = value), Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform), ]); //................................................................................................. FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); //................................................................................................. //.....................................................q............................................ // Initialize NotificationController first final notifController = Get.put( NotificationNavigationController(), permanent: true, ); //................................................................................................. // Initialize NetworkController Get.put(NetworkController()); //................................................................................................. // Set orientation SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); //........................................................................... await Get.putAsync( () async => NotificationService(), permanent: true, ); if (SharedServices.isLoggedIn()) { await Get.putAsync(() async { return await AgoraCallService().init(); }, permanent: true); } //................................................................................................. await SentryFlutter.init( (options) { options.dsn = sentryDsnId; options.sendDefaultPii = true; options.attachScreenshot = true; options.enableAppLifecycleBreadcrumbs = true; options.enableNativeCrashHandling = true; options.attachStacktrace = true; options.tracesSampleRate = 0.01; options.debug = kDebugMode; options.diagnosticLevel = kDebugMode ? SentryLevel.debug : SentryLevel.error; options.enableLogs = kDebugMode; options.replay.sessionSampleRate = kDebugMode ? 0.0 : 0.1; options.replay.onErrorSampleRate = 1.0; options.environment = kDebugMode ? sentryDevEnvironment : sentryReleaseEnvironment; }, appRunner: () { runApp(SentryWidget(child: MyApp())); WidgetsBinding.instance.addPostFrameCallback((_) { unawaited(_initializePostFrameServices(logger, notifController)); }); }, ); //...................................................................... // runApp(SentryWidget(child: MyApp())); // WidgetsBinding.instance.addPostFrameCallback((_) { // unawaited(_initializePostFrameServices(logger, notifController)); // }); } Future _initializePostFrameServices( LoggerService logger, NotificationNavigationController notifController, ) async { await _handleNotificationLaunch(logger, notifController); if (SharedServices.isLoggedIn()) { Future.delayed(const Duration(seconds: 1), () { if (!Get.isRegistered()) { Get.put(SocketService(), permanent: true); } }); } } Future _handleNotificationLaunch( LoggerService logger, NotificationNavigationController notifController, ) async { final details = await globalNotificationsPlugin.getNotificationAppLaunchDetails(); if (details?.didNotificationLaunchApp ?? false) { final payload = details?.notificationResponse?.payload; final notificationId = details?.notificationResponse?.id; final actionId = details?.notificationResponse?.actionId; if (notificationId != null) { await globalNotificationsPlugin.cancel(notificationId); } if (payload != null) { try { final data = jsonDecode(payload); final notificationType = parseNotificationType( data['notificationType'], ); if (actionId == 'reject_call') { notifController.isCallingNotificationNavigation.value = false; // DON'T RETURN - just skip processing } else { // Only process normal incoming calls if (notificationType == ApiEnum.CallingNotification) { await globalNotificationsPlugin.cancelAll(); final channelName = extractChannelName(data); if (channelName != null) { activeCallNotifications.remove(channelName); } } notifController.setFlagsFromPayload(data); } } catch (e) { logger.error('Error decoding notification payload', error: e); } } } } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth >= 600) { return ScreenUtilInit( designSize: const Size(600, 960), minTextAdapt: true, splitScreenMode: true, builder: (context, child) { return GetMaterialApp( initialBinding: MyBinding(), debugShowCheckedModeBanner: false, initialRoute: RouteConstant.splashScreen, getPages: AppPageRouter().getPages, title: 'OnUFitness', theme: AppTheme.currentTheme, ); }, ); } else { return ScreenUtilInit( designSize: const Size(375, 812), minTextAdapt: true, splitScreenMode: true, builder: (context, child) { return GetMaterialApp( initialBinding: MyBinding(), debugShowCheckedModeBanner: false, initialRoute: RouteConstant.splashScreen, getPages: AppPageRouter().getPages, title: 'OnUFitness', theme: AppTheme.currentTheme, ); }, ); } }, ); } }