// ignore_for_file: dead_code import 'dart:math'; import 'package:filcnaplo/api/providers/live_card_provider.dart'; import 'package:filcnaplo/ui/date_widget.dart'; import 'package:filcnaplo_premium/providers/premium_provider.dart'; import 'package:animated_list_plus/animated_list_plus.dart'; import 'package:filcnaplo/api/providers/update_provider.dart'; import 'package:filcnaplo/api/providers/sync.dart'; import 'package:confetti/confetti.dart'; import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo_kreta_api/providers/absence_provider.dart'; import 'package:filcnaplo_kreta_api/providers/event_provider.dart'; import 'package:filcnaplo_kreta_api/providers/exam_provider.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; import 'package:filcnaplo_kreta_api/providers/homework_provider.dart'; import 'package:filcnaplo_kreta_api/providers/message_provider.dart'; import 'package:filcnaplo_kreta_api/providers/note_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/status_provider.dart'; import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; import 'package:filcnaplo_mobile_ui/common/empty.dart'; import 'package:filcnaplo_mobile_ui/common/filter_bar.dart'; import 'package:filcnaplo_mobile_ui/common/profile_image/profile_button.dart'; import 'package:filcnaplo_mobile_ui/common/profile_image/profile_image.dart'; import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.dart'; import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'home_page.i18n.dart'; import 'package:filcnaplo/ui/filter/widgets.dart'; import 'package:filcnaplo/ui/filter/sort.dart'; import 'package:i18n_extension/i18n_extension.dart'; class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State with TickerProviderStateMixin { late TabController _tabController; late UserProvider user; late SettingsProvider settings; late UpdateProvider updateProvider; late StatusProvider statusProvider; late GradeProvider gradeProvider; late TimetableProvider timetableProvider; late MessageProvider messageProvider; late AbsenceProvider absenceProvider; late HomeworkProvider homeworkProvider; late ExamProvider examProvider; late NoteProvider noteProvider; late EventProvider eventProvider; late PageController _pageController; ConfettiController? _confettiController; late LiveCardProvider _liveCard; late AnimationController _liveCardAnimation; late String greeting; late String firstName; late List listOrder; static const pageCount = 4; @override void initState() { super.initState(); _tabController = TabController(length: pageCount, vsync: this); _pageController = PageController(); user = Provider.of(context, listen: false); _liveCard = Provider.of(context, listen: false); _liveCardAnimation = AnimationController( vsync: this, duration: const Duration(milliseconds: 500)); _liveCardAnimation.animateTo(_liveCard.show ? 1.0 : 0.0, duration: Duration.zero); listOrder = List.generate(pageCount, (index) => "$index"); } @override void dispose() { // _filterController.dispose(); _pageController.dispose(); _tabController.dispose(); _confettiController?.dispose(); _liveCardAnimation.dispose(); super.dispose(); } void setGreeting() { DateTime now = DateTime.now(); List nameParts = user.displayName?.split(" ") ?? ["?"]; if (!settings.presentationMode) { firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; } else { firstName = "János"; } bool customWelcome = false; if (now.isBefore(DateTime(now.year, DateTime.august, 31)) && now.isAfter(DateTime(now.year, DateTime.june, 14))) { greeting = "goodrest"; if (NavigationScreen.of(context)?.init("confetti") ?? false) { _confettiController = ConfettiController(duration: const Duration(seconds: 1)); Future.delayed(const Duration(seconds: 1)) .then((value) => mounted ? _confettiController?.play() : null); } } else if (now.month == user.student?.birth.month && now.day == user.student?.birth.day) { greeting = "happybirthday"; if (NavigationScreen.of(context)?.init("confetti") ?? false) { _confettiController = ConfettiController(duration: const Duration(seconds: 3)); Future.delayed(const Duration(seconds: 1)) .then((value) => mounted ? _confettiController?.play() : null); } } else if (now.isAfter(DateTime(now.year, DateTime.may, 28)) && now.isBefore(DateTime(now.year, DateTime.may, 30))) { greeting = "refilcopen"; if (NavigationScreen.of(context)?.init("confetti") ?? false) { _confettiController = ConfettiController(duration: const Duration(seconds: 3)); Future.delayed(const Duration(seconds: 1)) .then((value) => mounted ? _confettiController?.play() : null); } } else if (now.month == DateTime.december && now.day >= 24 && now.day <= 26) { greeting = "merryxmas"; } else if (now.month == DateTime.january && now.day == 1) { greeting = "happynewyear"; } else if (settings.welcomeMessage.replaceAll(' ', '') != '') { greeting = settings.welcomeMessage; greeting = localizeFill( settings.welcomeMessage, [firstName], ); customWelcome = true; } else if (now.hour >= 18) { greeting = "goodevening"; } else if (now.hour >= 10) { greeting = "goodafternoon"; } else if (now.hour >= 4) { greeting = "goodmorning"; } else { greeting = "goodevening"; } greeting = customWelcome ? greeting : greeting.i18n.fill([firstName]); } @override Widget build(BuildContext context) { user = Provider.of(context); settings = Provider.of(context); statusProvider = Provider.of(context, listen: false); updateProvider = Provider.of(context); _liveCard = Provider.of(context); gradeProvider = Provider.of(context); context.watch(); _liveCardAnimation.animateTo(_liveCard.show ? 1.0 : 0.0); setGreeting(); return Scaffold( body: Stack( children: [ Padding( padding: const EdgeInsets.only(top: 12.0), child: NestedScrollView( physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics()), headerSliverBuilder: (context, _) => [ AnimatedBuilder( animation: _liveCardAnimation, builder: (context, child) { return SliverAppBar( automaticallyImplyLeading: false, surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, centerTitle: false, titleSpacing: 0.0, // Welcome text title: Padding( padding: const EdgeInsets.only(left: 24.0), child: Text( greeting, overflow: TextOverflow.fade, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18.0, color: Theme.of(context) .textTheme .bodyMedium ?.color, ), ), ), actions: [ // Profile Icon Padding( padding: const EdgeInsets.only(right: 24.0), child: ProfileButton( child: ProfileImage( heroTag: "profile", name: firstName, backgroundColor: Theme.of(context) .colorScheme .primary, //!settings.presentationMode //? ColorUtils.stringToColor(user.displayName ?? "?") //: Theme.of(context).colorScheme.secondary, badge: updateProvider.available, role: user.role, profilePictureString: user.picture, ), ), ), ], expandedHeight: _liveCardAnimation.value * 234.0, // Live Card flexibleSpace: FlexibleSpaceBar( background: Padding( padding: EdgeInsets.only( left: 24.0, right: 24.0, top: 58.0 + MediaQuery.of(context).padding.top, bottom: 52.0, ), child: Transform.scale( scale: _liveCardAnimation.value, child: Opacity( opacity: _liveCardAnimation.value, child: const LiveCard(), ), ), ), ), shadowColor: Colors.black, // Filter Bar bottom: FilterBar( items: [ Tab(text: "All".i18n), Tab(text: "Grades".i18n), Tab(text: "Messages".i18n), Tab(text: "Absences".i18n), ], controller: _tabController, disableFading: true, onTap: (i) async { int selectedPage = _pageController.page!.round(); if (i == selectedPage) return; if (_pageController.page?.roundToDouble() != _pageController.page) { _pageController.animateToPage(i, curve: Curves.easeIn, duration: kTabScrollDuration); return; } // swap current page with target page setState(() { _pageController.jumpToPage(i); String currentList = listOrder[selectedPage]; listOrder[selectedPage] = listOrder[i]; listOrder[i] = currentList; }); }, ), pinned: true, floating: false, snap: false, ); }, ), ], body: Padding( padding: const EdgeInsets.only(top: 12.0), child: NotificationListener( onNotification: (notification) { // from flutter source if (notification is ScrollUpdateNotification && !_tabController.indexIsChanging) { if ((_pageController.page! - _tabController.index) .abs() > 1.0) { _tabController.index = _pageController.page!.floor(); } _tabController.offset = (_pageController.page! - _tabController.index) .clamp(-1.0, 1.0); } else if (notification is ScrollEndNotification) { _tabController.index = _pageController.page!.round(); if (!_tabController.indexIsChanging) { _tabController.offset = (_pageController.page! - _tabController.index) .clamp(-1.0, 1.0); } } return false; }, child: PageView.custom( controller: _pageController, childrenDelegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return FutureBuilder>( key: ValueKey(listOrder[index]), future: getFilterWidgets(homeFilters[index], context: context), builder: (context, dateWidgets) => dateWidgets .data != null ? RefreshIndicator( color: Theme.of(context).colorScheme.secondary, onRefresh: () => syncAll(context), child: ImplicitlyAnimatedList( items: [ if (index == 0) const SizedBox(key: Key("\$premium")), ...sortDateWidgets(context, dateWidgets: dateWidgets.data!), ], itemBuilder: filterItemBuilder, spawnIsolate: false, areItemsTheSame: (a, b) => a.key == b.key, physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics()), padding: const EdgeInsets.symmetric( horizontal: 24.0), )) : Container(), ); }, childCount: 4, findChildIndexCallback: (Key key) { final ValueKey valueKey = key as ValueKey; final String data = valueKey.value; return listOrder.indexOf(data); }, ), physics: const PageScrollPhysics() .applyTo(const BouncingScrollPhysics()), ), ), )), ), // confetti 🎊 if (_confettiController != null) Align( alignment: Alignment.topCenter, child: ConfettiWidget( confettiController: _confettiController!, blastDirectionality: BlastDirectionality.explosive, emissionFrequency: 0.02, numberOfParticles: 120, maxBlastForce: 20, minBlastForce: 10, gravity: 0.3, minimumSize: const Size(5, 5), maximumSize: const Size(20, 20), ), ), ], ), ); } Future filterViewBuilder(context, int activeData) async { final activeFilter = homeFilters[activeData]; List filterWidgets = sortDateWidgets( context, dateWidgets: await getFilterWidgets(activeFilter, context: context), showDivider: true, ); return Padding( padding: const EdgeInsets.only(top: 12.0), child: RefreshIndicator( color: Theme.of(context).colorScheme.secondary, onRefresh: () => syncAll(context), child: ListView.builder( padding: EdgeInsets.zero, physics: const BouncingScrollPhysics(), itemBuilder: (context, index) { if (filterWidgets.isNotEmpty) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: filterWidgets[index], ); } else { return Empty(subtitle: "empty".i18n); } }, itemCount: max(filterWidgets.length, 1), ), ), ); } }