From afb19f394c5c871d9ebaf96e3535e2c567c72f04 Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 17:48:08 +0100 Subject: [PATCH 01/11] Fix formatting --- lib/grades.dart | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/grades.dart b/lib/grades.dart index 1d14155..6d77b1f 100644 --- a/lib/grades.dart +++ b/lib/grades.dart @@ -103,13 +103,14 @@ class GradesPageState extends BaseState { ), ), Padding( - padding: const EdgeInsets.only(top: 40), - child: RefreshIndicator( - onRefresh: _pullRefresh, - child: ListView( - children: rows, - ), - )), + padding: const EdgeInsets.only(top: 40), + child: RefreshIndicator( + onRefresh: _pullRefresh, + child: ListView( + children: rows, + ), + ), + ), ], ), ), From 6adf29412dbb9271a1cb4b1f3b5ada60ec8f9d4b Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 17:48:23 +0100 Subject: [PATCH 02/11] Add grades button --- lib/home.dart | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/home.dart b/lib/home.dart index fae73fe..a6b6556 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -613,6 +613,29 @@ class HomePageState extends BaseState { ), ), ), + Container( + width: MediaQuery.of(context).size.width, + margin: const EdgeInsets.only(left: 20, right: 20, top: 10), + child: Card( + elevation: 5, + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Grades", + style: const TextStyle(fontSize: 20), + ), + Text( + "Check your grades", + style: const TextStyle(fontSize: 12), + ), + ], + ), + ), + ), + ), ], ), ], From bf4e7f023fc5af0fb33b921c5f4586f616e85ba1 Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 18:32:25 +0100 Subject: [PATCH 03/11] Fix analyze issues, add new notifications --- lib/create_message.dart | 55 ++++++++++++++++++++++++++++++++++++----- lib/icanteen_setup.dart | 7 +++--- lib/l10n/app_en.arb | 6 +++++ lib/main.dart | 36 ++++++++++++++------------- pubspec.lock | 32 ++++++++++++++++++++++++ pubspec.yaml | 1 + 6 files changed, 111 insertions(+), 26 deletions(-) diff --git a/lib/create_message.dart b/lib/create_message.dart index 29b3a73..9c83221 100644 --- a/lib/create_message.dart +++ b/lib/create_message.dart @@ -5,6 +5,7 @@ import 'package:eduapge2/api.dart'; import 'package:eduapge2/main.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:toastification/toastification.dart'; class SendMessageScreen extends StatefulWidget { const SendMessageScreen({super.key}); @@ -51,7 +52,7 @@ class SendMessageScreenState extends BaseState { loc = AppLocalizations.of(context); return PopScope( canPop: message.isEmpty, - onPopInvoked: (didPop) { + onPopInvokedWithResult: (didPop, dynamic _) { if (didPop) { return; } @@ -317,6 +318,24 @@ class SendMessageScreenState extends BaseState { final messageOptionsJson = jsonEncode(messageOptions); + Navigator.of(context).pop(); + + toastification.show( + type: ToastificationType.info, + style: ToastificationStyle.flat, + title: Text(loc!.createMessageNotifSending), + description: Text(loc!.createMessageNotifSendingBody), + alignment: Alignment.bottomCenter, + autoCloseDuration: const Duration(seconds: 2), + icon: Icon(Icons.send_rounded), + borderRadius: BorderRadius.circular(12.0), + boxShadow: highModeShadow, + showProgressBar: true, + closeButtonShowType: CloseButtonShowType.none, + closeOnClick: false, + applyBlurEffect: true, + ); + data.dio .post( "${data.baseUrl}/api/message", @@ -330,13 +349,37 @@ class SendMessageScreenState extends BaseState { ), ) .then((response) { - Navigator.of(context).pop(); + toastification.show( + type: ToastificationType.success, + style: ToastificationStyle.flat, + title: Text(loc!.createMessageNotifSent), + description: Text(loc!.createMessageNotifSentBody), + alignment: Alignment.bottomCenter, + autoCloseDuration: const Duration(seconds: 4), + icon: Icon(Icons.check), + borderRadius: BorderRadius.circular(12.0), + boxShadow: highModeShadow, + showProgressBar: true, + closeButtonShowType: CloseButtonShowType.none, + closeOnClick: false, + applyBlurEffect: true, + ); }).catchError((error) { - final snackBar = SnackBar( - content: Text(error.toString()), + toastification.show( + type: ToastificationType.error, + style: ToastificationStyle.flat, + title: Text(loc!.createMessageNotifError), + description: Text(loc!.createMessageNotifErrorBody), + alignment: Alignment.bottomCenter, + autoCloseDuration: const Duration(seconds: 4), + icon: Icon(Icons.cancel), + borderRadius: BorderRadius.circular(12.0), + boxShadow: highModeShadow, + showProgressBar: true, + closeButtonShowType: CloseButtonShowType.none, + closeOnClick: false, + applyBlurEffect: true, ); - - ScaffoldMessenger.of(context).showSnackBar(snackBar); }); }, child: Text(loc!.createMessageSend), diff --git a/lib/icanteen_setup.dart b/lib/icanteen_setup.dart index 2139a88..d2e70d0 100644 --- a/lib/icanteen_setup.dart +++ b/lib/icanteen_setup.dart @@ -31,7 +31,7 @@ class ICanteenSetupScreenState extends BaseState { String server = ""; bool showPassword = false; - Future login() async { + void login() { setState(() { hasLogin = true; }); @@ -107,8 +107,9 @@ class ICanteenSetupScreenState extends BaseState { onPressed: () => { if (!hasLogin) { - login().then((value) => - {Navigator.pop(context), widget.loadedCallback()}) + login(), + Navigator.pop(context), + widget.loadedCallback(), }, }, child: !hasLogin diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3e91a08..1cc2e82 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -72,6 +72,12 @@ "createMessageErrorSelectRecipient": "Please select a recipient", "createMessageErrorNoMessage": "Please write a message", "createMessageSend": "Send", + "createMessageNotifSending": "Sending message", + "createMessageNotifSendingBody": "Your message is being sent...", + "createMessageNotifSent": "Sent message", + "createMessageNotifSentBody": "Your message was sent successfully", + "createMessageNotifError": "Error", + "createMessageNotifErrorBody": "There was an issue sending your message, it has been reported!", "qrLoginPleaseLogin": "EduPage2 QR Login", "qrLoginUseExistingCredentials": "You are about to login to EduPage2 using a QR code" } diff --git a/lib/main.dart b/lib/main.dart index 923b0c5..30ee332 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -22,6 +22,7 @@ import 'home.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:firebase_core/firebase_core.dart'; import 'firebase_options.dart'; +import 'package:toastification/toastification.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -82,22 +83,24 @@ class MyApp extends StatelessWidget { DeviceOrientation.portraitDown, ]); return DynamicColorBuilder(builder: (lightColorScheme, darkColorScheme) { - return MaterialApp( - title: 'EduPage2', - navigatorKey: navigatorKey, - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - navigatorObservers: [SentryNavigatorObserver(), observer], - theme: ThemeData( - colorScheme: lightColorScheme ?? _defaultLightColorScheme, - useMaterial3: true, - ), - darkTheme: ThemeData( - colorScheme: darkColorScheme ?? _defaultDarkColorScheme, - useMaterial3: true, + return ToastificationWrapper( + child: MaterialApp( + title: 'EduPage2', + navigatorKey: navigatorKey, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + navigatorObservers: [SentryNavigatorObserver(), observer], + theme: ThemeData( + colorScheme: lightColorScheme ?? _defaultLightColorScheme, + useMaterial3: true, + ), + darkTheme: ThemeData( + colorScheme: darkColorScheme ?? _defaultDarkColorScheme, + useMaterial3: true, + ), + themeMode: ThemeMode.dark, + home: const PageBase(), ), - themeMode: ThemeMode.dark, - home: const PageBase(), ); }); } @@ -188,8 +191,7 @@ class PageBaseState extends BaseState { }); // Ask the Shorebird servers if there is a new patch available. - final isUpdateAvailable = - await _shorebirdCodePush.checkForUpdate(); + final isUpdateAvailable = await _shorebirdCodePush.checkForUpdate(); if (!mounted) return; diff --git a/pubspec.lock b/pubspec.lock index b6d68a4..7795de5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -145,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.7.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -391,6 +399,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + iconsax_flutter: + dependency: transitive + description: + name: iconsax_flutter + sha256: "95b65699da8ea98f87c5d232f06b0debaaf1ec1332b697e4d90969ec9a93037d" + url: "https://pub.dev" + source: hosted + version: "1.0.0" in_app_update: dependency: "direct main" description: @@ -572,6 +588,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pausable_timer: + dependency: transitive + description: + name: pausable_timer + sha256: "6ef1a95441ec3439de6fb63f39a011b67e693198e7dae14e20675c3c00e86074" + url: "https://pub.dev" + source: hosted + version: "3.1.0+3" petitparser: dependency: transitive description: @@ -817,6 +841,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + toastification: + dependency: "direct main" + description: + name: toastification + sha256: "4d97fbfa463dfe83691044cba9f37cb185a79bb9205cfecb655fa1f6be126a13" + url: "https://pub.dev" + source: hosted + version: "2.3.0" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 93098d4..5dfc42a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: install_referrer: ^1.2.1 in_app_update: ^4.2.2 app_links: ^6.1.1 + toastification: ^2.3.0 dev_dependencies: integration_test: sdk: flutter From a19f6114f8ee298f7e07dff9be923b7a8bf4370e Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 18:34:44 +0100 Subject: [PATCH 04/11] Add czech translation for notifications --- lib/l10n/app_cs.arb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index 3a60312..cff31cd 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -140,6 +140,12 @@ "createMessageErrorSelectRecipient": "Vyberte prosím příjemce", "createMessageErrorNoMessage": "Napište prosím zprávu", "createMessageSend": "Odeslat", + "createMessageNotifSending": "Odesílání zprávy", + "createMessageNotifSendingBody": "Vaše zpráva se odesílá", + "createMessageNotifSent": "Zpráva odeslána", + "createMessageNotifSentBody": "Vaše zpráva se odeslala úspěšně", + "createMessageNotifError": "Chyba", + "createMessageNotifErrorBody": "Při odesílání zprávy se vyskytla chyba, tato chyba byla nahlášena.", "qrLoginPleaseLogin": "EduPage2 QR Přihlášení", "qrLoginUseExistingCredentials": "Chystáte se přihlásit pomocí QR kódu" } From 70c68edbb46aa183bee00809d7c37e25ce90a9bd Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 20:24:54 +0100 Subject: [PATCH 05/11] Update to support latest API --- lib/grades.dart | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/grades.dart b/lib/grades.dart index 6d77b1f..88c016a 100644 --- a/lib/grades.dart +++ b/lib/grades.dart @@ -1,3 +1,4 @@ +import 'package:eduapge2/api.dart'; import 'package:eduapge2/main.dart'; import 'package:flutter/material.dart'; import 'package:flutter_session_manager/flutter_session_manager.dart'; @@ -14,14 +15,14 @@ class GradesPage extends StatefulWidget { class GradesPageState extends BaseState { bool loading = true; - late List apidataMsg; + late List apidataMsg; late Widget messages; @override void initState() { - getData(); //fetching data super.initState(); + getData(); } getData() async { @@ -29,7 +30,7 @@ class GradesPageState extends BaseState { loading = true; //make loading true to show progressindicator }); - apidataMsg = await widget.sessionManager.get('messages'); + apidataMsg = EP2Data.getInstance().timeline.items.values.toList(); messages = getMessages(apidataMsg); loading = false; @@ -63,19 +64,12 @@ class GradesPageState extends BaseState { setState(() {}); //refresh UI } - Widget getMessages(var apidataMsg) { + Widget getMessages(List apidataMsg) { List rows = []; - apidataMsg ??= [ - { - "type": "znamka", - "title": "Načítání...", - "text": "Nebude to trvat dlouho", - } - ]; - apidataMsg = apidataMsg.where((msg) => msg["type"] == "znamka").toList(); + apidataMsg = apidataMsg.where((msg) => msg.type == "znamka").toList(); Map> grades = {}; - for (Map msg in apidataMsg) { - String gradeInfo = msg["text"].split(' - ')[1]; + for (TimelineItem msg in apidataMsg) { + String gradeInfo = msg.text.split(' - ')[1]; String className = gradeInfo.split(': ')[0]; String grade = gradeInfo.split(': ')[1]; if (!grades.containsKey(className)) grades[className] = []; @@ -96,12 +90,6 @@ class GradesPageState extends BaseState { padding: const EdgeInsets.all(10), child: Stack( children: [ - Text( - AppLocalizations.of(context)!.messagesTitle, - style: const TextStyle( - fontSize: 24, - ), - ), Padding( padding: const EdgeInsets.only(top: 40), child: RefreshIndicator( From 7c79a0b2e7101e3856cad6c2f40f016823349dde Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 20:25:42 +0100 Subject: [PATCH 06/11] Better color scheme generation --- lib/main.dart | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 30ee332..da60374 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -66,14 +66,18 @@ class MyApp extends StatelessWidget { static FirebaseAnalytics analytics = FirebaseAnalytics.instance; static FirebaseAnalyticsObserver observer = FirebaseAnalyticsObserver(analytics: analytics); - static final _defaultLightColorScheme = - ThemeData(colorSchemeSeed: const Color.fromARGB(255, 105, 140, 243)) - .colorScheme; - static final _defaultDarkColorScheme = ThemeData( - colorSchemeSeed: const Color.fromARGB(255, 105, 140, 243), - brightness: Brightness.dark) - .colorScheme; + ColorScheme _generateColorScheme(Color? primaryColor, + [Brightness? brightness]) { + final Color seedColor = primaryColor ?? Colors.blue; + + final ColorScheme newScheme = ColorScheme.fromSeed( + seedColor: seedColor, + brightness: brightness ?? Brightness.light, + ); + + return newScheme.harmonized(); + } // This widget is the root of your application. @override @@ -91,11 +95,17 @@ class MyApp extends StatelessWidget { supportedLocales: AppLocalizations.supportedLocales, navigatorObservers: [SentryNavigatorObserver(), observer], theme: ThemeData( - colorScheme: lightColorScheme ?? _defaultLightColorScheme, + colorScheme: _generateColorScheme( + lightColorScheme?.primary, + Brightness.light, + ), useMaterial3: true, ), darkTheme: ThemeData( - colorScheme: darkColorScheme ?? _defaultDarkColorScheme, + colorScheme: _generateColorScheme( + darkColorScheme?.primary, + Brightness.dark, + ), useMaterial3: true, ), themeMode: ThemeMode.dark, From 07fb6c1fa1f440d391c42724a228b943d50ea7d8 Mon Sep 17 00:00:00 2001 From: vyPal Date: Sun, 17 Nov 2024 20:25:58 +0100 Subject: [PATCH 07/11] Add grades button to home page --- lib/home.dart | 81 +++++++++++++++++++++++++++++++++++---------- lib/l10n/app_cs.arb | 2 ++ lib/l10n/app_en.arb | 2 ++ pubspec.lock | 8 +++++ pubspec.yaml | 1 + 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/lib/home.dart b/lib/home.dart index a6b6556..c54e5b1 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:eduapge2/api.dart'; +import 'package:eduapge2/grades.dart'; import 'package:eduapge2/icanteen_setup.dart'; import 'package:eduapge2/main.dart'; import 'package:eduapge2/message.dart'; @@ -16,6 +17,7 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:auto_size_text/auto_size_text.dart'; class HomePage extends StatefulWidget { final SessionManager sessionManager; @@ -334,7 +336,7 @@ class HomePageState extends BaseState { key: scaffoldKey, body: Stack( children: [ - Column( + ListView( children: [ Container( width: MediaQuery.of(context).size.width, @@ -616,24 +618,69 @@ class HomePageState extends BaseState { Container( width: MediaQuery.of(context).size.width, margin: const EdgeInsets.only(left: 20, right: 20, top: 10), - child: Card( - elevation: 5, - child: Padding( - padding: const EdgeInsets.all(10), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Grades", - style: const TextStyle(fontSize: 20), + child: GridView( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + childAspectRatio: 2, + ), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + children: [ + InkWell( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GradesPage( + sessionManager: widget.sessionManager, + ), + ), + ); + }, + child: Card( + elevation: 5, + child: Padding( + padding: const EdgeInsets.all(10), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const Icon(Icons.assignment_rounded), + AutoSizeText( + local!.homeGrades, + style: const TextStyle(fontSize: 20), + maxLines: 1, + minFontSize: 12, + overflow: TextOverflow.ellipsis, + ) + ], + ), ), - Text( - "Check your grades", - style: const TextStyle(fontSize: 12), + ), + ), + Card( + elevation: 5, + child: Padding( + padding: const EdgeInsets.all(10), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const Icon(Icons.home_work_rounded), + AutoSizeText( + local.homeHomework, + style: const TextStyle(fontSize: 20), + maxLines: 1, + minFontSize: 12, + overflow: TextOverflow.ellipsis, + ) + ], ), - ], + ), ), - ), + ], ), ), ], @@ -652,7 +699,7 @@ class HomePageState extends BaseState { splashColor: Colors.transparent, child: ListTile( leading: const Icon(Icons.lunch_dining_rounded), - title: Text(local!.homeSetupICanteen), + title: Text(local.homeSetupICanteen), onTap: () { Navigator.push( context, diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index cff31cd..380cda5 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -66,6 +66,8 @@ "homePreview": "Náhled", "homePatchAvailable": "Instaluje se nový patch...", "homePatchDownloaded": "Patch byl stažen, restartujte aplikaci pro instalaci", + "homeGrades": "Známky", + "homeHomework": "Úkoly", "homeworkTitle": "Domácí úkoly", "@homeworkTitle": { "description": "Title of homework page" diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1cc2e82..5748a5b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -19,6 +19,8 @@ "homePreview": "Preview", "homePatchAvailable": "Installing new patch...", "homePatchDownloaded": "Patch downloaded, please restart EduPage2", + "homeGrades": "Grades", + "homeHomework": "Homework", "homeworkTitle": "Homework", "messagesTitle": "Messages", "loginPleaseLogin": "Please login to EduPage2", diff --git a/pubspec.lock b/pubspec.lock index 7795de5..ae986cb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -57,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5dfc42a..9bb9dab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: in_app_update: ^4.2.2 app_links: ^6.1.1 toastification: ^2.3.0 + auto_size_text: ^3.0.0 dev_dependencies: integration_test: sdk: flutter From aa1f003539e17885f5e960e0dc588b7fa66dd29d Mon Sep 17 00:00:00 2001 From: vyPal Date: Tue, 19 Nov 2024 15:57:21 +0100 Subject: [PATCH 08/11] Add localized title to grades page --- lib/grades.dart | 52 ++++++++++++++++++++++++--------------------- lib/l10n/app_cs.arb | 3 ++- lib/l10n/app_en.arb | 3 ++- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/lib/grades.dart b/lib/grades.dart index 88c016a..7775e0a 100644 --- a/lib/grades.dart +++ b/lib/grades.dart @@ -1,8 +1,8 @@ import 'package:eduapge2/api.dart'; import 'package:eduapge2/main.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_session_manager/flutter_session_manager.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_session_manager/flutter_session_manager.dart'; class GradesPage extends StatefulWidget { final SessionManager sessionManager; @@ -17,7 +17,7 @@ class GradesPageState extends BaseState { bool loading = true; late List apidataMsg; - late Widget messages; + List messages = []; @override void initState() { @@ -44,8 +44,30 @@ class GradesPageState extends BaseState { toolbarHeight: 0, ), body: !loading - ? Stack( - children: [messages], + ? Card( + elevation: 5, + child: Padding( + padding: const EdgeInsets.all(10), + child: Stack( + children: [ + Text( + AppLocalizations.of(context)!.gradesTitle, + style: const TextStyle( + fontSize: 24, + ), + ), + Padding( + padding: const EdgeInsets.only(top: 40), + child: RefreshIndicator( + onRefresh: _pullRefresh, + child: ListView( + children: messages, + ), + ), + ), + ], + ), + ), ) : Text(AppLocalizations.of(context)!.loading), backgroundColor: Theme.of(context).colorScheme.surface, @@ -64,7 +86,7 @@ class GradesPageState extends BaseState { setState(() {}); //refresh UI } - Widget getMessages(List apidataMsg) { + List getMessages(List apidataMsg) { List rows = []; apidataMsg = apidataMsg.where((msg) => msg.type == "znamka").toList(); Map> grades = {}; @@ -84,24 +106,6 @@ class GradesPageState extends BaseState { ), )); } - return Card( - elevation: 5, - child: Padding( - padding: const EdgeInsets.all(10), - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.only(top: 40), - child: RefreshIndicator( - onRefresh: _pullRefresh, - child: ListView( - children: rows, - ), - ), - ), - ], - ), - ), - ); + return rows; } } diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index 380cda5..8f0f42a 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -149,5 +149,6 @@ "createMessageNotifError": "Chyba", "createMessageNotifErrorBody": "Při odesílání zprávy se vyskytla chyba, tato chyba byla nahlášena.", "qrLoginPleaseLogin": "EduPage2 QR Přihlášení", - "qrLoginUseExistingCredentials": "Chystáte se přihlásit pomocí QR kódu" + "qrLoginUseExistingCredentials": "Chystáte se přihlásit pomocí QR kódu", + "gradesTitle": "Známky" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5748a5b..4fb3e27 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -81,5 +81,6 @@ "createMessageNotifError": "Error", "createMessageNotifErrorBody": "There was an issue sending your message, it has been reported!", "qrLoginPleaseLogin": "EduPage2 QR Login", - "qrLoginUseExistingCredentials": "You are about to login to EduPage2 using a QR code" + "qrLoginUseExistingCredentials": "You are about to login to EduPage2 using a QR code", + "gradesTitle": "Grades" } From 1ec074d6403335def196fea5767c0eb0dec6b090 Mon Sep 17 00:00:00 2001 From: vyPal Date: Wed, 20 Nov 2024 16:43:27 +0100 Subject: [PATCH 09/11] Make preview builds on workflow dispatch --- .github/workflows/build-preview-apk.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build-preview-apk.yml b/.github/workflows/build-preview-apk.yml index 76a565e..d2c8182 100644 --- a/.github/workflows/build-preview-apk.yml +++ b/.github/workflows/build-preview-apk.yml @@ -9,12 +9,7 @@ permissions: repository-projects: write security-events: write statuses: write -on: - push: - branches: - - 'build-**' - - '!build-prerelease' - - '!build-release' +on: workflow_dispatch jobs: check_changes: outputs: From 0bc3f99866389e4c80270cf64253be94d52ac14b Mon Sep 17 00:00:00 2001 From: vyPal Date: Wed, 20 Nov 2024 18:02:05 +0100 Subject: [PATCH 10/11] Add Grades to api manager --- lib/api.dart | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 226 insertions(+), 2 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 7218377..5c560b3 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -1,11 +1,12 @@ import 'dart:convert'; + +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:dio/dio.dart'; import 'package:eduapge2/timetable.dart'; import 'package:firebase_remote_config/firebase_remote_config.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:connectivity_plus/connectivity_plus.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; Future isConnected() async { var connectivityResult = await (Connectivity().checkConnectivity()); @@ -23,6 +24,7 @@ class EP2Data { late User user; late Timeline timeline; late TimeTable timetable; + late Grades grades; static EP2Data? _instance; @@ -120,6 +122,12 @@ class EP2Data { await timetable.loadRecentTt(); } + grades = (await Grades.loadFromCache()) ?? Grades(events: {}, notes: {}); + + if (isInternetAvailable && !quickstart) { + await grades.loadGrades(); + } + if (quickstart && isInternetAvailable) { loadInBackground(); } @@ -133,6 +141,7 @@ class EP2Data { } await timeline.loadMessages(); await timetable.loadRecentTt(); + await grades.loadGrades(); } } @@ -1132,3 +1141,218 @@ class Timeline { await saveToCache(); } } + +class Event { + final String provider; + final String id; + final String studentID; + final String subjectID; + final String eventID; + final String month; + final String data; + final String date; + final String teacherID; + final String signed; + final String signedAdult; + final String timestamp; + final String state; + final String color; + final String eventName; + final String firstAverage; + final dynamic eventType; + final dynamic weight; + final String classID; + final String planID; + final dynamic gradeCount; + final dynamic moreData; + final String average; + + Event({ + required this.provider, + required this.id, + required this.studentID, + required this.subjectID, + required this.eventID, + required this.month, + required this.data, + required this.date, + required this.teacherID, + required this.signed, + required this.signedAdult, + required this.timestamp, + required this.state, + required this.color, + required this.eventName, + required this.firstAverage, + required this.eventType, + required this.weight, + required this.classID, + required this.planID, + required this.gradeCount, + required this.moreData, + required this.average, + }); + + factory Event.fromJson(Map json) { + return Event( + provider: json['provider'] as String, + id: json['znamkaid'] as String, + studentID: json['studentid'] as String, + subjectID: json['predmetid'] as String, + eventID: json['udalostID'] as String, + month: json['mesiac'] as String, + data: json['data'] as String, + date: json['datum'] as String, + teacherID: json['ucitelid'] as String, + signed: json['podpisane'] as String, + signedAdult: json['podpisane_rodic'] as String, + timestamp: json['timestamp'] as String, + state: json['stav'] as String, + color: json['p_farba'] as String, + eventName: json['p_meno'] as String, + firstAverage: json['p_najskor_priemer'] as String, + eventType: json['p_typ_udalosti'], + weight: json['p_vaha'], + classID: json['TriedaID'] as String, + planID: json['planid'] as String, + gradeCount: json['p_pocet_znamok'], + moreData: json['moredata'], + average: json['priemer'] as String, + ); + } + + Map toJson() { + return { + 'provider': provider, + 'znamkaid': id, + 'studentid': studentID, + 'predmetid': subjectID, + 'udalostID': eventID, + 'mesiac': month, + 'data': data, + 'datum': date, + 'ucitelid': teacherID, + 'podpisane': signed, + 'podpisane_rodic': signedAdult, + 'timestamp': timestamp, + 'stav': state, + 'p_farba': color, + 'p_meno': eventName, + 'p_najskor_priemer': firstAverage, + 'p_typ_udalosti': eventType, + 'p_vaha': weight, + 'TriedaID': classID, + 'planid': planID, + 'p_pocet_znamok': gradeCount, + 'moredata': moreData, + 'priemer': average, + }; + } +} + +class Note { + final String id; + final String date; + final String text; + final String type; + final String subjectID; + + Note({ + required this.id, + required this.date, + required this.text, + required this.type, + required this.subjectID, + }); + + factory Note.fromJson(Map json) { + return Note( + id: json['VcelickaID'] as String, + date: json['p_datum'] as String, + text: json['p_text'] as String, + type: json['p_typ'] as String, + subjectID: json['PredmetID'] as String, + ); + } + + Map toJson() { + return { + 'VcelickaID': id, + 'p_datum': date, + 'p_text': text, + 'p_typ': type, + 'PredmetID': subjectID, + }; + } +} + +class Grades { + EP2Data data = EP2Data.getInstance(); + + final Map events; + final Map notes; + + Grades({ + required this.events, + required this.notes, + }); + + factory Grades.fromJson(Map json) { + return Grades( + events: (json['Events'] as Map).map( + (key, value) => + MapEntry(key, Event.fromJson(value as Map)), + ), + notes: (json['Notes'] as Map).map( + (key, value) => + MapEntry(key, Note.fromJson(value as Map)), + ), + ); + } + + Map toJson() { + return { + 'Events': events.map((key, value) => MapEntry(key, value.toJson())), + 'Notes': notes.map((key, value) => MapEntry(key, value.toJson())), + }; + } + + Future saveToCache() async { + final timelineJson = jsonEncode(toJson()); + await data.sharedPreferences.setString('grades', timelineJson); + } + + static Future loadFromCache() async { + final prefs = await SharedPreferences.getInstance(); + final timelineJson = prefs.getString('grades'); + if (timelineJson != null) { + return Grades.fromJson(jsonDecode(timelineJson)); + } else { + return null; + } + } + + Future loadGrades() async { + Response response = await data.dio.get( + "${data.baseUrl}/api/grades", + options: Options( + headers: { + "Authorization": "Bearer ${data.user.token}", + }, + ), + ); + + Map newEvents = response.data["Events"]; + Map newNotes = response.data["Notes"]; + + newEvents.forEach((key, value) { + events[key] = Event.fromJson(value); + }); + + newNotes.forEach((key, value) { + notes[key] = Note.fromJson(value); + }); + + await saveToCache(); + } +} From 33b2be6c4a50d658cfa988046dede99ec8520867 Mon Sep 17 00:00:00 2001 From: vyPal Date: Wed, 20 Nov 2024 18:02:28 +0100 Subject: [PATCH 11/11] Fix scrolling not loading messages --- lib/messages.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/messages.dart b/lib/messages.dart index 278f1ee..893aacb 100644 --- a/lib/messages.dart +++ b/lib/messages.dart @@ -3,8 +3,8 @@ import 'package:eduapge2/create_message.dart'; import 'package:eduapge2/main.dart'; import 'package:eduapge2/message.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_session_manager/flutter_session_manager.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_session_manager/flutter_session_manager.dart'; import 'package:html_unescape/html_unescape.dart'; class MessagesPage extends StatefulWidget { @@ -63,6 +63,8 @@ class TimeTablePageState extends BaseState { _scrollController.position.maxScrollExtent - 200) { _isFetching = true; await EP2Data.getInstance().timeline.loadOlderMessages(); + messages = + getMessages(EP2Data.getInstance().timeline.items.values.toList()); _isFetching = false; } });