import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:onufitness/constants/api_enum_constant.dart'; import 'package:onufitness/constants/asset_constants.dart'; import 'package:onufitness/constants/color_constant.dart'; import 'package:onufitness/constants/string_constant.dart'; import 'package:onufitness/controller/get_agora_token_controller.dart'; import 'package:onufitness/screens/accounts/views/coach_account/coach_my_account_screen.dart'; import 'package:onufitness/screens/accounts/views/trainee_account/trainee_account.dart'; import 'package:onufitness/screens/chat/controllers/chat_controller.dart'; import 'package:onufitness/screens/goals/screens/goal_screen.dart'; import 'package:onufitness/screens/echoboard/controllers/echoboard_controller.dart'; import 'package:onufitness/screens/echoboard/views/echoboard_view_screen.dart'; import 'package:onufitness/screens/home/view/home_screen.dart'; import 'package:onufitness/services/agora/agora_chat_service.dart'; import 'package:onufitness/services/agora/call_services.dart'; import 'package:onufitness/services/local_storage_services/shared_services.dart'; import 'package:onufitness/services/notification_services/notification_service.dart'; import 'package:permission_handler/permission_handler.dart'; class NavigationController extends GetxController { var currentIndex = 0.obs; void changeIndex(int index) { if (index >= 0 && index < 4) { currentIndex.value = index; } else { currentIndex.value = 0; } } } class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @override State createState() => _DashboardScreenState(); } class _DashboardScreenState extends State with WidgetsBindingObserver { final notificationService = Get.find(); final AgoraTokenController agoraTokenController = Get.put( AgoraTokenController(), permanent: true, ); final ChatController agoraChatController = Get.put( ChatController(), permanent: true, ); @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((_) { // Request all permissions sequentially requestAllPermissionsSequentially(); agoraChatTokenAPIcall(); }); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.resumed) { log("App resumed – re-checking Agora login..."); agoraChatTokenAPIcall(); } else if (state == AppLifecycleState.paused) { log("App paused – you can handle disconnects here if needed"); } } /// Request all permissions sequentially to ensure all popups appear Future requestAllPermissionsSequentially() async { try { log("Starting sequential permission requests..."); await WidgetsBinding.instance.endOfFrame; // Add a small initial delay to ensure UI is ready await Future.delayed(const Duration(milliseconds: 500)); // 1. Request Notification permission first log("Requesting notification permission..."); await notificationService.requestPermissions(); // Small delay between permissions await Future.delayed(const Duration(milliseconds: 300)); // 2. Request Microphone permission log("Requesting microphone permission..."); await requestMicrophonePermission(); // Small delay between permissions await Future.delayed(const Duration(milliseconds: 300)); // 3. Request Camera permission log("Requesting camera permission..."); await requestCameraPermission(); log("All permission requests completed"); } catch (e, st) { log("Error requesting permissions: $e", stackTrace: st); } } // Request microphone permission Future requestMicrophonePermission() async { try { final status = await Permission.microphone.status; log("Microphone permission: $status"); if (status.isDenied) { final result = await Permission.microphone.request(); log("Microphone permission result: $result"); if (result.isPermanentlyDenied) { await openAppSettings(); } } else if (status.isPermanentlyDenied) { await openAppSettings(); } } catch (e) { log("Error requesting microphone permission: $e"); } } // Request camera permission Future requestCameraPermission() async { try { final status = await Permission.camera.status; log("Camera permission: $status"); if (status.isDenied) { final result = await Permission.camera.request(); log("Camera permission result: $result"); if (result.isPermanentlyDenied) { await openAppSettings(); } } else if (status.isPermanentlyDenied) { await openAppSettings(); } } catch (e) { log("Error requesting camera permission: $e"); } } Future agoraChatTokenAPIcall() async { try { if (!Get.isRegistered()) { Get.put(AgoraTokenController()); } final agoraTokenController = Get.find(); final success = await agoraTokenController.getAgoraUserAndRrmToken(); if (success) { await agoraChatCallServicesLogin(); } else { log("Agora token fetch failed."); } } catch (e, st) { log("Error in agoraChatTokenAPIcall: $e", stackTrace: st); } } Future agoraChatCallServicesLogin() async { // Agora Chat Service Initialization await chatLoginToAgora(); //Small delay await Future.delayed(Duration(milliseconds: 500)); // Agora Call Service Initialization await initializeCallAgora(); } chatLoginToAgora() async { if (!Get.isRegistered()) { Get.put(await AgoraChatService().init(), permanent: true); } else { final chatService = Get.find(); await chatService.initChatSdk(); await chatService.loginToAgora(); } } initializeCallAgora() async { // No need to re-initialize, just ensure it's available if (!Get.isRegistered()) { await Get.putAsync(() async { return await AgoraCallService().init(); }, permanent: true); } else { Get.find().agoraRTMlogin(); } } final NavigationController navController = Get.put( NavigationController(), permanent: true, ); final EchoBoardController echoBoardController = Get.put( EchoBoardController(), permanent: true, ); final List pages = [ FitnessDashboard(), EchoBoardViewScreen(), GoalScreen(), SharedServices.getLoginDetails()?.data?.userRole == ApiEnum.traineeUserRole ? TraineeMyAccountScreen() : CoachMyAccountScreen(), ]; @override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { final int? initialIndex = Get.arguments; if (initialIndex != null && initialIndex != navController.currentIndex.value) { navController.changeIndex(initialIndex); } }); return LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth >= 600) { return navBarLayout(context); } else { return navBarLayout(context); } }, ); } Widget navBarLayout(BuildContext context) { return AnnotatedRegion( value: SystemUiOverlayStyle( systemNavigationBarColor: Colors.white, statusBarColor: Colors.white, systemNavigationBarIconBrightness: Brightness.dark, statusBarIconBrightness: Brightness.dark, ), child: Obx( () => Scaffold( // ✅ Add this to ensure proper system UI styling extendBody: true, extendBodyBehindAppBar: true, body: SafeArea(child: pages[navController.currentIndex.value]), bottomNavigationBar: Stack( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( topRight: Radius.circular(30), topLeft: Radius.circular(30), ), boxShadow: [ BoxShadow( color: Colors.black38, spreadRadius: 0, blurRadius: 10, ), ], ), child: ClipRRect( borderRadius: const BorderRadius.only( topRight: Radius.circular(24), topLeft: Radius.circular(24), ), child: BottomNavigationBar( type: BottomNavigationBarType.fixed, currentIndex: navController.currentIndex.value, onTap: navController.changeIndex, selectedItemColor: Color.fromRGBO(79, 84, 104, 1), unselectedItemColor: Color.fromRGBO(79, 84, 104, 1), showUnselectedLabels: true, backgroundColor: Colors.white, items: [ BottomNavigationBarItem( icon: SizedBox( height: 25.h, width: 25.w, child: Image.asset(AssetConstants.home), ), label: navHomeText, ), BottomNavigationBarItem( icon: SizedBox( height: 25.h, width: 25.w, child: Image.asset( AssetConstants.echoBoard, fit: BoxFit.contain, ), ), label: navEchoboardText, ), BottomNavigationBarItem( icon: SizedBox( height: 25.h, width: 25.w, child: Image.asset( AssetConstants.goal, fit: BoxFit.contain, ), ), label: navGoalText, ), BottomNavigationBarItem( icon: SizedBox( height: 25.h, width: 25.w, child: Image.asset( AssetConstants.account, fit: BoxFit.contain, ), ), label: navAccountText, ), ], ), ), ), Positioned( left: MediaQuery.of(context).size.width / 4 * navController.currentIndex.value + MediaQuery.of(context).size.width / 8 - 15, child: Container( width: 30, height: 4, color: Color(primaryColor), ), ), ], ), ), ), ); } // Widget navBarLayout(BuildContext context) { // return Obx( // () => Scaffold( // body: pages[navController.currentIndex.value], // bottomNavigationBar: Stack( // children: [ // Container( // decoration: BoxDecoration( // borderRadius: BorderRadius.only( // topRight: Radius.circular(30), // topLeft: Radius.circular(30), // ), // boxShadow: [ // BoxShadow( // color: Colors.black38, // spreadRadius: 0, // blurRadius: 10, // ), // ], // ), // child: ClipRRect( // borderRadius: const BorderRadius.only( // topRight: Radius.circular(24), // topLeft: Radius.circular(24), // ), // child: BottomNavigationBar( // type: BottomNavigationBarType.fixed, // currentIndex: navController.currentIndex.value, // onTap: navController.changeIndex, // selectedItemColor: Color.fromRGBO(79, 84, 104, 1), // unselectedItemColor: Color.fromRGBO(79, 84, 104, 1), // showUnselectedLabels: true, // backgroundColor: Colors.white, // items: [ // BottomNavigationBarItem( // icon: SizedBox( // height: 25.h, // width: 25.w, // child: Image.asset(AssetConstants.home), // ), // label: navHomeText, // ), // BottomNavigationBarItem( // icon: SizedBox( // height: 25.h, // width: 25.w, // child: Image.asset( // AssetConstants.echoBoard, // fit: BoxFit.contain, // ), // ), // label: navEchoboardText, // ), // BottomNavigationBarItem( // icon: SizedBox( // height: 25.h, // width: 25.w, // child: Image.asset( // AssetConstants.goal, // fit: BoxFit.contain, // ), // ), // label: navGoalText, // ), // BottomNavigationBarItem( // icon: SizedBox( // height: 25.h, // width: 25.w, // child: Image.asset( // AssetConstants.account, // fit: BoxFit.contain, // ), // ), // label: navAccountText, // ), // ], // ), // ), // ), // Positioned( // left: // MediaQuery.of(context).size.width / // 4 * // navController.currentIndex.value + // MediaQuery.of(context).size.width / 8 - // 15, // child: Container( // width: 30, // height: 4, // color: Color(primaryColor), // ), // ), // ], // ), // ), // ); // } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } }