onufitness_mobile/lib/screens/navbar/bottom_nav_bar.dart
2026-01-13 11:36:24 +05:30

457 lines
15 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen>
with WidgetsBindingObserver {
final notificationService = Get.find<NotificationService>();
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<void> 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<void> 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<void> 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<void> agoraChatTokenAPIcall() async {
try {
if (!Get.isRegistered<AgoraTokenController>()) {
Get.put(AgoraTokenController());
}
final agoraTokenController = Get.find<AgoraTokenController>();
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<void> 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<AgoraChatService>()) {
Get.put(await AgoraChatService().init(), permanent: true);
} else {
final chatService = Get.find<AgoraChatService>();
await chatService.initChatSdk();
await chatService.loginToAgora();
}
}
initializeCallAgora() async {
// No need to re-initialize, just ensure it's available
if (!Get.isRegistered<AgoraCallService>()) {
await Get.putAsync<AgoraCallService>(() async {
return await AgoraCallService().init();
}, permanent: true);
} else {
Get.find<AgoraCallService>().agoraRTMlogin();
}
}
final NavigationController navController = Get.put(
NavigationController(),
permanent: true,
);
final EchoBoardController echoBoardController = Get.put(
EchoBoardController(),
permanent: true,
);
final List<Widget> 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<SystemUiOverlayStyle>(
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();
}
}