Files
sfm_app_final/lib/feature/main/main_screen.dart
2025-06-09 15:43:50 +07:00

422 lines
16 KiB
Dart

// ignore_for_file: use_build_context_synchronously
import 'dart:developer';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:go_router/go_router.dart';
import 'package:badges/badges.dart' as badges;
import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart';
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
import 'package:sfm_app/product/utils/permission_handler.dart';
import '../../product/permission/notification_permission.dart';
import '../../product/services/notification_services.dart';
import '../settings/profile/profile_model.dart';
import '../../product/extension/context_extension.dart';
import '../../bloc/home_bloc.dart';
import '../../product/constant/app/app_constants.dart';
import '../../product/constant/enums/app_route_enums.dart';
import '../../product/permission/location_permission.dart';
import '../../product/services/theme_services.dart';
import '../../bloc/devices_manager_bloc.dart';
import '../devices/devices_manager_screen.dart';
import '../home/home_screen.dart';
import '../../bloc/inter_family_bloc.dart';
import '../inter_family/inter_family_screen.dart';
import '../../bloc/device_logs_bloc.dart';
import '../device_log/device_logs_screen.dart';
import '../../bloc/main_bloc.dart';
import '../../bloc/map_bloc.dart';
import '../map/map_screen.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/constant/enums/app_theme_enums.dart';
import '../../product/services/api_services.dart';
import '../../main.dart';
import '../../product/constant/icon/icon_constants.dart';
import '../../product/constant/lang/language_constants.dart';
import '../../product/services/language_services.dart';
import '../bell/bell_model.dart';
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
PersistentTabController controller = PersistentTabController(initialIndex: 0);
// @pragma('vm:entry-point')
// Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// log("Full background message payload: ${message.toMap()}");
// await Firebase.initializeApp();
// final notificationServices = NotificationServices();
// await notificationServices.initLocalNotifications(controller);
// await notificationServices.showNotification(message);
// log("Background message handled: ${message.data['title']}");
// }
class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
APIServices apiServices = APIServices();
// final NotificationServices notificationServices = NotificationServices();
late MainBloc mainBloc;
bool isVN = true;
bool isLight = true;
String role = 'Unknown';
String titlePage = "Page Title";
int currentPageIndex = 0;
final _badgeKey = GlobalKey();
Bell bell = Bell();
void initialCheck() async {
String language = await apiServices.checkLanguage();
String theme = await apiServices.checkTheme();
if (language == LanguageConstants.VIETNAM) {
isVN = true;
} else {
isVN = false;
}
if (theme == AppThemes.LIGHT.name) {
isLight = true;
} else if (theme == AppThemes.DARK.name) {
isLight = false;
} else {
isLight = true;
}
mainBloc.sinkIsVNIcon.add(isVN);
mainBloc.sinkThemeMode.add(isLight);
checkAndRequestPermission();
NotificationPermission.instance.checkNotificationPermission(context);
}
@override
void initState() {
super.initState();
mainBloc = BlocProvider.of(context);
mainBloc.getFCMTokenAndPresentations();
WidgetsBinding.instance.addObserver(this);
initialCheck();
getBellNotification();
mainBloc.getUserProfile(context);
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
log("New FCM Token: $newToken");
// Gửi token mới lên server
mainBloc.sendNotificationToken(newToken);
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null ) {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your channel id', 'your channel name',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker');
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
flutterLocalNotificationsPlugin.show(
notification.hashCode, notification.title, notification.body, platformChannelSpecifics,
);
}
});
// notificationServices.initLocalNotifications(controller);
// notificationServices.firebaseInit(context);
// NotificationServices().setupInteractMessage(controller);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.inactive) {
log("App Inactive");
} else if (state == AppLifecycleState.resumed) {
log("App Resumed");
} else if (state == AppLifecycleState.paused) {
log("App paused");
} else if (state == AppLifecycleState.detached) {
log("App detached");
}
}
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: IconConstants.instance.getMaterialIcon(Icons.home),
title: appLocalization(context).home_page_destination,
activeColorPrimary: Colors.blue,
inactiveColorPrimary: Colors.grey,
inactiveIcon:
IconConstants.instance.getMaterialIcon(Icons.home_outlined),
),
PersistentBottomNavBarItem(
icon: IconConstants.instance.getMaterialIcon(Icons.settings),
title: appLocalization(context).manager_page_destination,
activeColorPrimary: Colors.blue,
inactiveColorPrimary: Colors.grey,
inactiveIcon:
IconConstants.instance.getMaterialIcon(Icons.settings_outlined),
),
PersistentBottomNavBarItem(
icon: IconConstants.instance.getMaterialIcon(Icons.location_on),
title: appLocalization(context).map_page_destination,
activeColorPrimary: Colors.blue,
inactiveColorPrimary: Colors.grey,
inactiveIcon:
IconConstants.instance.getMaterialIcon(Icons.location_on_outlined),
),
PersistentBottomNavBarItem(
icon: IconConstants.instance.getMaterialIcon(Icons.history),
title: appLocalization(context).history_page_destination,
activeColorPrimary: Colors.blue,
inactiveColorPrimary: Colors.grey,
inactiveIcon:
IconConstants.instance.getMaterialIcon(Icons.history_outlined),
),
PersistentBottomNavBarItem(
icon: IconConstants.instance.getMaterialIcon(Icons.group),
title: appLocalization(context).group_page_destination,
activeColorPrimary: Colors.blue,
inactiveColorPrimary: Colors.grey,
inactiveIcon:
IconConstants.instance.getMaterialIcon(Icons.group_outlined),
),
];
}
List<Widget> _buildScreens() {
return [
BlocProvider(
child: const HomeScreen(),
blocBuilder: () => HomeBloc(),
),
BlocProvider(
child: const DevicesManagerScreen(),
blocBuilder: () => DevicesManagerBloc()),
BlocProvider(
child: const MapScreen(),
blocBuilder: () => MapBloc(),
),
BlocProvider(
child: const DeviceLogsScreen(),
blocBuilder: () => DeviceLogsBloc(),
),
BlocProvider(
child: const InterFamilyScreen(),
blocBuilder: () => InterFamilyBloc(),
),
];
}
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>(
stream: mainBloc.streamThemeMode,
initialData: isLight,
builder: (context, themeModeSnapshot) {
return Scaffold(
appBar: AppBar(
title: StreamBuilder<User>(
stream: mainBloc.streamUserProfile,
builder: (context, userSnapshot) {
return Row(
children: [
IconConstants.instance.getMaterialIcon(Icons.person),
SizedBox(
width: context.lowValue,
),
Flexible( child: Text(userSnapshot.data?.name ?? ""))
],
);
}),
backgroundColor: Colors.transparent,
actions: [
IconButton(
onPressed: () async {
ThemeData newTheme = await ThemeServices().changeTheme(
isLight ? AppThemes.DARK.name : AppThemes.LIGHT.name);
MyApp.setTheme(context, newTheme);
isLight = !isLight;
mainBloc.sinkThemeMode.add(isLight);
},
icon: Icon(
themeModeSnapshot.data ?? isLight
? Icons.light_mode_outlined
: Icons.dark_mode_outlined,
),
),
StreamBuilder<bool>(
stream: mainBloc.streamIsVNIcon,
initialData: isVN,
builder: (context, isVnSnapshot) {
return IconButton(
onPressed: () async {
log("Locale: ${LanguageServices().getLocale()}");
Locale locale = await LanguageServices().setLocale(isVN
? LanguageConstants.ENGLISH
: LanguageConstants.VIETNAM);
MyApp.setLocale(context, locale);
isVN = !isVN;
mainBloc.sinkIsVNIcon.add(isVN);
},
icon: Image.asset(
IconConstants.instance.getIcon(
isVnSnapshot.data ?? isVN ? 'vi_icon' : 'en_icon'),
height: 24,
width: 24,
),
);
},
),
StreamBuilder<Bell>(
stream: mainBloc.streamBellBloc,
builder: (context, bellSnapshot) {
return checkStatus(bellSnapshot.data?.items ?? [])
? IconButton(
onPressed: () {
context.pushNamed(AppRoutes.BELL.name);
},
icon: const Icon(
Icons.notifications,
),
)
: GestureDetector(
child: badges.Badge(
badgeStyle: const badges.BadgeStyle(
shape: badges.BadgeShape.twitter,
),
key: _badgeKey,
badgeContent: const Icon(
CupertinoIcons.circle_filled,
color: Colors.red,
size: 5,
),
badgeAnimation: const badges.BadgeAnimation.slide(
animationDuration: Duration(milliseconds: 200),
colorChangeAnimationDuration:
Duration(seconds: 1),
loopAnimation: false,
curve: Curves.decelerate,
colorChangeAnimationCurve: Curves.easeInCirc,
),
showBadge: true,
// ignorePointer: false,
child: const Icon(
Icons.notifications,
size: 30,
),
),
onTap: () {
context.pushNamed(AppRoutes.BELL.name);
},
);
},
),
PopupMenuButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
icon: const Icon(Icons.more_vert),
itemBuilder: (context) {
return [
PopupMenuItem(
value: ApplicationConstants.SETTINGS_PATH,
onTap: () {
context.pushNamed(AppRoutes.SETTINGS.name);
},
child: Row(
children: [
const Icon(Icons.person),
const SizedBox(width: 5),
Text(appLocalization(context).profile_icon_title)
],
),
),
PopupMenuItem(
value: ApplicationConstants.LOGOUT_PATH,
onTap: () {
Future.delayed(
const Duration(milliseconds: 200),
() async {
await apiServices.logOut(context);
},
);
},
child: Row(
children: [
const Icon(Icons.logout),
const SizedBox(width: 5),
Text(
appLocalization(context).log_out,
),
],
),
),
];
},
)
],
),
body: PersistentTabView(
context,
controller: controller,
screens: _buildScreens(),
items: _navBarsItems(),
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true,
stateManagement: false,
backgroundColor:
themeModeSnapshot.data! ? Colors.white : Colors.black,
decoration: NavBarDecoration(
borderRadius: BorderRadius.circular(30.0),
colorBehindNavBar:
themeModeSnapshot.data! ? Colors.white : Colors.black,
),
animationSettings: const NavBarAnimationSettings(
navBarItemAnimation: ItemAnimationSettings(
duration: Duration(milliseconds: 200),
curve: Curves.bounceInOut,
),
screenTransitionAnimation: ScreenTransitionAnimationSettings(
animateTabTransition: true,
curve: Curves.bounceInOut,
duration: Duration(milliseconds: 200),
),
),
navBarStyle: NavBarStyle.style13,
),
);
},
);
}
Future<void> getBellNotification() async {
try{
bell = await apiServices.getBellNotifications("0", "20");
mainBloc.bellBloc.add(bell);
}catch(e){
showErrorTopSnackBarCustom(context, e.toString());
}
}
bool checkStatus(List<BellItems> bells) {
if (bells.isEmpty) {
return true;
}
return !bells.any((bell) => bell.status == 0);
}
}