diff --git a/lib/calendar_widget.dart b/lib/calendar_widget.dart index 9b549bb..ebc2cd6 100644 --- a/lib/calendar_widget.dart +++ b/lib/calendar_widget.dart @@ -1,4 +1,3 @@ - import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; @@ -198,8 +197,7 @@ class _CalendarWidgetState extends State { }, controller: CalendarController(), appointmentBuilder: (context, calendarAppointmentDetails) { - final Event event = - calendarAppointmentDetails.appointments.first; + final Event event = calendarAppointmentDetails.appointments.first; return Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( @@ -248,7 +246,8 @@ class _CalendarWidgetState extends State { await showNotificationsSettingsModal(context); }, style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, backgroundColor: const Color(0xFF7293E1), + foregroundColor: Colors.white, + backgroundColor: const Color(0xFF7293E1), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10)), ), diff --git a/lib/globals.dart b/lib/globals.dart index 9fa2710..6162a42 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,7 +1,8 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:my_intra/model/event.dart'; + FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); bool adminMode = false; List loadedDates = []; -List loadedEvents = []; \ No newline at end of file +List loadedEvents = []; diff --git a/lib/home.dart b/lib/home.dart index 4aebccd..6bedb27 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -100,8 +100,7 @@ class _HomePageLoggedInState extends State { "check-notifications", "check-notifications-task", constraints: Constraints(networkType: NetworkType.connected), existingWorkPolicy: ExistingWorkPolicy.replace); - Workmanager().registerPeriodicTask( - "check-events", "check-events-task", + Workmanager().registerPeriodicTask("check-events", "check-events-task", constraints: Constraints(networkType: NetworkType.connected), frequency: const Duration(minutes: 15), existingWorkPolicy: ExistingWorkPolicy.replace); @@ -114,11 +113,10 @@ class _HomePageLoggedInState extends State { if (_updateInfo?.updateAvailability == UpdateAvailability.updateAvailable && _updateInfo!.availableVersionCode!.isEven) { - InAppUpdate.performImmediateUpdate() - .onError((e, stack) { - showSnack(e.toString()); - return Future.error(stack); - }); + InAppUpdate.performImmediateUpdate().onError((e, stack) { + showSnack(e.toString()); + return Future.error(stack); + }); } else if (_updateInfo?.updateAvailability == UpdateAvailability.updateAvailable) { InAppUpdate.startFlexibleUpdate(); @@ -262,34 +260,34 @@ Future showDialogConnexionIntra(BuildContext context) async { await Future.delayed(const Duration(microseconds: 1)); if (context.mounted) { return showDialog( - context: context, - barrierDismissible: false, // user must tap button! - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Connexion'), - content: const SingleChildScrollView( - child: ListBody( - children: [ - Text( - 'Since the end of 2022, it is not longer possible to login with an autologin link.'), - Text( - 'Therefore, My Intra uses a cookie system to keep you logged in.'), - Text( - 'For this to work, you need to login to your Intra account, then the application will automatically retrieve the cookie.') - ], - ), - ), - actions: [ - TextButton( - child: const Text('Ok'), - onPressed: () { - Navigator.of(context).pop(); - }, + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Connexion'), + content: const SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Since the end of 2022, it is not longer possible to login with an autologin link.'), + Text( + 'Therefore, My Intra uses a cookie system to keep you logged in.'), + Text( + 'For this to work, you need to login to your Intra account, then the application will automatically retrieve the cookie.') + ], + ), ), - ], - ); - }, - ); + actions: [ + TextButton( + child: const Text('Ok'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); } } diff --git a/lib/main.dart b/lib/main.dart index ce0a228..a97c6ff 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -106,11 +106,7 @@ Future main() async { await globals.flutterLocalNotificationsPlugin.initialize( initializationSettings, onDidReceiveNotificationResponse: onDidReceiveNotificationResponse); - Workmanager().initialize( - callbackDispatcher, - isInDebugMode: - false - ); + Workmanager().initialize(callbackDispatcher, isInDebugMode: false); FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError; await FirebasePerformance.instance.setPerformanceCollectionEnabled(true); runApp(MaterialApp( @@ -121,7 +117,6 @@ Future main() async { home: const HomePage())); } - class LoginIntra extends StatefulWidget { const LoginIntra({super.key}); @@ -172,13 +167,13 @@ class _LoginIntraState extends State { constraints: Constraints(networkType: NetworkType.connected), existingWorkPolicy: ExistingWorkPolicy.replace); - if (context.mounted) { - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => const HomePageLoggedIn()), - ); - } + if (context.mounted) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const HomePageLoggedIn()), + ); + } return; } } diff --git a/lib/model/files.dart b/lib/model/files.dart index 5517fd8..1df006a 100644 --- a/lib/model/files.dart +++ b/lib/model/files.dart @@ -1,21 +1,14 @@ -class File{ +class File { final String name; final String url; final String mime; File({required this.name, required this.url, required this.mime}); Map toJson() { - return { - 'name': name, - 'url': url, - 'mime': mime - }; + return {'name': name, 'url': url, 'mime': mime}; } factory File.fromJson(Map json) { - return File( - name: json['title'], - url: json['fullpath'], - mime: json['mime']); + return File(name: json['title'], url: json['fullpath'], mime: json['mime']); } -} \ No newline at end of file +} diff --git a/lib/notifications_settings.dart b/lib/notifications_settings.dart index 4e19b5c..e0d01a5 100644 --- a/lib/notifications_settings.dart +++ b/lib/notifications_settings.dart @@ -3,86 +3,88 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; Future showNotificationsSettingsModal(BuildContext context) async { - return await showDialog(context: context, builder: (context) { - return AlertDialog( - contentPadding: const EdgeInsets.all(16), - insetPadding: const EdgeInsets.symmetric(horizontal: 0), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - content: SizedBox( - width: 332, - child: FutureBuilder( - future: SharedPreferences.getInstance(), - builder: (context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - int delay = snapshot.data!.getInt("notifications_delay") ?? 5; - return StatefulBuilder( - builder: (context, setState) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 20), - Text( - "Notifications settings", - style: GoogleFonts.openSans( - fontWeight: FontWeight.w700, fontSize: 15), - ), - const SizedBox(height: 30), - Text( - "My Intra can alert you when an event is about to start. You can choose to be alerted 5, 10 or 15 minutes before the event starts.", - style: GoogleFonts.openSans( - fontWeight: FontWeight.w700, fontSize: 15), - ), - const SizedBox(height: 30), - Text( - "Please chose the delay you want:", - style: GoogleFonts.openSans( - fontWeight: FontWeight.w700, fontSize: 15), - ), - const SizedBox(height: 30), - RadioListTile( - title: const Text("5 minutes"), - value: 5, - groupValue: delay, - onChanged: (value) { - snapshot.data!.setInt("notifications_delay", value as int); - delay = value; - setState(() {}); - Navigator.pop(context); - }, - ), - RadioListTile( - title: const Text("10 minutes"), - value: 10, - groupValue: delay, - onChanged: (value) { - snapshot.data!.setInt("notifications_delay", value as int); - delay = value; - setState(() {}); - Navigator.pop(context); - - }, - ), - RadioListTile( - title: const Text("15 minutes"), - value: 15, - groupValue: delay, - onChanged: (value) { - snapshot.data!.setInt("notifications_delay", value as int); - delay = value; - setState(() {}); - Navigator.pop(context); - - }, - ), - ],); - } - ); - } else { - return const Center(child: CircularProgressIndicator()); - } - } - ) - )); - }); -} \ No newline at end of file + return await showDialog( + context: context, + builder: (context) { + return AlertDialog( + contentPadding: const EdgeInsets.all(16), + insetPadding: const EdgeInsets.symmetric(horizontal: 0), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + content: SizedBox( + width: 332, + child: FutureBuilder( + future: SharedPreferences.getInstance(), + builder: + (context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + int delay = + snapshot.data!.getInt("notifications_delay") ?? 5; + return StatefulBuilder(builder: (context, setState) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 20), + Text( + "Notifications settings", + style: GoogleFonts.openSans( + fontWeight: FontWeight.w700, fontSize: 15), + ), + const SizedBox(height: 30), + Text( + "My Intra can alert you when an event is about to start. You can choose to be alerted 5, 10 or 15 minutes before the event starts.", + style: GoogleFonts.openSans( + fontWeight: FontWeight.w700, fontSize: 15), + ), + const SizedBox(height: 30), + Text( + "Please chose the delay you want:", + style: GoogleFonts.openSans( + fontWeight: FontWeight.w700, fontSize: 15), + ), + const SizedBox(height: 30), + RadioListTile( + title: const Text("5 minutes"), + value: 5, + groupValue: delay, + onChanged: (value) { + snapshot.data!.setInt( + "notifications_delay", value as int); + delay = value; + setState(() {}); + Navigator.pop(context); + }, + ), + RadioListTile( + title: const Text("10 minutes"), + value: 10, + groupValue: delay, + onChanged: (value) { + snapshot.data!.setInt( + "notifications_delay", value as int); + delay = value; + setState(() {}); + Navigator.pop(context); + }, + ), + RadioListTile( + title: const Text("15 minutes"), + value: 15, + groupValue: delay, + onChanged: (value) { + snapshot.data!.setInt( + "notifications_delay", value as int); + delay = value; + setState(() {}); + Navigator.pop(context); + }, + ), + ], + ); + }); + } else { + return const Center(child: CircularProgressIndicator()); + } + }))); + }); +} diff --git a/lib/notifications_widget.dart b/lib/notifications_widget.dart index 6f8b3fa..bd51ebc 100644 --- a/lib/notifications_widget.dart +++ b/lib/notifications_widget.dart @@ -40,7 +40,7 @@ class _NotificationsWidgetState extends State { if (widget.notifications != null) { widget.notifications!.then((value) { for (var element in value) { - element.read = true; + element.read = true; } }); List> mapList = []; @@ -283,11 +283,11 @@ class _NotificationsWidgetState extends State { if (result) { if (context.mounted) { ScaffoldMessenger.of(context) - .showSnackBar( - const SnackBar( - content: Text( - "You have been registered !")), - ); + .showSnackBar( + const SnackBar( + content: Text( + "You have been registered !")), + ); } setState(() { widget.projects = getProjectData(); @@ -295,11 +295,11 @@ class _NotificationsWidgetState extends State { } else { if (context.mounted) { ScaffoldMessenger.of(context) - .showSnackBar( - const SnackBar( - content: - Text("An error occured.")), - ); + .showSnackBar( + const SnackBar( + content: + Text("An error occured.")), + ); } } }, diff --git a/lib/onboarding.dart b/lib/onboarding.dart index d8cc4c0..668d6f6 100644 --- a/lib/onboarding.dart +++ b/lib/onboarding.dart @@ -51,11 +51,10 @@ class _OnboardingWidgetState extends State { if (_updateInfo?.updateAvailability == UpdateAvailability.updateAvailable && _updateInfo!.availableVersionCode!.isEven) { - InAppUpdate.performImmediateUpdate() - .onError((e, stack){ - showSnack(e.toString()); - return Future.error(stack); - }); + InAppUpdate.performImmediateUpdate().onError((e, stack) { + showSnack(e.toString()); + return Future.error(stack); + }); } else if (_updateInfo?.updateAvailability == UpdateAvailability.updateAvailable) { InAppUpdate.startFlexibleUpdate(); @@ -169,36 +168,36 @@ class _OnboardingWidgetState extends State { await Future.delayed(const Duration(microseconds: 1)); if (context.mounted) { return showDialog( - context: context, - barrierDismissible: false, // user must tap button! - builder: (BuildContext context) { - return AlertDialog( - title: const Text('New Update'), - content: const SingleChildScrollView( - child: ListBody( - children: [ - Text( - 'Because of a radical change to the login process of the Intranet, the old app was not working anymore'), - Text( - 'We decided to recode My Intra from scratch, and releasing the app to iOS.'), - Text( - 'The app will have new features and a way better design. We are planning on releasing it in the next few weeks.'), - Text( - 'In the meantime we have pushed this version of the app so that you will be notified when the new app will be released with a built-in update feature.') - ], + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('New Update'), + content: const SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Because of a radical change to the login process of the Intranet, the old app was not working anymore'), + Text( + 'We decided to recode My Intra from scratch, and releasing the app to iOS.'), + Text( + 'The app will have new features and a way better design. We are planning on releasing it in the next few weeks.'), + Text( + 'In the meantime we have pushed this version of the app so that you will be notified when the new app will be released with a built-in update feature.') + ], + ), ), - ), - actions: [ - TextButton( - child: const Text('Ok'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); + actions: [ + TextButton( + child: const Text('Ok'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); } } @@ -209,60 +208,60 @@ class _OnboardingWidgetState extends State { final formKey = GlobalKey(); if (context.mounted) { await showDialog( - context: context, - barrierDismissible: false, // user must tap button! - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Login'), - content: SingleChildScrollView( - child: Column( - children: [ - Form( - key: formKey, - child: TextFormField( - controller: field, - decoration: const InputDecoration( - icon: Icon(Icons.login), - hintText: 'Login value', - labelText: 'Login', + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Login'), + content: SingleChildScrollView( + child: Column( + children: [ + Form( + key: formKey, + child: TextFormField( + controller: field, + decoration: const InputDecoration( + icon: Icon(Icons.login), + hintText: 'Login value', + labelText: 'Login', + ), + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, ), - validator: (String? value) { - if (value == null || value.isEmpty) { - return 'Please enter some text'; - } - return null; - }, - ), - ) - ], + ) + ], + ), ), - ), - actions: [ - TextButton( - child: const Text('Ok'), - onPressed: () { - if (formKey.currentState!.validate()) { - // If the form is valid, display a snackbar. In the real world, - // you'd often call a server or save the information in a database. - if (field.text == "CorentinTuCassesLesCouilles") { - res = true; - } else { - res = false; + actions: [ + TextButton( + child: const Text('Ok'), + onPressed: () { + if (formKey.currentState!.validate()) { + // If the form is valid, display a snackbar. In the real world, + // you'd often call a server or save the information in a database. + if (field.text == "CorentinTuCassesLesCouilles") { + res = true; + } else { + res = false; + } + Navigator.of(context).pop(); } + }, + ), + TextButton( + child: const Text('Cancel'), + onPressed: () { Navigator.of(context).pop(); - } - }, - ), - TextButton( - child: const Text('Cancel'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); + }, + ), + ], + ); + }, + ); } return res; } diff --git a/lib/utils/check_for_events.dart b/lib/utils/check_for_events.dart index 6c84ee7..6dd8ac4 100644 --- a/lib/utils/check_for_events.dart +++ b/lib/utils/check_for_events.dart @@ -4,22 +4,22 @@ import 'package:html/parser.dart'; import 'package:my_intra/utils/get_events.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:my_intra/globals.dart' as globals; + Future checkForEvents() async { var sharedPrefs = await SharedPreferences.getInstance(); int delay = sharedPrefs.getInt("notifications_delay") ?? 5; var alertedEvents = sharedPrefs.getStringList("alerted_events") ?? []; DateTime now = DateTime.now(); var events = await getEventsForDate(now, now); - const AndroidNotificationDetails androidNotificationDetails = - AndroidNotificationDetails('alerts', 'Alerts Notifications', - channelDescription: - 'Notifications for the alerts of the Intra', - importance: Importance.defaultImportance, - styleInformation: BigTextStyleInformation(''), - priority: Priority.defaultPriority, - ticker: 'ticker'); - const NotificationDetails notificationDetails = - NotificationDetails(android: androidNotificationDetails); + const AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails('alerts', 'Alerts Notifications', + channelDescription: 'Notifications for the alerts of the Intra', + importance: Importance.defaultImportance, + styleInformation: BigTextStyleInformation(''), + priority: Priority.defaultPriority, + ticker: 'ticker'); + const NotificationDetails notificationDetails = + NotificationDetails(android: androidNotificationDetails); for (var event in events) { String codeEvt = event.codeevent!.replaceAll("event-", ""); if (event.start.difference(now).inMinutes > delay) { @@ -28,15 +28,15 @@ Future checkForEvents() async { if (alertedEvents.contains(codeEvt)) { continue; } - await globals.flutterLocalNotificationsPlugin.show( - int.parse(codeEvt), - 'Activity starts in ${event.start.difference(now).inMinutes} minutes', - parseFragment(event.actiTitle).text, - notificationDetails, - payload: 'alert-notif'); + await globals.flutterLocalNotificationsPlugin.show( + int.parse(codeEvt), + 'Activity starts in ${event.start.difference(now).inMinutes} minutes', + parseFragment(event.actiTitle).text, + notificationDetails, + payload: 'alert-notif'); alertedEvents.add(codeEvt); } await sharedPrefs.setStringList("alerted_events", alertedEvents); debugPrint(alertedEvents.toString()); return true; -} \ No newline at end of file +}