import 'dart:io'; import 'dart:math'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:filcnaplo/api/client.dart'; import 'package:filcnaplo/api/providers/ad_provider.dart'; import 'package:filcnaplo/api/providers/live_card_provider.dart'; import 'package:filcnaplo/api/providers/news_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/status_provider.dart'; import 'package:filcnaplo/models/config.dart'; import 'package:filcnaplo/theme/observer.dart'; import 'package:filcnaplo/theme/theme.dart'; import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; import 'package:filcnaplo_premium/providers/goal_provider.dart'; import 'package:filcnaplo_premium/providers/share_provider.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:i18n_extension/i18n_widget.dart'; import 'package:material_color_utilities/palettes/core_palette.dart'; import 'package:provider/provider.dart'; // Mobile UI import 'package:filcnaplo_mobile_ui/common/system_chrome.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/login/login_route.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/login/login_screen.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/settings/settings_route.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart' as mobile; // Desktop UI import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_screen.dart' as desktop; import 'package:filcnaplo_desktop_ui/screens/login/login_screen.dart' as desktop; import 'package:filcnaplo_desktop_ui/screens/login/login_route.dart' as desktop; // Providers 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/homework_provider.dart'; import 'package:filcnaplo_kreta_api/providers/message_provider.dart'; import 'package:filcnaplo_kreta_api/providers/note_provider.dart'; import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/update_provider.dart'; import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:filcnaplo_premium/providers/premium_provider.dart'; class App extends StatelessWidget { final SettingsProvider settings; final UserProvider user; final DatabaseProvider database; const App( {Key? key, required this.database, required this.settings, required this.user}) : super(key: key); @override Widget build(BuildContext context) { mobile.setSystemChrome(context); // Set high refresh mode #28 if (Platform.isAndroid) FlutterDisplayMode.setHighRefreshRate(); CorePalette? corePalette; final status = StatusProvider(); final kreta = KretaClient(user: user, settings: settings, status: status); final timetable = TimetableProvider(user: user, database: database, kreta: kreta); final premium = PremiumProvider(settings: settings); WidgetsBinding.instance.addPostFrameCallback((_) { FilcAPI.getConfig(settings).then((Config? config) { if (config != null) settings.update(config: config); }); premium.activate(); }); return MultiProvider( providers: [ // refilc providers ChangeNotifierProvider(create: (_) => premium), ChangeNotifierProvider(create: (_) => settings), ChangeNotifierProvider(create: (_) => user), ChangeNotifierProvider(create: (_) => status), Provider(create: (_) => kreta), Provider(create: (context) => database), ChangeNotifierProvider( create: (context) => ThemeModeObserver( initialTheme: settings.theme, ), ), ChangeNotifierProvider( create: (context) => NewsProvider(context: context), ), ChangeNotifierProvider( create: (context) => UpdateProvider(context: context), ), ChangeNotifierProvider( create: (context) => AdProvider(context: context), ), // user data (kreten) providers ChangeNotifierProvider( create: (_) => GradeProvider( settings: settings, user: user, database: database, kreta: kreta, ), ), ChangeNotifierProvider(create: (_) => timetable), ChangeNotifierProvider( create: (context) => ExamProvider(context: context), ), ChangeNotifierProvider( create: (context) => HomeworkProvider( context: context, database: database, user: user, ), ), ChangeNotifierProvider( create: (context) => MessageProvider(context: context), ), ChangeNotifierProvider( create: (context) => NoteProvider(context: context), ), ChangeNotifierProvider( create: (context) => EventProvider(context: context), ), ChangeNotifierProvider( create: (context) => AbsenceProvider(context: context), ), // other providers ChangeNotifierProvider( create: (_) => GradeCalculatorProvider( settings: settings, user: user, database: database, kreta: kreta, ), ), ChangeNotifierProvider( create: (context) => LiveCardProvider( timetable: timetable, settings: settings, ), ), ChangeNotifierProvider( create: (context) => GoalProvider( database: database, user: user, ), ), ChangeNotifierProvider( create: (context) => ShareProvider( user: user, ), ), ], child: Consumer( builder: (context, themeMode, child) { return FutureBuilder( future: DynamicColorPlugin.getCorePalette(), builder: (context, snapshot) { corePalette = snapshot.data; return MaterialApp( builder: (context, child) { // Limit font size scaling to 1.0 double textScaleFactor = min(MediaQuery.of(context).textScaleFactor, 1.0); return I18n( initialLocale: Locale( settings.language, settings.language.toUpperCase()), child: MediaQuery( data: MediaQuery.of(context) .copyWith(textScaleFactor: textScaleFactor), child: child ?? Container(), ), ); }, title: "reFilc", debugShowCheckedModeBanner: false, theme: AppTheme.lightTheme(context, palette: corePalette), darkTheme: AppTheme.darkTheme(context, palette: corePalette), themeMode: themeMode.themeMode, localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', 'EN'), Locale('hu', 'HU'), Locale('de', 'DE'), ], localeListResolutionCallback: (locales, supported) { Locale locale = const Locale('hu', 'HU'); for (var loc in locales ?? []) { if (supported.contains(loc)) { locale = loc; break; } } return locale; }, onGenerateRoute: (settings) => rootNavigator(settings), initialRoute: user.getUsers().isNotEmpty ? "navigation" : "login", ); }, ); }, ), ); } Route? rootNavigator(RouteSettings route) { if (kIsWeb) { switch (route.name) { case "login_back": return CupertinoPageRoute( builder: (context) => const desktop.LoginScreen(back: true)); case "login": return _rootRoute(const desktop.LoginScreen()); case "navigation": return _rootRoute(const desktop.NavigationScreen()); case "login_to_navigation": return desktop.loginRoute(const desktop.NavigationScreen()); } } else if (Platform.isAndroid || Platform.isIOS) { switch (route.name) { case "login_back": return CupertinoPageRoute( builder: (context) => const mobile.LoginScreen(back: true)); case "login": return _rootRoute(const mobile.LoginScreen()); case "navigation": return _rootRoute(const mobile.NavigationScreen()); case "login_to_navigation": return mobile.loginRoute(const mobile.NavigationScreen()); case "settings": return mobile.settingsRoute(const mobile.SettingsScreen()); } } else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) { switch (route.name) { case "login_back": return CupertinoPageRoute( builder: (context) => const desktop.LoginScreen(back: true)); case "login": return _rootRoute(const desktop.LoginScreen()); case "navigation": return _rootRoute(const desktop.NavigationScreen()); case "login_to_navigation": return desktop.loginRoute(const desktop.NavigationScreen()); } } return null; } Route _rootRoute(Widget widget) { return PageRouteBuilder(pageBuilder: (context, _, __) => widget); } }