import 'dart:async'; import 'dart:developer'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import 'package:provider/provider.dart'; import 'package:badges/badges.dart' as badges; import 'api/mhsl/breaker/getBreakers/getBreakersResponse.dart'; import 'api/mhsl/server/userIndex/update/updateUserindex.dart'; import 'main.dart'; import 'model/breakers/Breaker.dart'; import 'model/breakers/BreakerProps.dart'; import 'model/chatList/chatListProps.dart'; import 'model/dataCleaner.dart'; import 'model/timetable/timetableProps.dart'; import 'notification/notificationController.dart'; import 'notification/notificationTasks.dart'; import 'notification/notifyUpdater.dart'; import 'storage/base/settingsProvider.dart'; import 'view/pages/files/files.dart'; import 'view/pages/overhang.dart'; import 'view/pages/talk/chatList.dart'; import 'view/pages/timetable/timetable.dart'; class App extends StatefulWidget { const App({super.key}); @override State createState() => _AppState(); } class _AppState extends State with WidgetsBindingObserver { late Timer refetchChats; late Timer updateTimings; @override void didChangeAppLifecycleState(AppLifecycleState state) { log('AppLifecycle: ${state.toString()}'); if(state == AppLifecycleState.resumed) { EasyThrottle.throttle( 'appLifecycleState', const Duration(seconds: 10), () { log('Refreshing due to LifecycleChange'); NotificationTasks.updateProviders(context); Provider.of(context, listen: false).run(); } ); } } @override void initState() { Main.bottomNavigator = PersistentTabController(initialIndex: 0); WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { Provider.of(context, listen: false).run(); Provider.of(context, listen: false).run(); }); updateTimings = Timer.periodic(const Duration(seconds: 30), (Timer t) => setState((){})); refetchChats = Timer.periodic(const Duration(seconds: 60), (timer) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { Provider.of(context, listen: false).run(); }); }); // User index UpdateUserIndex.index(); // User Notifications if(Provider.of(context, listen: false).val().notificationSettings.enabled) { update() => NotifyUpdater.registerToServer(); FirebaseMessaging.instance.onTokenRefresh.listen((event) => update()); update(); } FirebaseMessaging.onMessage.listen((message) => NotificationController.onForegroundMessageHandler(message, context)); FirebaseMessaging.onBackgroundMessage(NotificationController.onBackgroundMessageHandler); FirebaseMessaging.onMessageOpenedApp.listen((message) => NotificationController.onAppOpenedByNotification(message, context)); FirebaseMessaging.instance.getInitialMessage().then((message) => message == null ? null : NotificationController.onAppOpenedByNotification(message, context)); DataCleaner.cleanOldCache(); super.initState(); } @override Widget build(BuildContext context) => PersistentTabView( controller: Main.bottomNavigator, navBarOverlap: const NavBarOverlap.none(), backgroundColor: Theme.of(context).colorScheme.primary, screenTransitionAnimation: const ScreenTransitionAnimation(curve: Curves.easeOutQuad, duration: Duration(milliseconds: 200)), tabs: [ PersistentTabConfig( screen: const Breaker(breaker: BreakerArea.timetable, child: Timetable()), item: ItemConfig( activeForegroundColor: Theme.of(context).primaryColor, inactiveForegroundColor: Theme.of(context).colorScheme.secondary, icon: const Icon(Icons.calendar_month), title: 'Vertretung' ), ), PersistentTabConfig( screen: const Breaker(breaker: BreakerArea.talk, child: ChatList()), item: ItemConfig( activeForegroundColor: Theme.of(context).primaryColor, inactiveForegroundColor: Theme.of(context).colorScheme.secondary, icon: Consumer( builder: (context, value, child) { if(value.primaryLoading()) return const Icon(Icons.chat); var messages = value.getRoomsResponse.data.map((e) => e.unreadMessages).reduce((a, b) => a+b); return badges.Badge( showBadge: messages > 0, position: badges.BadgePosition.topEnd(top: -3, end: -3), stackFit: StackFit.loose, badgeStyle: badges.BadgeStyle( padding: const EdgeInsets.all(3), badgeColor: Theme.of(context).primaryColor, elevation: 1, ), badgeContent: Text('$messages', style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold)), child: const Icon(Icons.chat), ); }, ), title: 'Talk', ), ), PersistentTabConfig( screen: const Breaker(breaker: BreakerArea.files, child: Files([])), item: ItemConfig( activeForegroundColor: Theme.of(context).primaryColor, inactiveForegroundColor: Theme.of(context).colorScheme.secondary, icon: const Icon(Icons.folder), title: 'Dateien' ), ), PersistentTabConfig( screen: const Breaker(breaker: BreakerArea.more, child: Overhang()), item: ItemConfig( activeForegroundColor: Theme.of(context).primaryColor, inactiveForegroundColor: Theme.of(context).colorScheme.secondary, icon: const Icon(Icons.apps), title: 'Mehr' ), ), ], navBarBuilder: (config) => Style6BottomNavBar( navBarConfig: config, navBarDecoration: NavBarDecoration( border: const Border(top: BorderSide(width: 1, color: Colors.grey)), color: Theme.of(context).colorScheme.surface, ), ), ); @override void dispose() { refetchChats.cancel(); updateTimings.cancel(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } }