From 77eb1235f7e570e6b28b3da8bda58ae9f137b8d1 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 6 Jul 2023 23:44:04 +0100 Subject: [PATCH 01/21] Remove unused faculties provider --- uni/android/build.gradle | 4 ++-- uni/lib/controller/load_info.dart | 2 -- uni/lib/main.dart | 5 ----- uni/lib/model/providers/exam_provider.dart | 2 +- .../model/providers/state_provider_notifier.dart | 16 ++++++++++++++-- uni/lib/model/providers/state_providers.dart | 6 ------ .../model/providers/user_faculties_provider.dart | 14 -------------- 7 files changed, 17 insertions(+), 32 deletions(-) delete mode 100644 uni/lib/model/providers/user_faculties_provider.dart diff --git a/uni/android/build.gradle b/uni/android/build.gradle index 96de58432..954fa1cd5 100644 --- a/uni/android/build.gradle +++ b/uni/android/build.gradle @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir -} \ No newline at end of file +} diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index 93b7c1a56..32cf8561a 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -106,8 +106,6 @@ void loadLocalUserInfoToState(StateProviders stateProviders, await AppSharedPreferences.getFilteredExams(), Completer()); stateProviders.examProvider .setHiddenExams(await AppSharedPreferences.getHiddenExams(), Completer()); - stateProviders.userFacultiesProvider - .setUserFaculties(await AppSharedPreferences.getUserFaculties()); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '' && diff --git a/uni/lib/main.dart b/uni/lib/main.dart index fa5edf566..9ca04849a 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -21,7 +21,6 @@ import 'package:uni/model/providers/profile_state_provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/model/providers/user_faculties_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/about/about.dart'; import 'package:uni/view/bug_report/bug_report.dart'; @@ -59,7 +58,6 @@ Future main() async { LibraryOccupationProvider(), FacultyLocationsProvider(), LastUserInfoProvider(), - UserFacultiesProvider(), FavoriteCardsProvider(), HomePageEditingModeProvider()); @@ -101,9 +99,6 @@ Future main() async { stateProviders.facultyLocationsProvider), ChangeNotifierProvider( create: (context) => stateProviders.lastUserInfoProvider), - ChangeNotifierProvider( - create: (context) => - stateProviders.userFacultiesProvider), ChangeNotifierProvider( create: (context) => stateProviders.favoriteCardsProvider), diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/exam_provider.dart index 2ba2bc8d3..d9baec552 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/exam_provider.dart @@ -29,7 +29,7 @@ class ExamProvider extends StateProviderNotifier { UnmodifiableMapView get filteredExamsTypes => UnmodifiableMapView(_filteredExamsTypes); - void getUserExams( + Future getUserExams( Completer action, ParserExams parserExams, Tuple2 userPersistentInfo, diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 2e602f197..ba1e500c9 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,9 +1,9 @@ -import 'package:flutter/cupertino.dart'; - +import 'package:flutter/material.dart'; import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { RequestStatus _status = RequestStatus.none; + bool _initialized = false; RequestStatus get status => _status; @@ -11,4 +11,16 @@ abstract class StateProviderNotifier extends ChangeNotifier { _status = status; notifyListeners(); } + + /*void ensureInitialized() { + if (!_initialized) { + _initialized = true; + loadFromStorage(); + loadFromRemote(); + } + } + + void loadFromStorage(); + + void loadFromRemote();*/ } diff --git a/uni/lib/model/providers/state_providers.dart b/uni/lib/model/providers/state_providers.dart index a52545ccd..e6d36398d 100644 --- a/uni/lib/model/providers/state_providers.dart +++ b/uni/lib/model/providers/state_providers.dart @@ -12,7 +12,6 @@ import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/model/providers/profile_state_provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; -import 'package:uni/model/providers/user_faculties_provider.dart'; class StateProviders { final LectureProvider lectureProvider; @@ -25,7 +24,6 @@ class StateProviders { final LibraryOccupationProvider libraryOccupationProvider; final FacultyLocationsProvider facultyLocationsProvider; final LastUserInfoProvider lastUserInfoProvider; - final UserFacultiesProvider userFacultiesProvider; final FavoriteCardsProvider favoriteCardsProvider; final HomePageEditingModeProvider homePageEditingMode; @@ -40,7 +38,6 @@ class StateProviders { this.libraryOccupationProvider, this.facultyLocationsProvider, this.lastUserInfoProvider, - this.userFacultiesProvider, this.favoriteCardsProvider, this.homePageEditingMode); @@ -64,8 +61,6 @@ class StateProviders { Provider.of(context, listen: false); final lastUserInfoProvider = Provider.of(context, listen: false); - final userFacultiesProvider = - Provider.of(context, listen: false); final favoriteCardsProvider = Provider.of(context, listen: false); final homePageEditingMode = @@ -82,7 +77,6 @@ class StateProviders { libraryOccupationProvider, facultyLocationsProvider, lastUserInfoProvider, - userFacultiesProvider, favoriteCardsProvider, homePageEditingMode); } diff --git a/uni/lib/model/providers/user_faculties_provider.dart b/uni/lib/model/providers/user_faculties_provider.dart deleted file mode 100644 index 0d6ba6316..000000000 --- a/uni/lib/model/providers/user_faculties_provider.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:collection'; - -import 'package:uni/model/providers/state_provider_notifier.dart'; - -class UserFacultiesProvider extends StateProviderNotifier{ - List _faculties = []; - - UnmodifiableListView get faculties => UnmodifiableListView(_faculties); - - setUserFaculties(List faculties){ - _faculties = faculties; - notifyListeners(); - } -} \ No newline at end of file From 3c531b6fd5bcec535de165eceb152ea8b579caf4 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 00:38:34 +0100 Subject: [PATCH 02/21] Implement LazyConsumer --- uni/lib/controller/load_info.dart | 4 +- uni/lib/model/providers/exam_provider.dart | 4 +- .../providers/favorite_cards_provider.dart | 11 ++- .../providers/state_provider_notifier.dart | 19 ++-- .../bus_stop_next_arrivals.dart | 57 +++++------ .../widgets/estimated_arrival_timestamp.dart | 4 +- .../bus_stop_selection.dart | 4 +- uni/lib/view/calendar/calendar.dart | 4 +- .../common_widgets/last_update_timestamp.dart | 4 +- .../request_dependent_widget_builder.dart | 12 +-- uni/lib/view/course_units/course_units.dart | 6 +- uni/lib/view/exams/exams.dart | 32 ++++--- uni/lib/view/home/widgets/bus_stop_card.dart | 12 ++- uni/lib/view/home/widgets/exam_card.dart | 10 +- .../view/home/widgets/restaurant_card.dart | 4 +- uni/lib/view/home/widgets/schedule_card.dart | 42 ++++---- uni/lib/view/lazy_consumer.dart | 22 +++++ uni/lib/view/library/library.dart | 4 +- .../widgets/library_occupation_card.dart | 4 +- uni/lib/view/locations/locations.dart | 6 +- uni/lib/view/login/login.dart | 10 +- uni/lib/view/profile/profile.dart | 39 ++++---- .../profile/widgets/account_info_card.dart | 21 ++-- .../view/profile/widgets/print_info_card.dart | 7 +- .../profile/widgets/profile_overview.dart | 57 ++++++----- .../view/restaurant/restaurant_page_view.dart | 96 +++++++++---------- uni/lib/view/schedule/schedule.dart | 9 +- 27 files changed, 263 insertions(+), 241 deletions(-) create mode 100644 uni/lib/view/lazy_consumer.dart diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index 32cf8561a..fc030c70c 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -99,9 +99,7 @@ void loadLocalUserInfoToState(StateProviders stateProviders, final Tuple2 userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - Logger().i('Setting up user preferences'); - stateProviders.favoriteCardsProvider - .setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); + //Logger().i('Setting up user preferences'); stateProviders.examProvider.setFilteredExams( await AppSharedPreferences.getFilteredExams(), Completer()); stateProviders.examProvider diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/exam_provider.dart index d9baec552..b0b680acb 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/exam_provider.dart @@ -7,20 +7,18 @@ import 'package:uni/controller/fetchers/exam_fetcher.dart'; import 'package:uni/controller/local_storage/app_exams_database.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/model/request_status.dart'; class ExamProvider extends StateProviderNotifier { List _exams = []; List _hiddenExams = []; Map _filteredExamsTypes = {}; - - UnmodifiableListView get exams => UnmodifiableListView(_exams); UnmodifiableListView get hiddenExams => diff --git a/uni/lib/model/providers/favorite_cards_provider.dart b/uni/lib/model/providers/favorite_cards_provider.dart index 99ef9088c..03a326ec4 100644 --- a/uni/lib/model/providers/favorite_cards_provider.dart +++ b/uni/lib/model/providers/favorite_cards_provider.dart @@ -1,10 +1,19 @@ +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/utils/favorite_widget_type.dart'; class FavoriteCardsProvider extends StateProviderNotifier { List _favoriteCards = []; - List get favoriteCards => _favoriteCards.toList(); + List get favoriteCards { + ensureInitialized(); + return _favoriteCards.toList(); + } + + @override + loadFromRemote() async { + setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); + } setFavoriteCards(List favoriteCards) { _favoriteCards = favoriteCards; diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index ba1e500c9..2c6f5a955 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,3 +1,4 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:uni/model/request_status.dart'; @@ -12,15 +13,21 @@ abstract class StateProviderNotifier extends ChangeNotifier { notifyListeners(); } - /*void ensureInitialized() { - if (!_initialized) { - _initialized = true; - loadFromStorage(); + void ensureInitialized() async { + if (_initialized) { + return; + } + + _initialized = true; + loadFromStorage(); + if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { loadFromRemote(); } + + notifyListeners(); } - void loadFromStorage(); + void loadFromStorage() async {} - void loadFromRemote();*/ + void loadFromRemote() async {} } diff --git a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index 4ff78add8..e99d2d6f0 100644 --- a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart'; import 'package:uni/view/bus_stop_selection/bus_stop_selection.dart'; import 'package:uni/view/common_widgets/last_update_timestamp.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/lazy_consumer.dart'; class BusStopNextArrivalsPage extends StatefulWidget { const BusStopNextArrivalsPage({Key? key}) : super(key: key); @@ -21,10 +21,9 @@ class BusStopNextArrivalsPageState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, busProvider, _) => ListView(children: [ - NextArrivals( - busProvider.configuredBusStops, busProvider.status) + NextArrivals(busProvider.configuredBusStops, busProvider.status) ])); } } @@ -34,8 +33,7 @@ class NextArrivals extends StatefulWidget { final Map buses; final RequestStatus busStopStatus; - const NextArrivals(this.buses, this.busStopStatus, - {super.key}); + const NextArrivals(this.buses, this.busStopStatus, {super.key}); @override NextArrivalsState createState() => NextArrivalsState(); @@ -46,33 +44,26 @@ class NextArrivalsState extends State { @override Widget build(BuildContext context) { Widget contentBuilder() { - switch (widget.busStopStatus) { - case RequestStatus.successful: - return SizedBox( - height: MediaQuery - .of(context) - .size - .height, - child: Column(children: requestSuccessful(context))); - case RequestStatus.busy: - return SizedBox( - height: MediaQuery - .of(context) - .size - .height, - child: Column(children: requestBusy(context))); - case RequestStatus.failed: - return SizedBox( - height: MediaQuery - .of(context) - .size - .height, - child: Column(children: requestFailed(context))); - default: - return Container(); + switch (widget.busStopStatus) { + case RequestStatus.successful: + return SizedBox( + height: MediaQuery.of(context).size.height, + child: Column(children: requestSuccessful(context))); + case RequestStatus.busy: + return SizedBox( + height: MediaQuery.of(context).size.height, + child: Column(children: requestBusy(context))); + case RequestStatus.failed: + return SizedBox( + height: MediaQuery.of(context).size.height, + child: Column(children: requestFailed(context))); + default: + return Container(); + } } - } - return DefaultTabController(length: widget.buses.length, child: contentBuilder()); + + return DefaultTabController( + length: widget.buses.length, child: contentBuilder()); } /// Returns a list of widgets for a successfull request diff --git a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart index c1ec2d134..0fa7c3cdf 100644 --- a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart +++ b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/view/lazy_consumer.dart'; /// Manages the section with the estimated time for the bus arrival class EstimatedArrivalTimeStamp extends StatelessWidget { @@ -13,7 +13,7 @@ class EstimatedArrivalTimeStamp extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, busProvider, _) => getContent(context, busProvider.timeStamp), ); diff --git a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart index 545fb6e2c..a273c830c 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/controller/local_storage/app_bus_stop_database.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; @@ -7,6 +6,7 @@ import 'package:uni/view/bus_stop_selection/widgets/bus_stop_search.dart'; import 'package:uni/view/bus_stop_selection/widgets/bus_stop_selection_row.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; +import 'package:uni/view/lazy_consumer.dart'; class BusStopSelectionPage extends StatefulWidget { const BusStopSelectionPage({super.key}); @@ -36,7 +36,7 @@ class BusStopSelectionPageState @override Widget getBody(BuildContext context) { final width = MediaQuery.of(context).size.width; - return Consumer(builder: (context, busProvider, _) { + return LazyConsumer(builder: (context, busProvider, _) { final List rows = []; busProvider.configuredBusStops.forEach((stopCode, stopData) => rows.add(BusStopSelectionRow(stopCode, stopData))); diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 4942cc005..2af4205c1 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/lazy_consumer.dart'; class CalendarPageView extends StatefulWidget { const CalendarPageView({Key? key}) : super(key: key); @@ -16,7 +16,7 @@ class CalendarPageView extends StatefulWidget { class CalendarPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, calendarProvider, _) => getCalendarPage(context, calendarProvider.calendar), ); diff --git a/uni/lib/view/common_widgets/last_update_timestamp.dart b/uni/lib/view/common_widgets/last_update_timestamp.dart index 4b5138ce2..39f7fec46 100644 --- a/uni/lib/view/common_widgets/last_update_timestamp.dart +++ b/uni/lib/view/common_widgets/last_update_timestamp.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; +import 'package:uni/view/lazy_consumer.dart'; class LastUpdateTimeStamp extends StatefulWidget { const LastUpdateTimeStamp({super.key}); @@ -33,7 +33,7 @@ class _LastUpdateTimeStampState extends State { @override Widget build(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, lastUserInfoProvider, _) => Container( padding: const EdgeInsets.only(top: 8.0, bottom: 10.0), child: _getContent(context, lastUserInfoProvider.lastUpdateTime!)), diff --git a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart index f5f0b2d1d..a721917c8 100644 --- a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart +++ b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart @@ -1,12 +1,11 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart'; - import 'package:uni/controller/local_storage/app_last_user_info_update_database.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/lazy_consumer.dart'; /// Wraps content given its fetch data from the redux store, /// hydrating the component, displaying an empty message, @@ -36,7 +35,7 @@ class RequestDependentWidgetBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, lastUserInfoProvider, _) { switch (status) { case RequestStatus.successful: @@ -92,9 +91,8 @@ class RequestDependentWidgetBuilder extends StatelessWidget { child: Text('Aconteceu um erro ao carregar os dados', style: Theme.of(context).textTheme.titleMedium))), OutlinedButton( - onPressed: () => - Navigator.pushNamed(context, '/${DrawerItem.navBugReport.title}'), - + onPressed: () => Navigator.pushNamed( + context, '/${DrawerItem.navBugReport.title}'), child: const Text('Reportar erro')) ]); }); diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index 19a2b94e4..ba7abcd5e 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -1,14 +1,14 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/course_units/widgets/course_unit_card.dart'; +import 'package:uni/view/lazy_consumer.dart'; class CourseUnitsPageView extends StatefulWidget { const CourseUnitsPageView({Key? key}) : super(key: key); @@ -28,7 +28,7 @@ class CourseUnitsPageViewState @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, profileProvider, _) { final List courseUnits = profileProvider.currUcs; List availableYears = []; diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 17f68fa73..2d3420ddc 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/entities/exam.dart'; +import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; -import 'package:uni/view/exams/widgets/exam_page_title.dart'; import 'package:uni/view/common_widgets/row_container.dart'; -import 'package:uni/view/exams/widgets/exam_row.dart'; import 'package:uni/view/exams/widgets/day_title.dart'; +import 'package:uni/view/exams/widgets/exam_page_title.dart'; +import 'package:uni/view/exams/widgets/exam_row.dart'; +import 'package:uni/view/lazy_consumer.dart'; class ExamsPageView extends StatefulWidget { const ExamsPageView({super.key}); @@ -21,17 +22,17 @@ class ExamsPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return Consumer( - builder: (context, examProvider, _) { - return ListView( - children: [ - Column( - mainAxisSize: MainAxisSize.max, - children: createExamsColumn(context, examProvider.getFilteredExams()), - ) - ], - ); - }); + return LazyConsumer(builder: (context, examProvider, _) { + return ListView( + children: [ + Column( + mainAxisSize: MainAxisSize.max, + children: + createExamsColumn(context, examProvider.getFilteredExams()), + ) + ], + ); + }); } /// Creates a column with all the user's exams. @@ -105,7 +106,8 @@ class ExamsPageViewState extends GeneralPageViewState { } Widget createExamContext(context, Exam exam) { - final isHidden = Provider.of(context).hiddenExams.contains(exam.id); + final isHidden = + Provider.of(context).hiddenExams.contains(exam.id); return Container( key: Key('$exam-exam'), margin: const EdgeInsets.fromLTRB(12, 4, 12, 0), diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index ff567736a..9f778f350 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart'; import 'package:uni/view/bus_stop_selection/bus_stop_selection.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/common_widgets/last_update_timestamp.dart'; +import 'package:uni/view/lazy_consumer.dart'; /// Manages the bus stops card displayed on the user's personal area class BusStopCard extends GenericCard { @@ -24,16 +24,18 @@ class BusStopCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, busProvider, _) { - return getCardContent(context, busProvider.configuredBusStops, busProvider.status); + return getCardContent( + context, busProvider.configuredBusStops, busProvider.status); }, ); } } /// Returns a widget with the bus stop card final content -Widget getCardContent(BuildContext context, Map stopData, busStopStatus) { +Widget getCardContent( + BuildContext context, Map stopData, busStopStatus) { switch (busStopStatus) { case RequestStatus.successful: if (stopData.isNotEmpty) { diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 331a48e26..29e55ff4a 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; +import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/common_widgets/row_container.dart'; -import 'package:uni/view/common_widgets/generic_card.dart'; -import 'package:uni/utils/drawer_items.dart'; -import 'package:uni/view/home/widgets/exam_card_shimmer.dart'; import 'package:uni/view/exams/widgets/exam_row.dart'; import 'package:uni/view/exams/widgets/exam_title.dart'; +import 'package:uni/view/home/widgets/exam_card_shimmer.dart'; +import 'package:uni/view/lazy_consumer.dart'; /// Manages the exam card section inside the personal area. class ExamCard extends GenericCard { @@ -32,7 +32,7 @@ class ExamCard extends GenericCard { /// that no exams exist is displayed. @override Widget buildCardContent(BuildContext context) { - return Consumer(builder: (context, examProvider, _) { + return LazyConsumer(builder: (context, examProvider, _) { final filteredExams = examProvider.getFilteredExams(); final hiddenExams = examProvider.hiddenExams; final List exams = filteredExams diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 4eeb035d6..3c8f7f8c8 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/common_widgets/row_container.dart'; import 'package:uni/view/home/widgets/restaurant_row.dart'; +import 'package:uni/view/lazy_consumer.dart'; class RestaurantCard extends GenericCard { RestaurantCard({Key? key}) : super(key: key); @@ -22,7 +22,7 @@ class RestaurantCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, restaurantProvider, _) => RequestDependentWidgetBuilder( context: context, diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index a17fdc2d0..5f6f13ba9 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; -import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; -import 'package:uni/view/schedule/widgets/schedule_slot.dart'; +import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/home/widgets/schedule_card_shimmer.dart'; -import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/lazy_consumer.dart'; +import 'package:uni/view/schedule/widgets/schedule_slot.dart'; class ScheduleCard extends GenericCard { ScheduleCard({Key? key}) : super(key: key); @@ -23,20 +23,18 @@ class ScheduleCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( - builder: (context, lectureProvider, _) => RequestDependentWidgetBuilder( - context: context, - status: lectureProvider.status, - contentGenerator: generateSchedule, - content: lectureProvider.lectures, - contentChecker: lectureProvider.lectures.isNotEmpty, - onNullContent: Center( - child: Text('Não existem aulas para apresentar', - style: Theme.of(context).textTheme.titleLarge, - textAlign: TextAlign.center)), - contentLoadingWidget: const ScheduleCardShimmer().build(context)) - ); - + return LazyConsumer( + builder: (context, lectureProvider, _) => RequestDependentWidgetBuilder( + context: context, + status: lectureProvider.status, + contentGenerator: generateSchedule, + content: lectureProvider.lectures, + contentChecker: lectureProvider.lectures.isNotEmpty, + onNullContent: Center( + child: Text('Não existem aulas para apresentar', + style: Theme.of(context).textTheme.titleLarge, + textAlign: TextAlign.center)), + contentLoadingWidget: const ScheduleCardShimmer().build(context))); } Widget generateSchedule(lectures, BuildContext context) { @@ -58,7 +56,9 @@ class ScheduleCard extends GenericCard { if (now.compareTo(lectures[i].endTime) < 0) { if (lastAddedLectureDate.weekday != lectures[i].startTime.weekday && lastAddedLectureDate.compareTo(lectures[i].startTime) <= 0) { - rows.add(DateRectangle(date: TimeString.getWeekdaysStrings()[(lectures[i].startTime.weekday-1) % 7])); + rows.add(DateRectangle( + date: TimeString.getWeekdaysStrings()[ + (lectures[i].startTime.weekday - 1) % 7])); } rows.add(createRowFromLecture(context, lectures[i])); @@ -68,7 +68,9 @@ class ScheduleCard extends GenericCard { } if (rows.isEmpty) { - rows.add(DateRectangle(date: TimeString.getWeekdaysStrings()[lectures[0].startTime.weekday % 7])); + rows.add(DateRectangle( + date: TimeString.getWeekdaysStrings()[ + lectures[0].startTime.weekday % 7])); rows.add(createRowFromLecture(context, lectures[0])); } return rows; diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart new file mode 100644 index 000000000..925368b1d --- /dev/null +++ b/uni/lib/view/lazy_consumer.dart @@ -0,0 +1,22 @@ +import 'package:flutter/cupertino.dart'; +import 'package:provider/provider.dart'; +import 'package:uni/model/providers/state_provider_notifier.dart'; + +class LazyConsumer extends StatelessWidget { + final Widget Function(BuildContext, T, Widget?) builder; + + const LazyConsumer({ + Key? key, + required this.builder, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).ensureInitialized(); + }); + return Consumer( + builder: builder, + ); + } +} diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index 0f4f1d7a1..2756dbc51 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/entities/library_occupation.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/library/widgets/library_occupation_card.dart'; class LibraryPageView extends StatefulWidget { @@ -17,7 +17,7 @@ class LibraryPageView extends StatefulWidget { class LibraryPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, libraryOccupationProvider, _) => LibraryPage(libraryOccupationProvider.occupation)); diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index bcaa96d43..70da1215f 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/percent_indicator.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; +import 'package:uni/view/lazy_consumer.dart'; /// Manages the library card section inside the personal area. class LibraryOccupationCard extends GenericCard { @@ -24,7 +24,7 @@ class LibraryOccupationCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, libraryOccupationProvider, _) => RequestDependentWidgetBuilder( context: context, diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index b9ce8722c..2b2a573e8 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/location_group.dart'; import 'package:uni/model/providers/faculty_locations_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/locations/widgets/faculty_maps.dart'; import 'package:uni/view/locations/widgets/map.dart'; import 'package:uni/view/locations/widgets/marker.dart'; @@ -28,7 +28,7 @@ class LocationsPageState extends GeneralPageViewState @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, locationsProvider, _) { return LocationsPageView( locations: locationsProvider.locations, diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 915606c62..ead902fa0 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -4,14 +4,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/login_exceptions.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/model/request_status.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; import 'package:uni/view/login/widgets/inputs.dart'; -import 'package:uni/utils/drawer_items.dart'; -import 'package:url_launcher/url_launcher.dart'; import 'package:uni/view/theme.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../lazy_consumer.dart'; class LoginPageView extends StatefulWidget { const LoginPageView({super.key}); @@ -220,7 +222,7 @@ class LoginPageViewState extends State { /// Creates a widget for the user login depending on the status of his login. Widget createStatusWidget(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, sessionProvider, _) { switch (sessionProvider.status) { case RequestStatus.busy: diff --git a/uni/lib/view/profile/profile.dart b/uni/lib/view/profile/profile.dart index e1165559a..4c884f02a 100644 --- a/uni/lib/view/profile/profile.dart +++ b/uni/lib/view/profile/profile.dart @@ -1,8 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/profile_state_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/account_info_card.dart'; import 'package:uni/view/profile/widgets/course_info_card.dart'; import 'package:uni/view/profile/widgets/profile_overview.dart'; @@ -18,28 +18,27 @@ class ProfilePageView extends StatefulWidget { class ProfilePageViewState extends SecondaryPageViewState { @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; - final List courseWidgets = profile.courses.map((e) => [ - CourseInfoCard(course: e), - const Padding(padding: EdgeInsets.all(5.0)) - ]).flattened.toList(); + final List courseWidgets = profile.courses + .map((e) => [ + CourseInfoCard(course: e), + const Padding(padding: EdgeInsets.all(5.0)) + ]) + .flattened + .toList(); - return ListView( - shrinkWrap: false, - children: [ - const Padding(padding: EdgeInsets.all(5.0)), - ProfileOverview( - profile: profile, - getProfileDecorationImage: getProfileDecorationImage - ), - const Padding(padding: EdgeInsets.all(5.0)), - // PrintInfoCard() // TODO: Bring this back when print info is ready again - ...courseWidgets, - AccountInfoCard(), - ] - ); + return ListView(shrinkWrap: false, children: [ + const Padding(padding: EdgeInsets.all(5.0)), + ProfileOverview( + profile: profile, + getProfileDecorationImage: getProfileDecorationImage), + const Padding(padding: EdgeInsets.all(5.0)), + // PrintInfoCard() // TODO: Bring this back when print info is ready again + ...courseWidgets, + AccountInfoCard(), + ]); }, ); } diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index 47a6363f5..0c3265635 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/profile_state_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/tuition_notification_switch.dart'; /// Manages the 'Current account' section inside the user's page (accessible @@ -15,7 +15,7 @@ class AccountInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; return Column(children: [ @@ -49,17 +49,14 @@ class AccountInfoCard extends GenericCard { ]), TableRow(children: [ Container( - margin: - const EdgeInsets.only(top: 8.0, bottom: 20.0, left: 20.0), - child: Text("Notificar próxima data limite: ", - style: Theme.of(context).textTheme.titleSmall) - ), + margin: const EdgeInsets.only( + top: 8.0, bottom: 20.0, left: 20.0), + child: Text("Notificar próxima data limite: ", + style: Theme.of(context).textTheme.titleSmall)), Container( - margin: - const EdgeInsets.only(top: 8.0, bottom: 20.0, left: 20.0), - child: - const TuitionNotificationSwitch() - ) + margin: const EdgeInsets.only( + top: 8.0, bottom: 20.0, left: 20.0), + child: const TuitionNotificationSwitch()) ]) ]), showLastRefreshedTime(profileStateProvider.feesRefreshTime, context) diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index eb0155295..34bad39f0 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/profile_state_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/create_print_mb_dialog.dart'; class PrintInfoCard extends GenericCard { @@ -13,7 +13,7 @@ class PrintInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; return Column( @@ -47,8 +47,7 @@ class PrintInfoCard extends GenericCard { ), onPressed: () => addMoneyDialog(context), child: const Center(child: Icon(Icons.add)), - ) - ), + )), ]) ]), showLastRefreshedTime( diff --git a/uni/lib/view/profile/widgets/profile_overview.dart b/uni/lib/view/profile/widgets/profile_overview.dart index 99f142d0b..b1593144b 100644 --- a/uni/lib/view/profile/widgets/profile_overview.dart +++ b/uni/lib/view/profile/widgets/profile_overview.dart @@ -1,52 +1,51 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; import 'package:uni/controller/load_info.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/view/lazy_consumer.dart'; class ProfileOverview extends StatelessWidget { final Profile profile; final DecorationImage Function(File?) getProfileDecorationImage; - const ProfileOverview({Key? key, required this.profile, - required this.getProfileDecorationImage}) : super(key: key); + const ProfileOverview( + {Key? key, + required this.profile, + required this.getProfileDecorationImage}) + : super(key: key); @override Widget build(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, sessionProvider, _) { return FutureBuilder( future: loadProfilePicture(sessionProvider.session), builder: (BuildContext context, AsyncSnapshot profilePic) => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 150.0, - height: 150.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: getProfileDecorationImage(profilePic.data) - ) - ), - const Padding(padding: EdgeInsets.all(8.0)), - Text(profile.name, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 20.0, fontWeight: FontWeight.w400) - ), - const Padding(padding: EdgeInsets.all(5.0)), - Text(profile.email, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 18.0, fontWeight: FontWeight.w300) - ), - ], - ), + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 150.0, + height: 150.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: getProfileDecorationImage(profilePic.data))), + const Padding(padding: EdgeInsets.all(8.0)), + Text(profile.name, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 20.0, fontWeight: FontWeight.w400)), + const Padding(padding: EdgeInsets.all(5.0)), + Text(profile.email, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18.0, fontWeight: FontWeight.w300)), + ], + ), ); }, ); } -} \ No newline at end of file +} diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 80704b74e..9b7f02144 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -1,13 +1,12 @@ -import 'package:provider/provider.dart'; -import 'package:uni/model/entities/meal.dart'; import 'package:flutter/material.dart'; +import 'package:uni/model/entities/meal.dart'; +import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; +import 'package:uni/model/utils/day_of_week.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; -import 'package:uni/model/utils/day_of_week.dart'; - -import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/restaurant/widgets/restaurant_page_card.dart'; import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; @@ -30,60 +29,57 @@ class _RestaurantPageState extends GeneralPageViewState final int weekDay = DateTime.now().weekday; super.initState(); tabController = TabController(vsync: this, length: DayOfWeek.values.length); - tabController.animateTo((tabController.index + (weekDay-1))); + tabController.animateTo((tabController.index + (weekDay - 1))); scrollViewController = ScrollController(); } @override Widget getBody(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, restaurantProvider, _) { - return Column(children: [ - ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [ - Container( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), - alignment: Alignment.center, - child: const PageTitle(name: 'Ementas', center: false, pad: false), - ), - TabBar( - controller: tabController, - isScrollable: true, - tabs: createTabs(context), - ), - ]), - const SizedBox(height: 10), - RequestDependentWidgetBuilder( - context: context, - status: restaurantProvider.status, - contentGenerator: createTabViewBuilder, - content: restaurantProvider.restaurants, - contentChecker: restaurantProvider.restaurants.isNotEmpty, - onNullContent: + return Column(children: [ + ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [ + Container( + padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), + alignment: Alignment.center, + child: const PageTitle(name: 'Ementas', center: false, pad: false), + ), + TabBar( + controller: tabController, + isScrollable: true, + tabs: createTabs(context), + ), + ]), + const SizedBox(height: 10), + RequestDependentWidgetBuilder( + context: context, + status: restaurantProvider.status, + contentGenerator: createTabViewBuilder, + content: restaurantProvider.restaurants, + contentChecker: restaurantProvider.restaurants.isNotEmpty, + onNullContent: const Center(child: Text('Não há refeições disponíveis.'))) - ]); - } - ); + ]); + }); } Widget createTabViewBuilder(dynamic restaurants, BuildContext context) { - final List dayContents = DayOfWeek.values.map((dayOfWeek) { - List restaurantsWidgets = []; - if (restaurants is List) { - restaurantsWidgets = restaurants - .map((restaurant) => RestaurantPageCard( - restaurant.name, - RestaurantDay(restaurant: restaurant, day: dayOfWeek) - )) - .toList(); - } - return ListView(children: restaurantsWidgets); - }).toList(); + final List dayContents = DayOfWeek.values.map((dayOfWeek) { + List restaurantsWidgets = []; + if (restaurants is List) { + restaurantsWidgets = restaurants + .map((restaurant) => RestaurantPageCard(restaurant.name, + RestaurantDay(restaurant: restaurant, day: dayOfWeek))) + .toList(); + } + return ListView(children: restaurantsWidgets); + }).toList(); - return Expanded( + return Expanded( child: TabBarView( - controller: tabController, - children: dayContents, - )); + controller: tabController, + children: dayContents, + )); } List createTabs(BuildContext context) { @@ -92,7 +88,9 @@ class _RestaurantPageState extends GeneralPageViewState for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add(Container( color: Theme.of(context).colorScheme.background, - child: Tab(key: Key('cantine-page-tab-$i'), text: toString(DayOfWeek.values[i])), + child: Tab( + key: Key('cantine-page-tab-$i'), + text: toString(DayOfWeek.values[i])), )); } @@ -118,7 +116,7 @@ class RestaurantDay extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: const [ Center( - child: Text("Não há informação disponível sobre refeições")), + child: Text("Não há informação disponível sobre refeições")), ], )); } else { diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 8d9ac565b..971c45eed 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; +import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/schedule/widgets/schedule_slot.dart'; class SchedulePage extends StatefulWidget { @@ -20,7 +20,7 @@ class SchedulePage extends StatefulWidget { class SchedulePageState extends State { @override Widget build(BuildContext context) { - return Consumer( + return LazyConsumer( builder: (context, lectureProvider, _) { return SchedulePageView( lectures: lectureProvider.lectures, @@ -51,8 +51,7 @@ class SchedulePageView extends StatefulWidget { for (int i = 0; i < daysOfTheWeek.length; i++) { final Set lectures = {}; for (int j = 0; j < schedule.length; j++) { - if (schedule[j].startTime.weekday-1 == i) lectures.add(schedule[j]); - + if (schedule[j].startTime.weekday - 1 == i) lectures.add(schedule[j]); } aggLectures.add(lectures); } From 972a189aff9fb702b70bce270d9b755e96422107 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 01:08:08 +0100 Subject: [PATCH 03/21] Move local data loaders to the providers --- uni/lib/controller/load_info.dart | 33 +--------- .../model/providers/bus_stop_provider.dart | 21 ++++--- .../model/providers/calendar_provider.dart | 5 +- uni/lib/model/providers/exam_provider.dart | 19 +++--- .../providers/faculty_locations_provider.dart | 20 +----- .../providers/favorite_cards_provider.dart | 2 +- .../home_page_editing_mode_provider.dart | 3 + .../providers/last_user_info_provider.dart | 3 +- uni/lib/model/providers/lecture_provider.dart | 17 +++--- .../library_occupation_provider.dart | 17 +++--- .../providers/profile_state_provider.dart | 61 +++++++++---------- .../model/providers/restaurant_provider.dart | 18 +++--- uni/lib/model/providers/session_provider.dart | 13 ++-- .../providers/state_provider_notifier.dart | 15 ++++- 14 files changed, 111 insertions(+), 136 deletions(-) diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index fc030c70c..c50b0a11e 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -72,7 +72,7 @@ Future loadRemoteUserInfoToState(StateProviders stateProviders) async { .getCourseUnitsAndCourseAverages(session, ucs); stateProviders.profileStateProvider .getUserPrintBalance(printBalance, session); - stateProviders.profileStateProvider.getUserFees(fees, session); + stateProviders.profileStateProvider.fetchUserFees(fees, session); }); final allRequests = Future.wait([ @@ -94,37 +94,6 @@ Future loadRemoteUserInfoToState(StateProviders stateProviders) async { return lastUpdate.future; } -void loadLocalUserInfoToState(StateProviders stateProviders, - {skipDatabaseLookup = false}) async { - final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - - //Logger().i('Setting up user preferences'); - stateProviders.examProvider.setFilteredExams( - await AppSharedPreferences.getFilteredExams(), Completer()); - stateProviders.examProvider - .setHiddenExams(await AppSharedPreferences.getHiddenExams(), Completer()); - - if (userPersistentInfo.item1 != '' && - userPersistentInfo.item2 != '' && - !skipDatabaseLookup) { - Logger().i('Fetching local info from database'); - stateProviders.examProvider.updateStateBasedOnLocalUserExams(); - stateProviders.lectureProvider.updateStateBasedOnLocalUserLectures(); - stateProviders.examProvider.updateStateBasedOnLocalUserExams(); - stateProviders.lectureProvider.updateStateBasedOnLocalUserLectures(); - stateProviders.busStopProvider.updateStateBasedOnLocalUserBusStops(); - stateProviders.profileStateProvider.updateStateBasedOnLocalProfile(); - stateProviders.profileStateProvider.updateStateBasedOnLocalRefreshTimes(); - stateProviders.restaurantProvider.updateStateBasedOnLocalRestaurants(); - stateProviders.lastUserInfoProvider.updateStateBasedOnLocalTime(); - stateProviders.calendarProvider.updateStateBasedOnLocalCalendar(); - stateProviders.profileStateProvider.updateStateBasedOnLocalCourseUnits(); - } - - stateProviders.facultyLocationsProvider.getFacultyLocations(Completer()); -} - Future handleRefresh(StateProviders stateProviders) async { await loadRemoteUserInfoToState(stateProviders); } diff --git a/uni/lib/model/providers/bus_stop_provider.dart b/uni/lib/model/providers/bus_stop_provider.dart index 202b6974b..c86d0ea59 100644 --- a/uni/lib/model/providers/bus_stop_provider.dart +++ b/uni/lib/model/providers/bus_stop_provider.dart @@ -4,10 +4,10 @@ import 'dart:collection'; import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/departures_fetcher.dart'; import 'package:uni/controller/local_storage/app_bus_stop_database.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/entities/trip.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/model/request_status.dart'; class BusStopProvider extends StateProviderNotifier { Map _configuredBusStops = Map.identity(); @@ -18,6 +18,16 @@ class BusStopProvider extends StateProviderNotifier { DateTime get timeStamp => _timeStamp; + @override + void loadFromStorage() async { + final AppBusStopDatabase busStopsDb = AppBusStopDatabase(); + final Map stops = await busStopsDb.busStops(); + + _configuredBusStops = stops; + notifyListeners(); + getUserBusTrips(Completer()); + } + getUserBusTrips(Completer action) async { updateStatus(RequestStatus.busy); @@ -79,13 +89,4 @@ class BusStopProvider extends StateProviderNotifier { final AppBusStopDatabase db = AppBusStopDatabase(); db.updateFavoriteBusStop(stopCode); } - - updateStateBasedOnLocalUserBusStops() async { - final AppBusStopDatabase busStopsDb = AppBusStopDatabase(); - final Map stops = await busStopsDb.busStops(); - - _configuredBusStops = stops; - notifyListeners(); - getUserBusTrips(Completer()); - } } diff --git a/uni/lib/model/providers/calendar_provider.dart b/uni/lib/model/providers/calendar_provider.dart index 4bcbea2b5..37d5fc7eb 100644 --- a/uni/lib/model/providers/calendar_provider.dart +++ b/uni/lib/model/providers/calendar_provider.dart @@ -4,10 +4,10 @@ import 'dart:collection'; import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/calendar_fetcher_html.dart'; import 'package:uni/controller/local_storage/app_calendar_database.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/model/request_status.dart'; class CalendarProvider extends StateProviderNotifier { List _calendar = []; @@ -32,7 +32,8 @@ class CalendarProvider extends StateProviderNotifier { action.complete(); } - updateStateBasedOnLocalCalendar() async { + @override + void loadFromStorage() async { final CalendarDatabase db = CalendarDatabase(); _calendar = await db.calendar(); notifyListeners(); diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/exam_provider.dart index b0b680acb..4d63f1561 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/exam_provider.dart @@ -27,6 +27,18 @@ class ExamProvider extends StateProviderNotifier { UnmodifiableMapView get filteredExamsTypes => UnmodifiableMapView(_filteredExamsTypes); + @override + void loadFromStorage() async { + setFilteredExams( + await AppSharedPreferences.getFilteredExams(), Completer()); + setHiddenExams(await AppSharedPreferences.getHiddenExams(), Completer()); + + final AppExamsDatabase db = AppExamsDatabase(); + final List exs = await db.exams(); + _exams = exs; + notifyListeners(); + } + Future getUserExams( Completer action, ParserExams parserExams, @@ -61,13 +73,6 @@ class ExamProvider extends StateProviderNotifier { action.complete(); } - updateStateBasedOnLocalUserExams() async { - final AppExamsDatabase db = AppExamsDatabase(); - final List exs = await db.exams(); - _exams = exs; - notifyListeners(); - } - updateFilteredExams() async { final exams = await AppSharedPreferences.getFilteredExams(); _filteredExamsTypes = exams; diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/faculty_locations_provider.dart index 0b3ee6478..981bbc1f3 100644 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ b/uni/lib/model/providers/faculty_locations_provider.dart @@ -1,9 +1,6 @@ -import 'dart:async'; import 'dart:collection'; -import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/location_group.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; @@ -13,19 +10,8 @@ class FacultyLocationsProvider extends StateProviderNotifier { UnmodifiableListView get locations => UnmodifiableListView(_locations); - getFacultyLocations(Completer action) async { - try { - updateStatus(RequestStatus.busy); - - _locations = await LocationFetcherAsset().getLocations(); - - notifyListeners(); - updateStatus(RequestStatus.successful); - } catch (e) { - Logger().e('Failed to get locations: ${e.toString()}'); - updateStatus(RequestStatus.failed); - } - - action.complete(); + @override + void loadFromStorage() async { + _locations = await LocationFetcherAsset().getLocations(); } } diff --git a/uni/lib/model/providers/favorite_cards_provider.dart b/uni/lib/model/providers/favorite_cards_provider.dart index 03a326ec4..d4cc583a0 100644 --- a/uni/lib/model/providers/favorite_cards_provider.dart +++ b/uni/lib/model/providers/favorite_cards_provider.dart @@ -11,7 +11,7 @@ class FavoriteCardsProvider extends StateProviderNotifier { } @override - loadFromRemote() async { + loadFromStorage() async { setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); } diff --git a/uni/lib/model/providers/home_page_editing_mode_provider.dart b/uni/lib/model/providers/home_page_editing_mode_provider.dart index e4506f86d..38d135041 100644 --- a/uni/lib/model/providers/home_page_editing_mode_provider.dart +++ b/uni/lib/model/providers/home_page_editing_mode_provider.dart @@ -5,6 +5,9 @@ class HomePageEditingModeProvider extends StateProviderNotifier { bool get isEditing => _isEditing; + @override + void loadFromStorage() {} + setHomePageEditingMode(bool state) { _isEditing = state; notifyListeners(); diff --git a/uni/lib/model/providers/last_user_info_provider.dart b/uni/lib/model/providers/last_user_info_provider.dart index f9774d35c..316429f3f 100644 --- a/uni/lib/model/providers/last_user_info_provider.dart +++ b/uni/lib/model/providers/last_user_info_provider.dart @@ -16,7 +16,8 @@ class LastUserInfoProvider extends StateProviderNotifier { action.complete(); } - updateStateBasedOnLocalTime() async { + @override + void loadFromStorage() async { final AppLastUserInfoUpdateDatabase db = AppLastUserInfoUpdateDatabase(); _lastUpdateTime = await db.getLastUserInfoUpdateTime(); notifyListeners(); diff --git a/uni/lib/model/providers/lecture_provider.dart b/uni/lib/model/providers/lecture_provider.dart index 12c415908..501625a1f 100644 --- a/uni/lib/model/providers/lecture_provider.dart +++ b/uni/lib/model/providers/lecture_provider.dart @@ -7,17 +7,25 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; import 'package:uni/controller/local_storage/app_lectures_database.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/model/request_status.dart'; class LectureProvider extends StateProviderNotifier { List _lectures = []; UnmodifiableListView get lectures => UnmodifiableListView(_lectures); + @override + void loadFromStorage() async { + final AppLecturesDatabase db = AppLecturesDatabase(); + final List lecs = await db.lectures(); + _lectures = lecs; + notifyListeners(); + } + void getUserLectures( Completer action, Tuple2 userPersistentInfo, @@ -55,11 +63,4 @@ class LectureProvider extends StateProviderNotifier { .getLectures(session, profile) .catchError((e) => ScheduleFetcherHtml().getLectures(session, profile)); } - - Future updateStateBasedOnLocalUserLectures() async { - final AppLecturesDatabase db = AppLecturesDatabase(); - final List lecs = await db.lectures(); - _lectures = lecs; - notifyListeners(); - } } diff --git a/uni/lib/model/providers/library_occupation_provider.dart b/uni/lib/model/providers/library_occupation_provider.dart index 038cb8ffc..5cd950667 100644 --- a/uni/lib/model/providers/library_occupation_provider.dart +++ b/uni/lib/model/providers/library_occupation_provider.dart @@ -13,6 +13,15 @@ class LibraryOccupationProvider extends StateProviderNotifier { LibraryOccupation? get occupation => _occupation; + @override + void loadFromStorage() async { + final LibraryOccupationDatabase db = LibraryOccupationDatabase(); + final LibraryOccupation occupation = await db.occupation(); + + _occupation = occupation; + notifyListeners(); + } + void getLibraryOccupation( Session session, Completer action, @@ -36,12 +45,4 @@ class LibraryOccupationProvider extends StateProviderNotifier { } action.complete(); } - - Future updateStateBasedOnLocalOccupation() async { - final LibraryOccupationDatabase db = LibraryOccupationDatabase(); - final LibraryOccupation occupation = await db.occupation(); - - _occupation = occupation; - notifyListeners(); - } } diff --git a/uni/lib/model/providers/profile_state_provider.dart b/uni/lib/model/providers/profile_state_provider.dart index 619b7a6de..e065dbe0b 100644 --- a/uni/lib/model/providers/profile_state_provider.dart +++ b/uni/lib/model/providers/profile_state_provider.dart @@ -14,12 +14,12 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/local_storage/app_user_database.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/model/request_status.dart'; // ignore: always_use_package_imports import '../../controller/fetchers/all_course_units_fetcher.dart'; @@ -39,26 +39,44 @@ class ProfileStateProvider extends StateProviderNotifier { Profile get profile => _profile; - updateStateBasedOnLocalProfile() async { + @override + void loadFromStorage() async { + loadCourses(); + loadBalanceRefreshTimes(); + loadCourseUnits(); + } + + void loadCourses() async { final profileDb = AppUserDataDatabase(); - final Profile profile = await profileDb.getUserData(); + _profile = await profileDb.getUserData(); final AppCoursesDatabase coursesDb = AppCoursesDatabase(); final List courses = await coursesDb.courses(); - profile.courses = courses; + _profile.courses = courses; + } + + void loadBalanceRefreshTimes() async { + final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); + final Map refreshTimes = + await refreshTimesDb.refreshTimes(); - // Build courses states map - final Map coursesStates = {}; - for (Course course in profile.courses) { - coursesStates[course.name!] = course.state!; + final printRefreshTime = refreshTimes['print']; + final feesRefreshTime = refreshTimes['fees']; + if (printRefreshTime != null) { + _printRefreshTime = DateTime.parse(printRefreshTime); } + if (feesRefreshTime != null) { + _feesRefreshTime = DateTime.parse(feesRefreshTime); + } + } - _profile = profile; - notifyListeners(); + void loadCourseUnits() async { + final AppCourseUnitsDatabase db = AppCourseUnitsDatabase(); + _currUcs = await db.courseUnits(); } - getUserFees(Completer action, Session session) async { + fetchUserFees(Completer action, Session session) async { try { final response = await FeesFetcher().getUserFeesResponse(session); @@ -134,21 +152,6 @@ class ProfileStateProvider extends StateProviderNotifier { action.complete(); } - updateStateBasedOnLocalRefreshTimes() async { - final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); - final Map refreshTimes = - await refreshTimesDb.refreshTimes(); - - final printRefreshTime = refreshTimes['print']; - final feesRefreshTime = refreshTimes['fees']; - if (printRefreshTime != null) { - _printRefreshTime = DateTime.parse(printRefreshTime); - } - if (feesRefreshTime != null) { - _feesRefreshTime = DateTime.parse(feesRefreshTime); - } - } - getUserInfo(Completer action, Session session) async { try { updateStatus(RequestStatus.busy); @@ -204,10 +207,4 @@ class ProfileStateProvider extends StateProviderNotifier { action.complete(); } - - updateStateBasedOnLocalCourseUnits() async { - final AppCourseUnitsDatabase db = AppCourseUnitsDatabase(); - _currUcs = await db.courseUnits(); - notifyListeners(); - } } diff --git a/uni/lib/model/providers/restaurant_provider.dart b/uni/lib/model/providers/restaurant_provider.dart index 54765609d..523e7003c 100644 --- a/uni/lib/model/providers/restaurant_provider.dart +++ b/uni/lib/model/providers/restaurant_provider.dart @@ -2,21 +2,26 @@ import 'dart:async'; import 'dart:collection'; import 'package:logger/logger.dart'; +import 'package:uni/controller/fetchers/restaurant_fetcher.dart'; import 'package:uni/controller/local_storage/app_restaurant_database.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; - import 'package:uni/model/request_status.dart'; -import 'package:uni/controller/fetchers/restaurant_fetcher.dart'; - class RestaurantProvider extends StateProviderNotifier { List _restaurants = []; UnmodifiableListView get restaurants => UnmodifiableListView(_restaurants); + @override + Future loadFromStorage() async { + final RestaurantDatabase restaurantDb = RestaurantDatabase(); + final List restaurants = await restaurantDb.getRestaurants(); + _restaurants = restaurants; + } + void getRestaurantsFromFetcher( Completer action, Session session) async { try { @@ -36,11 +41,4 @@ class RestaurantProvider extends StateProviderNotifier { } action.complete(); } - - void updateStateBasedOnLocalRestaurants() async { - final RestaurantDatabase restaurantDb = RestaurantDatabase(); - final List restaurants = await restaurantDb.getRestaurants(); - _restaurants = restaurants; - notifyListeners(); - } } diff --git a/uni/lib/model/providers/session_provider.dart b/uni/lib/model/providers/session_provider.dart index 44cf54aa1..82ac9fb8f 100644 --- a/uni/lib/model/providers/session_provider.dart +++ b/uni/lib/model/providers/session_provider.dart @@ -8,10 +8,10 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/model/entities/login_exceptions.dart'; -import 'package:uni/model/request_status.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/model/request_status.dart'; class SessionProvider extends StateProviderNotifier { Session _session = Session(); @@ -22,6 +22,9 @@ class SessionProvider extends StateProviderNotifier { UnmodifiableListView get faculties => UnmodifiableListView(_faculties); + @override + void loadFromStorage() {} + login( Completer action, String username, @@ -46,7 +49,7 @@ class SessionProvider extends StateProviderNotifier { Future.delayed(const Duration(seconds: 20), () => {NotificationManager().initializeNotifications()}); - loadLocalUserInfoToState(stateProviders, skipDatabaseLookup: true); + //loadLocalUserInfoToState(stateProviders, skipDatabaseLookup: true); await loadRemoteUserInfoToState(stateProviders); usernameController.clear(); @@ -59,7 +62,7 @@ class SessionProvider extends StateProviderNotifier { await NetworkRouter.loginInSigarra(username, password, faculties); if (isPasswordExpired(responseHtml)) { action.completeError(ExpiredCredentialsException()); - }else{ + } else { action.completeError(WrongCredentialsException()); } updateStatus(RequestStatus.failed); @@ -78,10 +81,10 @@ class SessionProvider extends StateProviderNotifier { StateProviders stateProviders, {Completer? action}) async { try { - loadLocalUserInfoToState(stateProviders); + //loadLocalUserInfoToState(stateProviders); updateStatus(RequestStatus.busy); _session = await NetworkRouter.login(username, password, faculties, true); - notifyListeners(); + //notifyListeners(); if (session.authenticated) { await loadRemoteUserInfoToState(stateProviders); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 2c6f5a955..ea623961b 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,5 +1,6 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { @@ -19,7 +20,15 @@ abstract class StateProviderNotifier extends ChangeNotifier { } _initialized = true; - loadFromStorage(); + + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final sessionIsPersistent = + userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; + if (sessionIsPersistent) { + loadFromStorage(); + } + if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { loadFromRemote(); } @@ -27,7 +36,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { notifyListeners(); } - void loadFromStorage() async {} + void loadFromStorage(); - void loadFromRemote() async {} + void loadFromRemote() {} } From b1e10700f296ec34cb007d56a19cf004795d7e5d Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 01:58:14 +0100 Subject: [PATCH 04/21] Move remote fetching logic to providers --- uni/lib/controller/load_info.dart | 74 ++------ uni/lib/main.dart | 14 +- uni/lib/model/entities/profile.dart | 7 +- .../model/providers/bus_stop_provider.dart | 7 + .../model/providers/calendar_provider.dart | 8 + uni/lib/model/providers/exam_provider.dart | 14 +- .../providers/faculty_locations_provider.dart | 6 + .../providers/favorite_cards_provider.dart | 10 +- .../home_page_editing_mode_provider.dart | 5 + .../providers/last_user_info_provider.dart | 5 + uni/lib/model/providers/lecture_provider.dart | 16 +- .../library_occupation_provider.dart | 8 + ...te_provider.dart => profile_provider.dart} | 37 ++-- .../model/providers/restaurant_provider.dart | 8 + uni/lib/model/providers/session_provider.dart | 8 +- .../providers/state_provider_notifier.dart | 8 +- uni/lib/model/providers/state_providers.dart | 6 +- uni/lib/view/course_units/course_units.dart | 7 +- uni/lib/view/lazy_consumer.dart | 10 +- uni/lib/view/profile/profile.dart | 4 +- .../profile/widgets/account_info_card.dart | 4 +- .../view/profile/widgets/print_info_card.dart | 4 +- uni/test/integration/src/exams_page_test.dart | 33 ++-- .../integration/src/schedule_page_test.dart | 159 +++++++++--------- .../unit/providers/exams_provider_test.dart | 60 ++++--- .../unit/providers/lecture_provider_test.dart | 6 +- 26 files changed, 298 insertions(+), 230 deletions(-) rename uni/lib/model/providers/{profile_state_provider.dart => profile_provider.dart} (86%) diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index c50b0a11e..746af7fd6 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -1,16 +1,12 @@ import 'dart:async'; import 'dart:io'; -import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:logger/logger.dart'; -import 'package:tuple/tuple.dart'; -import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/local_storage/file_offline_storage.dart'; -import 'package:uni/controller/parsers/parser_exams.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_providers.dart'; -Future loadReloginInfo(StateProviders stateProviders) async { +/*Future loadReloginInfo(StateProviders stateProviders) async { final Tuple2 userPersistentCredentials = await AppSharedPreferences.getPersistentUserInfo(); final String userName = userPersistentCredentials.item1; @@ -24,10 +20,10 @@ Future loadReloginInfo(StateProviders stateProviders) async { return action.future; } return Future.error('No credentials stored'); -} +}*/ -Future loadRemoteUserInfoToState(StateProviders stateProviders) async { - if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { +Future loadUserProfileInfoFromRemote(StateProviders stateProviders) async { + /*if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { return; } @@ -36,66 +32,18 @@ Future loadRemoteUserInfoToState(StateProviders stateProviders) async { final session = stateProviders.sessionProvider.session; if (!session.authenticated && session.persistentSession) { await loadReloginInfo(stateProviders); - } - - final Completer userInfo = Completer(), - ucs = Completer(), - exams = Completer(), - schedule = Completer(), - printBalance = Completer(), - fees = Completer(), - trips = Completer(), - lastUpdate = Completer(), - restaurants = Completer(), - libraryOccupation = Completer(), - calendar = Completer(); - - stateProviders.profileStateProvider.getUserInfo(userInfo, session); - stateProviders.busStopProvider.getUserBusTrips(trips); - stateProviders.restaurantProvider - .getRestaurantsFromFetcher(restaurants, session); - stateProviders.calendarProvider.getCalendarFromFetcher(session, calendar); - stateProviders.libraryOccupationProvider - .getLibraryOccupation(session, libraryOccupation); - - final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + }*/ - userInfo.future.then((value) { - final profile = stateProviders.profileStateProvider.profile; - final currUcs = stateProviders.profileStateProvider.currUcs; - stateProviders.examProvider.getUserExams( - exams, ParserExams(), userPersistentInfo, profile, session, currUcs); - stateProviders.lectureProvider - .getUserLectures(schedule, userPersistentInfo, session, profile); - stateProviders.profileStateProvider - .getCourseUnitsAndCourseAverages(session, ucs); - stateProviders.profileStateProvider - .getUserPrintBalance(printBalance, session); - stateProviders.profileStateProvider.fetchUserFees(fees, session); - }); + stateProviders.profileStateProvider + .fetchUserInfo(Completer(), stateProviders.sessionProvider.session); - final allRequests = Future.wait([ - ucs.future, - exams.future, - schedule.future, - printBalance.future, - fees.future, - userInfo.future, - trips.future, - restaurants.future, - libraryOccupation.future, - calendar.future - ]); - allRequests.then((futures) { - stateProviders.lastUserInfoProvider - .setLastUserInfoUpdateTimestamp(lastUpdate); - }); - return lastUpdate.future; + stateProviders.lastUserInfoProvider + .setLastUserInfoUpdateTimestamp(Completer()); } Future handleRefresh(StateProviders stateProviders) async { - await loadRemoteUserInfoToState(stateProviders); + Logger().e('TODO: handleRefresh'); + // await loadRemoteUserInfoToState(stateProviders); } Future loadProfilePicture(Session session, {forceRetrieval = false}) { diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 9ca04849a..aea2edfae 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -17,7 +17,7 @@ import 'package:uni/model/providers/home_page_editing_mode_provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; @@ -30,10 +30,10 @@ import 'package:uni/view/common_widgets/page_transition.dart'; import 'package:uni/view/course_units/course_units.dart'; import 'package:uni/view/exams/exams.dart'; import 'package:uni/view/home/home.dart'; +import 'package:uni/view/library/library.dart'; import 'package:uni/view/locations/locations.dart'; import 'package:uni/view/logout_route.dart'; import 'package:uni/view/navigation_service.dart'; -import 'package:uni/view/library/library.dart'; import 'package:uni/view/restaurant/restaurant_page_view.dart'; import 'package:uni/view/schedule/schedule.dart'; import 'package:uni/view/splash/splash.dart'; @@ -52,7 +52,7 @@ Future main() async { ExamProvider(), BusStopProvider(), RestaurantProvider(), - ProfileStateProvider(), + ProfileProvider(), SessionProvider(), CalendarProvider(), LibraryOccupationProvider(), @@ -64,10 +64,10 @@ Future main() async { OnStartUp.onStart(stateProviders.sessionProvider); WidgetsFlutterBinding.ensureInitialized(); - await Workmanager().initialize(workerStartCallback, - isInDebugMode: !kReleaseMode // run workmanager in debug mode when app is in debug mode - ); - + await Workmanager().initialize(workerStartCallback, + isInDebugMode: + !kReleaseMode // run workmanager in debug mode when app is in debug mode + ); final savedTheme = await AppSharedPreferences.getThemeMode(); await SentryFlutter.init((options) { diff --git a/uni/lib/model/entities/profile.dart b/uni/lib/model/entities/profile.dart index 6c222c657..b5fac913d 100644 --- a/uni/lib/model/entities/profile.dart +++ b/uni/lib/model/entities/profile.dart @@ -2,15 +2,17 @@ import 'dart:convert'; import 'package:tuple/tuple.dart'; import 'package:uni/model/entities/course.dart'; +import 'package:uni/model/entities/course_unit.dart'; /// Stores information about the user's profile. class Profile { final String name; final String email; - late List courses; final String printBalance; final String feesBalance; final String feesLimit; + late List courses; + late List currentCourseUnits; Profile( {this.name = '', @@ -19,7 +21,8 @@ class Profile { this.printBalance = '', this.feesBalance = '', this.feesLimit = ''}) - : courses = courses ?? []; + : courses = courses ?? [], + currentCourseUnits = []; /// Creates a new instance from a JSON object. static Profile fromResponse(dynamic response) { diff --git a/uni/lib/model/providers/bus_stop_provider.dart b/uni/lib/model/providers/bus_stop_provider.dart index c86d0ea59..302347b64 100644 --- a/uni/lib/model/providers/bus_stop_provider.dart +++ b/uni/lib/model/providers/bus_stop_provider.dart @@ -5,6 +5,8 @@ import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/departures_fetcher.dart'; import 'package:uni/controller/local_storage/app_bus_stop_database.dart'; import 'package:uni/model/entities/bus_stop.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/entities/trip.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; @@ -28,6 +30,11 @@ class BusStopProvider extends StateProviderNotifier { getUserBusTrips(Completer()); } + @override + void loadFromRemote(Session session, Profile profile) { + getUserBusTrips(Completer()); + } + getUserBusTrips(Completer action) async { updateStatus(RequestStatus.busy); diff --git a/uni/lib/model/providers/calendar_provider.dart b/uni/lib/model/providers/calendar_provider.dart index 37d5fc7eb..281e1b743 100644 --- a/uni/lib/model/providers/calendar_provider.dart +++ b/uni/lib/model/providers/calendar_provider.dart @@ -5,6 +5,7 @@ import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/calendar_fetcher_html.dart'; import 'package:uni/controller/local_storage/app_calendar_database.dart'; import 'package:uni/model/entities/calendar_event.dart'; +import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; @@ -15,6 +16,13 @@ class CalendarProvider extends StateProviderNotifier { UnmodifiableListView get calendar => UnmodifiableListView(_calendar); + @override + Future loadFromRemote(Session session, Profile profile) async { + final Completer action = Completer(); + getCalendarFromFetcher(session, action); + await action.future; + } + getCalendarFromFetcher(Session session, Completer action) async { try { updateStatus(RequestStatus.busy); diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/exam_provider.dart index 4d63f1561..1192abfdb 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/exam_provider.dart @@ -39,7 +39,19 @@ class ExamProvider extends StateProviderNotifier { notifyListeners(); } - Future getUserExams( + @override + void loadFromRemote(Session session, Profile profile) async { + final Completer action = Completer(); + final ParserExams parserExams = ParserExams(); + final Tuple2 userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + + fetchUserExams(action, parserExams, userPersistentInfo, profile, session, + profile.currentCourseUnits); + await action.future; + } + + Future fetchUserExams( Completer action, ParserExams parserExams, Tuple2 userPersistentInfo, diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/faculty_locations_provider.dart index 981bbc1f3..0e1af6403 100644 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ b/uni/lib/model/providers/faculty_locations_provider.dart @@ -4,6 +4,9 @@ import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset. import 'package:uni/model/entities/location_group.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import '../entities/profile.dart'; +import '../entities/session.dart'; + class FacultyLocationsProvider extends StateProviderNotifier { List _locations = []; @@ -14,4 +17,7 @@ class FacultyLocationsProvider extends StateProviderNotifier { void loadFromStorage() async { _locations = await LocationFetcherAsset().getLocations(); } + + @override + Future loadFromRemote(Session session, Profile profile) async {} } diff --git a/uni/lib/model/providers/favorite_cards_provider.dart b/uni/lib/model/providers/favorite_cards_provider.dart index d4cc583a0..79be2a624 100644 --- a/uni/lib/model/providers/favorite_cards_provider.dart +++ b/uni/lib/model/providers/favorite_cards_provider.dart @@ -1,20 +1,22 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/utils/favorite_widget_type.dart'; class FavoriteCardsProvider extends StateProviderNotifier { List _favoriteCards = []; - List get favoriteCards { - ensureInitialized(); - return _favoriteCards.toList(); - } + List get favoriteCards => _favoriteCards.toList(); @override loadFromStorage() async { setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); } + @override + Future loadFromRemote(Session session, Profile profile) async {} + setFavoriteCards(List favoriteCards) { _favoriteCards = favoriteCards; notifyListeners(); diff --git a/uni/lib/model/providers/home_page_editing_mode_provider.dart b/uni/lib/model/providers/home_page_editing_mode_provider.dart index 38d135041..e45457874 100644 --- a/uni/lib/model/providers/home_page_editing_mode_provider.dart +++ b/uni/lib/model/providers/home_page_editing_mode_provider.dart @@ -1,3 +1,5 @@ +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; class HomePageEditingModeProvider extends StateProviderNotifier { @@ -8,6 +10,9 @@ class HomePageEditingModeProvider extends StateProviderNotifier { @override void loadFromStorage() {} + @override + Future loadFromRemote(Session session, Profile profile) async {} + setHomePageEditingMode(bool state) { _isEditing = state; notifyListeners(); diff --git a/uni/lib/model/providers/last_user_info_provider.dart b/uni/lib/model/providers/last_user_info_provider.dart index 316429f3f..724091265 100644 --- a/uni/lib/model/providers/last_user_info_provider.dart +++ b/uni/lib/model/providers/last_user_info_provider.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'package:uni/controller/local_storage/app_last_user_info_update_database.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; class LastUserInfoProvider extends StateProviderNotifier { @@ -22,4 +24,7 @@ class LastUserInfoProvider extends StateProviderNotifier { _lastUpdateTime = await db.getLastUserInfoUpdateTime(); notifyListeners(); } + + @override + Future loadFromRemote(Session session, Profile profile) async {} } diff --git a/uni/lib/model/providers/lecture_provider.dart b/uni/lib/model/providers/lecture_provider.dart index 501625a1f..d1e26fa96 100644 --- a/uni/lib/model/providers/lecture_provider.dart +++ b/uni/lib/model/providers/lecture_provider.dart @@ -7,6 +7,7 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; import 'package:uni/controller/local_storage/app_lectures_database.dart'; +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; @@ -21,12 +22,21 @@ class LectureProvider extends StateProviderNotifier { @override void loadFromStorage() async { final AppLecturesDatabase db = AppLecturesDatabase(); - final List lecs = await db.lectures(); - _lectures = lecs; + final List lectures = await db.lectures(); + _lectures = lectures; notifyListeners(); } - void getUserLectures( + @override + Future loadFromRemote(Session session, Profile profile) async { + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final Completer action = Completer(); + fetchUserLectures(action, userPersistentInfo, session, profile); + await action.future; + } + + void fetchUserLectures( Completer action, Tuple2 userPersistentInfo, Session session, diff --git a/uni/lib/model/providers/library_occupation_provider.dart b/uni/lib/model/providers/library_occupation_provider.dart index 5cd950667..31b8092a1 100644 --- a/uni/lib/model/providers/library_occupation_provider.dart +++ b/uni/lib/model/providers/library_occupation_provider.dart @@ -4,6 +4,7 @@ import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/library_occupation_fetcher.dart'; import 'package:uni/controller/local_storage/app_library_occupation_database.dart'; import 'package:uni/model/entities/library_occupation.dart'; +import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; @@ -22,6 +23,13 @@ class LibraryOccupationProvider extends StateProviderNotifier { notifyListeners(); } + @override + Future loadFromRemote(Session session, Profile profile) async { + final Completer action = Completer(); + getLibraryOccupation(session, action); + await action.future; + } + void getLibraryOccupation( Session session, Completer action, diff --git a/uni/lib/model/providers/profile_state_provider.dart b/uni/lib/model/providers/profile_provider.dart similarity index 86% rename from uni/lib/model/providers/profile_state_provider.dart rename to uni/lib/model/providers/profile_provider.dart index e065dbe0b..35bb27a9f 100644 --- a/uni/lib/model/providers/profile_state_provider.dart +++ b/uni/lib/model/providers/profile_provider.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:collection'; import 'package:logger/logger.dart'; import 'package:tuple/tuple.dart'; @@ -15,7 +14,6 @@ import 'package:uni/controller/local_storage/app_user_database.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; import 'package:uni/model/entities/course.dart'; -import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; @@ -24,15 +22,11 @@ import 'package:uni/model/request_status.dart'; // ignore: always_use_package_imports import '../../controller/fetchers/all_course_units_fetcher.dart'; -class ProfileStateProvider extends StateProviderNotifier { - List _currUcs = []; +class ProfileProvider extends StateProviderNotifier { Profile _profile = Profile(); DateTime? _feesRefreshTime; DateTime? _printRefreshTime; - UnmodifiableListView get currUcs => - UnmodifiableListView(_currUcs); - String get feesRefreshTime => _feesRefreshTime.toString(); String get printRefreshTime => _printRefreshTime.toString(); @@ -46,6 +40,20 @@ class ProfileStateProvider extends StateProviderNotifier { loadCourseUnits(); } + @override + Future loadFromRemote(Session session, Profile profile) async { + final Completer userFeesAction = Completer(); + fetchUserFees(userFeesAction, session); + + final Completer printBalanceAction = Completer(); + fetchUserPrintBalance(printBalanceAction, session); + + final Completer courseUnitsAction = Completer(); + fetchCourseUnitsAndCourseAverages(session, courseUnitsAction); + + await Future.wait([userFeesAction.future, printBalanceAction.future]); + } + void loadCourses() async { final profileDb = AppUserDataDatabase(); _profile = await profileDb.getUserData(); @@ -73,7 +81,7 @@ class ProfileStateProvider extends StateProviderNotifier { void loadCourseUnits() async { final AppCourseUnitsDatabase db = AppCourseUnitsDatabase(); - _currUcs = await db.courseUnits(); + profile.currentCourseUnits = await db.courseUnits(); } fetchUserFees(Completer action, Session session) async { @@ -118,7 +126,7 @@ class ProfileStateProvider extends StateProviderNotifier { refreshTimesDatabase.saveRefreshTime(db, currentTime); } - getUserPrintBalance(Completer action, Session session) async { + fetchUserPrintBalance(Completer action, Session session) async { try { final response = await PrintFetcher().getUserPrintsResponse(session); final String printBalance = await getPrintsBalance(response); @@ -152,7 +160,7 @@ class ProfileStateProvider extends StateProviderNotifier { action.complete(); } - getUserInfo(Completer action, Session session) async { + fetchUserInfo(Completer action, Session session) async { try { updateStatus(RequestStatus.busy); @@ -162,7 +170,7 @@ class ProfileStateProvider extends StateProviderNotifier { final ucs = CurrentCourseUnitsFetcher() .getCurrentCourseUnits(session) - .then((res) => _currUcs = res); + .then((res) => _profile.currentCourseUnits = res); await Future.wait([profile, ucs]); notifyListeners(); updateStatus(RequestStatus.successful); @@ -181,12 +189,12 @@ class ProfileStateProvider extends StateProviderNotifier { action.complete(); } - getCourseUnitsAndCourseAverages( + fetchCourseUnitsAndCourseAverages( Session session, Completer action) async { updateStatus(RequestStatus.busy); try { final List courses = profile.courses; - _currUcs = await AllCourseUnitsFetcher() + _profile.currentCourseUnits = await AllCourseUnitsFetcher() .getAllCourseUnitsAndCourseAverages(courses, session); updateStatus(RequestStatus.successful); notifyListeners(); @@ -198,7 +206,8 @@ class ProfileStateProvider extends StateProviderNotifier { await coursesDb.saveNewCourses(courses); final courseUnitsDatabase = AppCourseUnitsDatabase(); - await courseUnitsDatabase.saveNewCourseUnits(currUcs); + await courseUnitsDatabase + .saveNewCourseUnits(_profile.currentCourseUnits); } } catch (e) { Logger().e('Failed to get all user ucs: $e'); diff --git a/uni/lib/model/providers/restaurant_provider.dart b/uni/lib/model/providers/restaurant_provider.dart index 523e7003c..d6a7a7556 100644 --- a/uni/lib/model/providers/restaurant_provider.dart +++ b/uni/lib/model/providers/restaurant_provider.dart @@ -4,6 +4,7 @@ import 'dart:collection'; import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/restaurant_fetcher.dart'; import 'package:uni/controller/local_storage/app_restaurant_database.dart'; +import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; @@ -22,6 +23,13 @@ class RestaurantProvider extends StateProviderNotifier { _restaurants = restaurants; } + @override + Future loadFromRemote(Session session, Profile profile) async { + final Completer action = Completer(); + getRestaurantsFromFetcher(action, session); + await action.future; + } + void getRestaurantsFromFetcher( Completer action, Session session) async { try { diff --git a/uni/lib/model/providers/session_provider.dart b/uni/lib/model/providers/session_provider.dart index 82ac9fb8f..5ef686b5d 100644 --- a/uni/lib/model/providers/session_provider.dart +++ b/uni/lib/model/providers/session_provider.dart @@ -8,6 +8,7 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/model/entities/login_exceptions.dart'; +import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; @@ -25,6 +26,9 @@ class SessionProvider extends StateProviderNotifier { @override void loadFromStorage() {} + @override + Future loadFromRemote(Session session, Profile profile) async {} + login( Completer action, String username, @@ -50,7 +54,7 @@ class SessionProvider extends StateProviderNotifier { () => {NotificationManager().initializeNotifications()}); //loadLocalUserInfoToState(stateProviders, skipDatabaseLookup: true); - await loadRemoteUserInfoToState(stateProviders); + await loadUserProfileInfoFromRemote(stateProviders); usernameController.clear(); passwordController.clear(); @@ -87,7 +91,7 @@ class SessionProvider extends StateProviderNotifier { //notifyListeners(); if (session.authenticated) { - await loadRemoteUserInfoToState(stateProviders); + await loadUserProfileInfoFromRemote(stateProviders); Future.delayed(const Duration(seconds: 20), () => {NotificationManager().initializeNotifications()}); updateStatus(RequestStatus.successful); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index ea623961b..b818caddc 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,6 +1,8 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { @@ -14,7 +16,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { notifyListeners(); } - void ensureInitialized() async { + void ensureInitialized(Session session, Profile profile) async { if (_initialized) { return; } @@ -30,7 +32,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { } if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - loadFromRemote(); + loadFromRemote(session, profile); } notifyListeners(); @@ -38,5 +40,5 @@ abstract class StateProviderNotifier extends ChangeNotifier { void loadFromStorage(); - void loadFromRemote() {} + void loadFromRemote(Session session, Profile profile); } diff --git a/uni/lib/model/providers/state_providers.dart b/uni/lib/model/providers/state_providers.dart index e6d36398d..f8a83dcbc 100644 --- a/uni/lib/model/providers/state_providers.dart +++ b/uni/lib/model/providers/state_providers.dart @@ -9,7 +9,7 @@ import 'package:uni/model/providers/home_page_editing_mode_provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; @@ -18,7 +18,7 @@ class StateProviders { final ExamProvider examProvider; final BusStopProvider busStopProvider; final RestaurantProvider restaurantProvider; - final ProfileStateProvider profileStateProvider; + final ProfileProvider profileStateProvider; final SessionProvider sessionProvider; final CalendarProvider calendarProvider; final LibraryOccupationProvider libraryOccupationProvider; @@ -50,7 +50,7 @@ class StateProviders { final restaurantProvider = Provider.of(context, listen: false); final profileStateProvider = - Provider.of(context, listen: false); + Provider.of(context, listen: false); final sessionProvider = Provider.of(context, listen: false); final calendarProvider = diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index ba7abcd5e..678e79ea5 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -1,7 +1,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:uni/model/entities/course_unit.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/page_title.dart'; @@ -28,9 +28,10 @@ class CourseUnitsPageViewState @override Widget getBody(BuildContext context) { - return LazyConsumer( + return LazyConsumer( builder: (context, profileProvider, _) { - final List courseUnits = profileProvider.currUcs; + final List courseUnits = + profileProvider.profile.currentCourseUnits; List availableYears = []; List availableSemesters = []; if (courseUnits.isNotEmpty) { diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 925368b1d..0027c7522 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -1,5 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; class LazyConsumer extends StatelessWidget { @@ -12,9 +14,15 @@ class LazyConsumer extends StatelessWidget { @override Widget build(BuildContext context) { + final session = + Provider.of(context, listen: false).session; + final profile = + Provider.of(context, listen: false).profile; WidgetsBinding.instance.addPostFrameCallback((_) { - Provider.of(context, listen: false).ensureInitialized(); + Provider.of(context, listen: false) + .ensureInitialized(session, profile); }); + return Consumer( builder: builder, ); diff --git a/uni/lib/view/profile/profile.dart b/uni/lib/view/profile/profile.dart index 4c884f02a..1c988249e 100644 --- a/uni/lib/view/profile/profile.dart +++ b/uni/lib/view/profile/profile.dart @@ -1,6 +1,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/account_info_card.dart'; @@ -18,7 +18,7 @@ class ProfilePageView extends StatefulWidget { class ProfilePageViewState extends SecondaryPageViewState { @override Widget getBody(BuildContext context) { - return LazyConsumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; final List courseWidgets = profile.courses diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index 0c3265635..4ffbcbbee 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/tuition_notification_switch.dart'; @@ -15,7 +15,7 @@ class AccountInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return LazyConsumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; return Column(children: [ diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index 34bad39f0..264a85689 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/profile_state_provider.dart'; +import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/create_print_mb_dialog.dart'; @@ -13,7 +13,7 @@ class PrintInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return LazyConsumer( + return LazyConsumer( builder: (context, profileStateProvider, _) { final profile = profileStateProvider.profile; return Column( diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index f8adeed87..f3d83b34d 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; @@ -29,25 +30,33 @@ void main() { final mockClient = MockClient(); final mockResponse = MockResponse(); final sopeCourseUnit = CourseUnit( - abbreviation: 'SOPE', occurrId: 0, name: 'Sistemas Operativos', status: 'V'); + abbreviation: 'SOPE', + occurrId: 0, + name: 'Sistemas Operativos', + status: 'V'); final sdisCourseUnit = CourseUnit( - abbreviation: 'SDIS', name: 'Sistemas Distribuídos', occurrId: 0, status: 'V'); + abbreviation: 'SDIS', + name: 'Sistemas Distribuídos', + occurrId: 0, + status: 'V'); final DateTime beginSopeExam = DateTime.parse('2099-11-18 17:00'); final DateTime endSopeExam = DateTime.parse('2099-11-18 19:00'); - final sopeExam = Exam('44426', beginSopeExam, endSopeExam, 'SOPE', [], 'MT', 'feup'); + final sopeExam = + Exam('44426', beginSopeExam, endSopeExam, 'SOPE', [], 'MT', 'feup'); final DateTime beginSdisExam = DateTime.parse('2099-10-21 17:00'); final DateTime endSdisExam = DateTime.parse('2099-10-21 19:00'); - final sdisExam = Exam('44425', beginSdisExam, endSdisExam, 'SDIS',[], 'MT', 'feup'); + final sdisExam = + Exam('44425', beginSdisExam, endSdisExam, 'SDIS', [], 'MT', 'feup'); final DateTime beginMdisExam = DateTime.parse('2099-10-22 17:00'); final DateTime endMdisExam = DateTime.parse('2099-10-22 19:00'); - final mdisExam = Exam('44429', beginMdisExam, endMdisExam, 'MDIS',[], 'MT', 'feup'); - + final mdisExam = + Exam('44429', beginMdisExam, endMdisExam, 'MDIS', [], 'MT', 'feup'); + final Map filteredExams = {}; - for(String type in Exam.displayedTypes) { + for (String type in Exam.displayedTypes) { filteredExams[type] = true; } - final profile = Profile(); profile.courses = [Course(id: 7474, faculty: 'feup')]; @@ -75,7 +84,7 @@ void main() { expect(find.byKey(Key('$mdisExam-exam')), findsNothing); final Completer completer = Completer(); - examProvider.getUserExams( + examProvider.fetchUserExams( completer, ParserExams(), const Tuple2('', ''), @@ -114,7 +123,7 @@ void main() { expect(find.byKey(Key('$sopeExam-exam')), findsNothing); final Completer completer = Completer(); - examProvider.getUserExams( + examProvider.fetchUserExams( completer, ParserExams(), const Tuple2('', ''), @@ -128,7 +137,7 @@ void main() { expect(find.byKey(Key('$sdisExam-exam')), findsOneWidget); expect(find.byKey(Key('$sopeExam-exam')), findsOneWidget); expect(find.byIcon(Icons.filter_alt), findsOneWidget); - + final Completer settingFilteredExams = Completer(); filteredExams['ExamDoesNotExist'] = true; examProvider.setFilteredExams(filteredExams, settingFilteredExams); @@ -160,7 +169,7 @@ void main() { expect(okButton, findsOneWidget); await tester.tap(okButton); - + await tester.pumpAndSettle(); expect(find.byKey(Key('$sdisExam-exam')), findsNothing); diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index 495f14fe0..ba74d834a 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; @@ -32,91 +33,91 @@ class UriMatcher extends CustomMatcher { } void main() { - group('SchedulePage Integration Tests', () { - final mockClient = MockClient(); - final mockResponse = MockResponse(); - final badMockResponse = MockResponse(); + group('SchedulePage Integration Tests', () { + final mockClient = MockClient(); + final mockResponse = MockResponse(); + final badMockResponse = MockResponse(); + + const htmlFetcherIdentifier = 'hor_geral.estudantes_view'; + const jsonFetcherIdentifier = 'mob_hor_geral.estudante'; - const htmlFetcherIdentifier = 'hor_geral.estudantes_view'; - const jsonFetcherIdentifier = 'mob_hor_geral.estudante'; - - Future testSchedule(WidgetTester tester) async { - final profile = Profile(); - profile.courses = [Course(id: 7474)]; + Future testSchedule(WidgetTester tester) async { + final profile = Profile(); + profile.courses = [Course(id: 7474)]; - NetworkRouter.httpClient = mockClient; - when(badMockResponse.statusCode).thenReturn(500); + NetworkRouter.httpClient = mockClient; + when(badMockResponse.statusCode).thenReturn(500); - final scheduleProvider = LectureProvider(); + final scheduleProvider = LectureProvider(); - const widget = SchedulePage(); + const widget = SchedulePage(); final providers = [ ChangeNotifierProvider(create: (_) => scheduleProvider), ChangeNotifierProvider(create: (_) => LastUserInfoProvider()), - ]; - - await tester.pumpWidget(testableWidget(widget, providers: providers)); - - const scheduleSlotTimeKey1 = 'schedule-slot-time-11:00-13:00'; - const scheduleSlotTimeKey2 = 'schedule-slot-time-14:00-16:00'; - - expect(find.byKey(const Key(scheduleSlotTimeKey1)), findsNothing); - expect(find.byKey(const Key(scheduleSlotTimeKey2)), findsNothing); - - final Completer completer = Completer(); - scheduleProvider.getUserLectures(completer, const Tuple2('', ''), Session(authenticated: true), profile); - await completer.future; - - await tester.tap(find.byKey(const Key('schedule-page-tab-2'))); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('schedule-page-tab-1'))); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('schedule-page-tab-0'))); - await tester.pumpAndSettle(); - - testScheduleSlot('ASSO', '11:00', '13:00', 'EaD', 'TP', 'DRP'); - - await tester.tap(find.byKey(const Key('schedule-page-tab-2'))); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('schedule-page-tab-3'))); - await tester.pumpAndSettle(); - - testScheduleSlot('IOPE', '14:00', '16:00', 'EaD', 'TE', 'MTD'); - - } - - testWidgets('Schedule with JSON Fetcher', (WidgetTester tester) async { - NetworkRouter.httpClient = mockClient; - final mockJson = File('test/integration/resources/schedule_example.json') - .readAsStringSync(encoding: const Latin1Codec()); - when(mockResponse.body).thenReturn(mockJson); - when(mockResponse.statusCode).thenReturn(200); - when(mockClient.get(argThat(UriMatcher(contains(htmlFetcherIdentifier))), - headers: anyNamed('headers'))) - .thenAnswer((_) async => badMockResponse); - - when(mockClient.get(argThat(UriMatcher(contains(jsonFetcherIdentifier))), - headers: anyNamed('headers'))) - .thenAnswer((_) async => mockResponse); - - await testSchedule(tester); - }); - - testWidgets('Schedule with HTML Fetcher', (WidgetTester tester) async { - final mockHtml = File('test/integration/resources/schedule_example.html') - .readAsStringSync(encoding: const Latin1Codec()); - when(mockResponse.body).thenReturn(mockHtml); - when(mockResponse.statusCode).thenReturn(200); - when(mockClient.get(argThat(UriMatcher(contains(htmlFetcherIdentifier))), - headers: anyNamed('headers'))) - .thenAnswer((_) async => mockResponse); - - when(mockClient.get(argThat(UriMatcher(contains(jsonFetcherIdentifier))), - headers: anyNamed('headers'))) - .thenAnswer((_) async => badMockResponse); - - await testSchedule(tester); - }); - }); + ]; + + await tester.pumpWidget(testableWidget(widget, providers: providers)); + + const scheduleSlotTimeKey1 = 'schedule-slot-time-11:00-13:00'; + const scheduleSlotTimeKey2 = 'schedule-slot-time-14:00-16:00'; + + expect(find.byKey(const Key(scheduleSlotTimeKey1)), findsNothing); + expect(find.byKey(const Key(scheduleSlotTimeKey2)), findsNothing); + + final Completer completer = Completer(); + scheduleProvider.fetchUserLectures(completer, const Tuple2('', ''), + Session(authenticated: true), profile); + await completer.future; + + await tester.tap(find.byKey(const Key('schedule-page-tab-2'))); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('schedule-page-tab-1'))); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('schedule-page-tab-0'))); + await tester.pumpAndSettle(); + + testScheduleSlot('ASSO', '11:00', '13:00', 'EaD', 'TP', 'DRP'); + + await tester.tap(find.byKey(const Key('schedule-page-tab-2'))); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('schedule-page-tab-3'))); + await tester.pumpAndSettle(); + + testScheduleSlot('IOPE', '14:00', '16:00', 'EaD', 'TE', 'MTD'); + } + + testWidgets('Schedule with JSON Fetcher', (WidgetTester tester) async { + NetworkRouter.httpClient = mockClient; + final mockJson = File('test/integration/resources/schedule_example.json') + .readAsStringSync(encoding: const Latin1Codec()); + when(mockResponse.body).thenReturn(mockJson); + when(mockResponse.statusCode).thenReturn(200); + when(mockClient.get(argThat(UriMatcher(contains(htmlFetcherIdentifier))), + headers: anyNamed('headers'))) + .thenAnswer((_) async => badMockResponse); + + when(mockClient.get(argThat(UriMatcher(contains(jsonFetcherIdentifier))), + headers: anyNamed('headers'))) + .thenAnswer((_) async => mockResponse); + + await testSchedule(tester); + }); + + testWidgets('Schedule with HTML Fetcher', (WidgetTester tester) async { + final mockHtml = File('test/integration/resources/schedule_example.html') + .readAsStringSync(encoding: const Latin1Codec()); + when(mockResponse.body).thenReturn(mockHtml); + when(mockResponse.statusCode).thenReturn(200); + when(mockClient.get(argThat(UriMatcher(contains(htmlFetcherIdentifier))), + headers: anyNamed('headers'))) + .thenAnswer((_) async => mockResponse); + + when(mockClient.get(argThat(UriMatcher(contains(jsonFetcherIdentifier))), + headers: anyNamed('headers'))) + .thenAnswer((_) async => badMockResponse); + + await testSchedule(tester); + }); + }); } diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index 54fb87afc..ad0b4964a 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -1,6 +1,7 @@ // @dart=2.10 import 'dart:async'; + import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:tuple/tuple.dart'; @@ -10,7 +11,6 @@ import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; - import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/request_status.dart'; @@ -23,19 +23,25 @@ void main() { final mockResponse = MockResponse(); final sopeCourseUnit = CourseUnit( - abbreviation: 'SOPE', occurrId: 0, name: 'Sistemas Operativos', status: 'V'); + abbreviation: 'SOPE', + occurrId: 0, + name: 'Sistemas Operativos', + status: 'V'); final sdisCourseUnit = CourseUnit( - abbreviation: 'SDIS', occurrId: 0, name: 'Sistemas Distribuídos', status: 'V'); + abbreviation: 'SDIS', + occurrId: 0, + name: 'Sistemas Distribuídos', + status: 'V'); final List rooms = ['B119', 'B107', 'B205']; final DateTime beginSopeExam = DateTime.parse('2800-09-12 12:00'); final DateTime endSopeExam = DateTime.parse('2800-09-12 15:00'); - final sopeExam = Exam('1229', beginSopeExam, endSopeExam, 'SOPE', - rooms, 'Recurso - Época Recurso (2ºS)', 'feup'); + final sopeExam = Exam('1229', beginSopeExam, endSopeExam, 'SOPE', rooms, + 'Recurso - Época Recurso (2ºS)', 'feup'); final DateTime beginSdisExam = DateTime.parse('2800-09-12 12:00'); final DateTime endSdisExam = DateTime.parse('2800-09-12 15:00'); - final sdisExam = Exam('1230', beginSdisExam, endSdisExam, 'SDIS', - rooms, 'Recurso - Época Recurso (2ºS)', 'feup'); + final sdisExam = Exam('1230', beginSdisExam, endSdisExam, 'SDIS', rooms, + 'Recurso - Época Recurso (2ºS)', 'feup'); const Tuple2 userPersistentInfo = Tuple2('', ''); @@ -57,11 +63,12 @@ void main() { }); test('When given one exam', () async { - when(parserExams.parseExams(any, any)).thenAnswer((_) async => {sopeExam}); + when(parserExams.parseExams(any, any)) + .thenAnswer((_) async => {sopeExam}); final action = Completer(); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -79,7 +86,7 @@ void main() { final Completer action = Completer(); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -94,19 +101,21 @@ void main() { since it is a Special Season Exam''', () async { final DateTime begin = DateTime.parse('2800-09-12 12:00'); final DateTime end = DateTime.parse('2800-09-12 15:00'); - final specialExam = Exam('1231', + final specialExam = Exam( + '1231', begin, end, 'SDIS', rooms, - 'Exames ao abrigo de estatutos especiais - Port.Est.Especiais', 'feup'); + 'Exames ao abrigo de estatutos especiais - Port.Est.Especiais', + 'feup'); final Completer action = Completer(); when(parserExams.parseExams(any, any)) .thenAnswer((_) async => {sopeExam, sdisExam, specialExam}); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -122,7 +131,7 @@ void main() { when(parserExams.parseExams(any, any)) .thenAnswer((_) async => throw Exception('RIP')); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -135,14 +144,15 @@ void main() { test('When Exam is today in one hour', () async { final DateTime begin = DateTime.now().add(const Duration(hours: 1)); final DateTime end = DateTime.now().add(const Duration(hours: 2)); - final todayExam = Exam('1232',begin, end, 'SDIS', rooms, + final todayExam = Exam('1232', begin, end, 'SDIS', rooms, 'Recurso - Época Recurso (1ºS)', 'feup'); - when(parserExams.parseExams(any, any)).thenAnswer((_) async => {todayExam}); + when(parserExams.parseExams(any, any)) + .thenAnswer((_) async => {todayExam}); final Completer action = Completer(); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -155,14 +165,15 @@ void main() { test('When Exam was one hour ago', () async { final DateTime end = DateTime.now().subtract(const Duration(hours: 1)); final DateTime begin = DateTime.now().subtract(const Duration(hours: 2)); - final todayExam = Exam('1233',begin, end, 'SDIS', rooms, + final todayExam = Exam('1233', begin, end, 'SDIS', rooms, 'Recurso - Época Recurso (1ºS)', 'feup'); - when(parserExams.parseExams(any, any)).thenAnswer((_) async => {todayExam}); + when(parserExams.parseExams(any, any)) + .thenAnswer((_) async => {todayExam}); final Completer action = Completer(); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); @@ -175,14 +186,15 @@ void main() { test('When Exam is ocurring', () async { final DateTime before = DateTime.now().subtract(const Duration(hours: 1)); final DateTime after = DateTime.now().add(const Duration(hours: 1)); - final todayExam = Exam('1234',before, after, 'SDIS', rooms, - 'Recurso - Época Recurso (1ºS)','feup'); + final todayExam = Exam('1234', before, after, 'SDIS', rooms, + 'Recurso - Época Recurso (1ºS)', 'feup'); - when(parserExams.parseExams(any, any)).thenAnswer((_) async => {todayExam}); + when(parserExams.parseExams(any, any)) + .thenAnswer((_) async => {todayExam}); final Completer action = Completer(); - provider.getUserExams( + provider.fetchUserExams( action, parserExams, userPersistentInfo, profile, session, userUcs); expect(provider.status, RequestStatus.busy); diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index 72611fec1..e9dcee38f 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -1,6 +1,7 @@ // @dart=2.10 import 'dart:async'; + import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:tuple/tuple.dart'; @@ -9,7 +10,6 @@ import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; - import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; @@ -48,7 +48,7 @@ void main() { when(fetcherMock.getLectures(any, any)) .thenAnswer((_) async => [lecture1, lecture2]); - provider.getUserLectures(action, userPersistentInfo, session, profile, + provider.fetchUserLectures(action, userPersistentInfo, session, profile, fetcher: fetcherMock); expect(provider.status, RequestStatus.busy); @@ -64,7 +64,7 @@ void main() { when(fetcherMock.getLectures(any, any)) .thenAnswer((_) async => throw Exception('💥')); - provider.getUserLectures(action, userPersistentInfo, session, profile); + provider.fetchUserLectures(action, userPersistentInfo, session, profile); expect(provider.status, RequestStatus.busy); await action.future; From 4842265d0e6832dedee14dc99349d1aa63aa8a98 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 02:30:17 +0100 Subject: [PATCH 05/21] Combine favorite cards and home page editing providers --- uni/lib/main.dart | 11 +--- .../home_page_editing_mode_provider.dart | 25 -------- ..._provider.dart => home_page_provider.dart} | 18 +++++- uni/lib/model/providers/profile_provider.dart | 22 ++++--- .../providers/state_provider_notifier.dart | 2 + uni/lib/model/providers/state_providers.dart | 18 ++---- .../bus_stop_next_arrivals.dart | 2 +- .../widgets/estimated_arrival_timestamp.dart | 2 +- .../bus_stop_selection.dart | 2 +- uni/lib/view/calendar/calendar.dart | 2 +- .../common_widgets/last_update_timestamp.dart | 2 +- .../request_dependent_widget_builder.dart | 2 +- uni/lib/view/course_units/course_units.dart | 3 +- uni/lib/view/exams/exams.dart | 2 +- uni/lib/view/home/widgets/bus_stop_card.dart | 2 +- uni/lib/view/home/widgets/exam_card.dart | 2 +- .../view/home/widgets/main_cards_list.dart | 61 +++++++++---------- .../view/home/widgets/restaurant_card.dart | 21 +++---- uni/lib/view/home/widgets/schedule_card.dart | 2 +- uni/lib/view/lazy_consumer.dart | 8 +-- uni/lib/view/library/library.dart | 17 +----- .../widgets/library_occupation_card.dart | 2 +- uni/lib/view/locations/locations.dart | 2 +- uni/lib/view/login/login.dart | 2 +- uni/lib/view/profile/profile.dart | 2 +- .../profile/widgets/account_info_card.dart | 2 +- .../view/profile/widgets/print_info_card.dart | 2 +- .../profile/widgets/profile_overview.dart | 2 +- .../view/restaurant/restaurant_page_view.dart | 2 +- uni/lib/view/schedule/schedule.dart | 2 +- 30 files changed, 104 insertions(+), 140 deletions(-) delete mode 100644 uni/lib/model/providers/home_page_editing_mode_provider.dart rename uni/lib/model/providers/{favorite_cards_provider.dart => home_page_provider.dart} (67%) diff --git a/uni/lib/main.dart b/uni/lib/main.dart index aea2edfae..1a61266e0 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -12,8 +12,7 @@ import 'package:uni/model/providers/bus_stop_provider.dart'; import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/providers/faculty_locations_provider.dart'; -import 'package:uni/model/providers/favorite_cards_provider.dart'; -import 'package:uni/model/providers/home_page_editing_mode_provider.dart'; +import 'package:uni/model/providers/home_page_provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; @@ -58,8 +57,7 @@ Future main() async { LibraryOccupationProvider(), FacultyLocationsProvider(), LastUserInfoProvider(), - FavoriteCardsProvider(), - HomePageEditingModeProvider()); + HomePageProvider()); OnStartUp.onStart(stateProviders.sessionProvider); WidgetsFlutterBinding.ensureInitialized(); @@ -100,10 +98,7 @@ Future main() async { ChangeNotifierProvider( create: (context) => stateProviders.lastUserInfoProvider), ChangeNotifierProvider( - create: (context) => - stateProviders.favoriteCardsProvider), - ChangeNotifierProvider( - create: (context) => stateProviders.homePageEditingMode), + create: (context) => stateProviders.homePageProvider), ], child: ChangeNotifierProvider( create: (_) => ThemeNotifier(savedTheme), diff --git a/uni/lib/model/providers/home_page_editing_mode_provider.dart b/uni/lib/model/providers/home_page_editing_mode_provider.dart deleted file mode 100644 index e45457874..000000000 --- a/uni/lib/model/providers/home_page_editing_mode_provider.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/state_provider_notifier.dart'; - -class HomePageEditingModeProvider extends StateProviderNotifier { - bool _isEditing = false; - - bool get isEditing => _isEditing; - - @override - void loadFromStorage() {} - - @override - Future loadFromRemote(Session session, Profile profile) async {} - - setHomePageEditingMode(bool state) { - _isEditing = state; - notifyListeners(); - } - - toggle() { - _isEditing = !_isEditing; - notifyListeners(); - } -} diff --git a/uni/lib/model/providers/favorite_cards_provider.dart b/uni/lib/model/providers/home_page_provider.dart similarity index 67% rename from uni/lib/model/providers/favorite_cards_provider.dart rename to uni/lib/model/providers/home_page_provider.dart index 79be2a624..8fe189b80 100644 --- a/uni/lib/model/providers/favorite_cards_provider.dart +++ b/uni/lib/model/providers/home_page_provider.dart @@ -1,22 +1,34 @@ -import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/utils/favorite_widget_type.dart'; -class FavoriteCardsProvider extends StateProviderNotifier { +class HomePageProvider extends StateProviderNotifier { List _favoriteCards = []; + bool _isEditing = false; List get favoriteCards => _favoriteCards.toList(); + bool get isEditing => _isEditing; @override - loadFromStorage() async { + Future loadFromStorage() async { setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); } @override Future loadFromRemote(Session session, Profile profile) async {} + setHomePageEditingMode(bool state) { + _isEditing = state; + notifyListeners(); + } + + toggleHomePageEditingMode() { + _isEditing = !_isEditing; + notifyListeners(); + } + setFavoriteCards(List favoriteCards) { _favoriteCards = favoriteCards; notifyListeners(); diff --git a/uni/lib/model/providers/profile_provider.dart b/uni/lib/model/providers/profile_provider.dart index 35bb27a9f..4ab96e5b7 100644 --- a/uni/lib/model/providers/profile_provider.dart +++ b/uni/lib/model/providers/profile_provider.dart @@ -67,7 +67,7 @@ class ProfileProvider extends StateProviderNotifier { void loadBalanceRefreshTimes() async { final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); final Map refreshTimes = - await refreshTimesDb.refreshTimes(); + await refreshTimesDb.refreshTimes(); final printRefreshTime = refreshTimes['print']; final feesRefreshTime = refreshTimes['fees']; @@ -93,7 +93,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('fees', currentTime.toString()); @@ -122,7 +122,7 @@ class ProfileProvider extends StateProviderNotifier { Future storeRefreshTime(String db, String currentTime) async { final AppRefreshTimesDatabase refreshTimesDatabase = - AppRefreshTimesDatabase(); + AppRefreshTimesDatabase(); refreshTimesDatabase.saveRefreshTime(db, currentTime); } @@ -133,7 +133,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('print', currentTime.toString()); @@ -161,6 +161,7 @@ class ProfileProvider extends StateProviderNotifier { } fetchUserInfo(Completer action, Session session) async { + print("fetched user info"); try { updateStatus(RequestStatus.busy); @@ -168,6 +169,8 @@ class ProfileProvider extends StateProviderNotifier { _profile = res; }); + print("profile courses: ${_profile.courses}"); + final ucs = CurrentCourseUnitsFetcher() .getCurrentCourseUnits(session) .then((res) => _profile.currentCourseUnits = res); @@ -176,7 +179,7 @@ class ProfileProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final profileDb = AppUserDataDatabase(); profileDb.insertUserData(_profile); @@ -189,8 +192,8 @@ class ProfileProvider extends StateProviderNotifier { action.complete(); } - fetchCourseUnitsAndCourseAverages( - Session session, Completer action) async { + fetchCourseUnitsAndCourseAverages(Session session, + Completer action) async { updateStatus(RequestStatus.busy); try { final List courses = profile.courses; @@ -199,8 +202,11 @@ class ProfileProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); notifyListeners(); + print("ola"); + print(_profile.currentCourseUnits); + final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final AppCoursesDatabase coursesDb = AppCoursesDatabase(); await coursesDb.saveNewCourses(courses); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index b818caddc..265a7ad52 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -23,6 +23,8 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initialized = true; + updateStatus(RequestStatus.busy); + final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); final sessionIsPersistent = diff --git a/uni/lib/model/providers/state_providers.dart b/uni/lib/model/providers/state_providers.dart index f8a83dcbc..af0287b06 100644 --- a/uni/lib/model/providers/state_providers.dart +++ b/uni/lib/model/providers/state_providers.dart @@ -4,8 +4,7 @@ import 'package:uni/model/providers/bus_stop_provider.dart'; import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/providers/faculty_locations_provider.dart'; -import 'package:uni/model/providers/favorite_cards_provider.dart'; -import 'package:uni/model/providers/home_page_editing_mode_provider.dart'; +import 'package:uni/model/providers/home_page_provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; @@ -24,8 +23,7 @@ class StateProviders { final LibraryOccupationProvider libraryOccupationProvider; final FacultyLocationsProvider facultyLocationsProvider; final LastUserInfoProvider lastUserInfoProvider; - final FavoriteCardsProvider favoriteCardsProvider; - final HomePageEditingModeProvider homePageEditingMode; + final HomePageProvider homePageProvider; StateProviders( this.lectureProvider, @@ -38,8 +36,7 @@ class StateProviders { this.libraryOccupationProvider, this.facultyLocationsProvider, this.lastUserInfoProvider, - this.favoriteCardsProvider, - this.homePageEditingMode); + this.homePageProvider); static StateProviders fromContext(BuildContext context) { final lectureProvider = @@ -61,10 +58,8 @@ class StateProviders { Provider.of(context, listen: false); final lastUserInfoProvider = Provider.of(context, listen: false); - final favoriteCardsProvider = - Provider.of(context, listen: false); - final homePageEditingMode = - Provider.of(context, listen: false); + final homePageProvider = + Provider.of(context, listen: false); return StateProviders( lectureProvider, @@ -77,7 +72,6 @@ class StateProviders { libraryOccupationProvider, facultyLocationsProvider, lastUserInfoProvider, - favoriteCardsProvider, - homePageEditingMode); + homePageProvider); } } diff --git a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index e99d2d6f0..ad2c15092 100644 --- a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -22,7 +22,7 @@ class BusStopNextArrivalsPageState @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, busProvider, _) => ListView(children: [ + builder: (context, busProvider) => ListView(children: [ NextArrivals(busProvider.configuredBusStops, busProvider.status) ])); } diff --git a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart index 0fa7c3cdf..a468aa2ad 100644 --- a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart +++ b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart @@ -14,7 +14,7 @@ class EstimatedArrivalTimeStamp extends StatelessWidget { @override Widget build(BuildContext context) { return LazyConsumer( - builder: (context, busProvider, _) => + builder: (context, busProvider) => getContent(context, busProvider.timeStamp), ); } diff --git a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart index a273c830c..08eb2dd8a 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -36,7 +36,7 @@ class BusStopSelectionPageState @override Widget getBody(BuildContext context) { final width = MediaQuery.of(context).size.width; - return LazyConsumer(builder: (context, busProvider, _) { + return LazyConsumer(builder: (context, busProvider) { final List rows = []; busProvider.configuredBusStops.forEach((stopCode, stopData) => rows.add(BusStopSelectionRow(stopCode, stopData))); diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 2af4205c1..181ec4036 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -17,7 +17,7 @@ class CalendarPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, calendarProvider, _) => + builder: (context, calendarProvider) => getCalendarPage(context, calendarProvider.calendar), ); } diff --git a/uni/lib/view/common_widgets/last_update_timestamp.dart b/uni/lib/view/common_widgets/last_update_timestamp.dart index 39f7fec46..a996352c1 100644 --- a/uni/lib/view/common_widgets/last_update_timestamp.dart +++ b/uni/lib/view/common_widgets/last_update_timestamp.dart @@ -34,7 +34,7 @@ class _LastUpdateTimeStampState extends State { @override Widget build(BuildContext context) { return LazyConsumer( - builder: (context, lastUserInfoProvider, _) => Container( + builder: (context, lastUserInfoProvider) => Container( padding: const EdgeInsets.only(top: 8.0, bottom: 10.0), child: _getContent(context, lastUserInfoProvider.lastUpdateTime!)), ); diff --git a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart index a721917c8..edf31fa4f 100644 --- a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart +++ b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart @@ -36,7 +36,7 @@ class RequestDependentWidgetBuilder extends StatelessWidget { @override Widget build(BuildContext context) { return LazyConsumer( - builder: (context, lastUserInfoProvider, _) { + builder: (context, lastUserInfoProvider) { switch (status) { case RequestStatus.successful: case RequestStatus.none: diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index 678e79ea5..e815bcd1b 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -28,8 +28,7 @@ class CourseUnitsPageViewState @override Widget getBody(BuildContext context) { - return LazyConsumer( - builder: (context, profileProvider, _) { + return LazyConsumer(builder: (context, profileProvider) { final List courseUnits = profileProvider.profile.currentCourseUnits; List availableYears = []; diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 2d3420ddc..5988080be 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -22,7 +22,7 @@ class ExamsPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return LazyConsumer(builder: (context, examProvider, _) { + return LazyConsumer(builder: (context, examProvider) { return ListView( children: [ Column( diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index 9f778f350..d5a12acb1 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -25,7 +25,7 @@ class BusStopCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, busProvider, _) { + builder: (context, busProvider) { return getCardContent( context, busProvider.configuredBusStops, busProvider.status); }, diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 29e55ff4a..d00e962d0 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -32,7 +32,7 @@ class ExamCard extends GenericCard { /// that no exams exist is displayed. @override Widget buildCardContent(BuildContext context) { - return LazyConsumer(builder: (context, examProvider, _) { + return LazyConsumer(builder: (context, examProvider) { final filteredExams = examProvider.getFilteredExams(); final hiddenExams = examProvider.hiddenExams; final List exams = filteredExams diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index 857a55140..11510c610 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -1,19 +1,19 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; -import 'package:uni/model/providers/favorite_cards_provider.dart'; -import 'package:uni/model/providers/home_page_editing_mode_provider.dart'; +import 'package:uni/model/providers/home_page_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/utils/favorite_widget_type.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; -import 'package:uni/view/library/widgets/library_occupation_card.dart'; -import 'package:uni/view/profile/widgets/account_info_card.dart'; -import 'package:uni/view/home/widgets/exit_app_dialog.dart'; +import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/home/widgets/bus_stop_card.dart'; import 'package:uni/view/home/widgets/exam_card.dart'; -import 'package:uni/view/common_widgets/page_title.dart'; +import 'package:uni/view/home/widgets/exit_app_dialog.dart'; import 'package:uni/view/home/widgets/schedule_card.dart'; -import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/lazy_consumer.dart'; +import 'package:uni/view/library/widgets/library_occupation_card.dart'; +import 'package:uni/view/profile/widgets/account_info_card.dart'; typedef CardCreator = GenericCard Function( Key key, bool isEditingMode, dynamic Function()? onDelete); @@ -41,37 +41,36 @@ class MainCardsList extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer2( - builder: (context, editingModeProvider, favoriteCardsProvider, _) => - Scaffold( + return LazyConsumer( + builder: (context, homePageProvider) => Scaffold( body: BackButtonExitWrapper( context: context, child: SizedBox( height: MediaQuery.of(context).size.height, - child: editingModeProvider.isEditing + child: homePageProvider.isEditing ? ReorderableListView( onReorder: (oldIndex, newIndex) => reorderCard( oldIndex, newIndex, - favoriteCardsProvider.favoriteCards, + homePageProvider.favoriteCards, context), - header: createTopBar(context, editingModeProvider), + header: createTopBar(context, homePageProvider), children: favoriteCardsFromTypes( - favoriteCardsProvider.favoriteCards, + homePageProvider.favoriteCards, context, - editingModeProvider), + homePageProvider), ) : ListView( children: [ - createTopBar(context, editingModeProvider), + createTopBar(context, homePageProvider), ...favoriteCardsFromTypes( - favoriteCardsProvider.favoriteCards, + homePageProvider.favoriteCards, context, - editingModeProvider) + homePageProvider) ], )), ), - floatingActionButton: editingModeProvider.isEditing + floatingActionButton: homePageProvider.isEditing ? createActionButton(context) : null, )); @@ -106,8 +105,7 @@ class MainCardsList extends StatelessWidget { List getCardAdders(BuildContext context) { final userSession = Provider.of(context, listen: false); final List favorites = - Provider.of(context, listen: false) - .favoriteCards; + Provider.of(context, listen: false).favoriteCards; final possibleCardAdditions = cardCreators.entries .where((e) => e.key.isVisible(userSession.faculties)) @@ -136,16 +134,15 @@ class MainCardsList extends StatelessWidget { } Widget createTopBar( - BuildContext context, HomePageEditingModeProvider editingModeProvider) { + BuildContext context, HomePageProvider editingModeProvider) { return Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 5), child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ PageTitle( name: DrawerItem.navPersonalArea.title, center: false, pad: false), GestureDetector( - onTap: () => - Provider.of(context, listen: false) - .setHomePageEditingMode(!editingModeProvider.isEditing), + onTap: () => Provider.of(context, listen: false) + .setHomePageEditingMode(!editingModeProvider.isEditing), child: Text( editingModeProvider.isEditing ? 'Concluir Edição' : 'Editar', style: Theme.of(context).textTheme.bodySmall)) @@ -154,7 +151,7 @@ class MainCardsList extends StatelessWidget { } List favoriteCardsFromTypes(List cardTypes, - BuildContext context, HomePageEditingModeProvider editingModeProvider) { + BuildContext context, HomePageProvider editingModeProvider) { final userSession = Provider.of(context, listen: false).session; return cardTypes @@ -162,7 +159,9 @@ class MainCardsList extends StatelessWidget { .where((type) => cardCreators.containsKey(type)) .map((type) { final i = cardTypes.indexOf(type); - return cardCreators[type]!(Key(i.toString()), editingModeProvider.isEditing, + return cardCreators[type]!( + Key(i.toString()), + editingModeProvider.isEditing, () => removeCardIndexFromFavorites(i, context)); }).toList(); } @@ -177,16 +176,14 @@ class MainCardsList extends StatelessWidget { void removeCardIndexFromFavorites(int i, BuildContext context) { final List favorites = - Provider.of(context, listen: false) - .favoriteCards; + Provider.of(context, listen: false).favoriteCards; favorites.removeAt(i); saveFavoriteCards(context, favorites); } void addCardToFavorites(FavoriteWidgetType type, BuildContext context) { final List favorites = - Provider.of(context, listen: false) - .favoriteCards; + Provider.of(context, listen: false).favoriteCards; if (!favorites.contains(type)) { favorites.add(type); } @@ -195,7 +192,7 @@ class MainCardsList extends StatelessWidget { void saveFavoriteCards( BuildContext context, List favorites) { - Provider.of(context, listen: false) + Provider.of(context, listen: false) .setFavoriteCards(favorites); AppSharedPreferences.saveFavoriteCards(favorites); } diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 3c8f7f8c8..0f7c248dc 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -23,17 +23,16 @@ class RestaurantCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, restaurantProvider, _) => - RequestDependentWidgetBuilder( - context: context, - status: restaurantProvider.status, - contentGenerator: generateRestaurant, - content: restaurantProvider.restaurants, - contentChecker: restaurantProvider.restaurants.isNotEmpty, - onNullContent: Center( - child: Text('Não existem cantinas para apresentar', - style: Theme.of(context).textTheme.headlineMedium, - textAlign: TextAlign.center)))); + builder: (context, restaurantProvider) => RequestDependentWidgetBuilder( + context: context, + status: restaurantProvider.status, + contentGenerator: generateRestaurant, + content: restaurantProvider.restaurants, + contentChecker: restaurantProvider.restaurants.isNotEmpty, + onNullContent: Center( + child: Text('Não existem cantinas para apresentar', + style: Theme.of(context).textTheme.headlineMedium, + textAlign: TextAlign.center)))); } Widget generateRestaurant(canteens, context) { diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index 5f6f13ba9..cf4ff2214 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -24,7 +24,7 @@ class ScheduleCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, lectureProvider, _) => RequestDependentWidgetBuilder( + builder: (context, lectureProvider) => RequestDependentWidgetBuilder( context: context, status: lectureProvider.status, contentGenerator: generateSchedule, diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 0027c7522..42b4f10d6 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -5,7 +5,7 @@ import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; class LazyConsumer extends StatelessWidget { - final Widget Function(BuildContext, T, Widget?) builder; + final Widget Function(BuildContext, T) builder; const LazyConsumer({ Key? key, @@ -23,8 +23,8 @@ class LazyConsumer extends StatelessWidget { .ensureInitialized(session, profile); }); - return Consumer( - builder: builder, - ); + return Consumer(builder: (context, provider, _) { + return builder(context, provider); + }); } } diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index 2756dbc51..eb2f3bfc4 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -18,23 +18,8 @@ class LibraryPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, libraryOccupationProvider, _) => + builder: (context, libraryOccupationProvider) => LibraryPage(libraryOccupationProvider.occupation)); - -/* - return StoreConnector>( - converter: (store) { - final LibraryOccupation? occupation = - store.state.content['libraryOccupation']; - return Tuple2(occupation, store.state.content['libraryOccupationStatus']); - }, builder: (context, occupationInfo) { - if (occupationInfo.item2 == RequestStatus.busy) { - return const Center(child: CircularProgressIndicator()); - } else { - return LibraryPage(occupationInfo.item1); - } - }); - */ } } diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index 70da1215f..be02eee33 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -25,7 +25,7 @@ class LibraryOccupationCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, libraryOccupationProvider, _) => + builder: (context, libraryOccupationProvider) => RequestDependentWidgetBuilder( context: context, status: libraryOccupationProvider.status, diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index 2b2a573e8..5c7c0e7de 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -29,7 +29,7 @@ class LocationsPageState extends GeneralPageViewState @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, locationsProvider, _) { + builder: (context, locationsProvider) { return LocationsPageView( locations: locationsProvider.locations, status: locationsProvider.status); diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index ead902fa0..738ee8ba2 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -223,7 +223,7 @@ class LoginPageViewState extends State { /// Creates a widget for the user login depending on the status of his login. Widget createStatusWidget(BuildContext context) { return LazyConsumer( - builder: (context, sessionProvider, _) { + builder: (context, sessionProvider) { switch (sessionProvider.status) { case RequestStatus.busy: return const SizedBox( diff --git a/uni/lib/view/profile/profile.dart b/uni/lib/view/profile/profile.dart index 1c988249e..656477735 100644 --- a/uni/lib/view/profile/profile.dart +++ b/uni/lib/view/profile/profile.dart @@ -19,7 +19,7 @@ class ProfilePageViewState extends SecondaryPageViewState { @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, profileStateProvider, _) { + builder: (context, profileStateProvider) { final profile = profileStateProvider.profile; final List courseWidgets = profile.courses .map((e) => [ diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index 4ffbcbbee..c759692b9 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -16,7 +16,7 @@ class AccountInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, profileStateProvider, _) { + builder: (context, profileStateProvider) { final profile = profileStateProvider.profile; return Column(children: [ Table( diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index 264a85689..0ae056c15 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -14,7 +14,7 @@ class PrintInfoCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { return LazyConsumer( - builder: (context, profileStateProvider, _) { + builder: (context, profileStateProvider) { final profile = profileStateProvider.profile; return Column( mainAxisSize: MainAxisSize.min, diff --git a/uni/lib/view/profile/widgets/profile_overview.dart b/uni/lib/view/profile/widgets/profile_overview.dart index b1593144b..ad3538caf 100644 --- a/uni/lib/view/profile/widgets/profile_overview.dart +++ b/uni/lib/view/profile/widgets/profile_overview.dart @@ -19,7 +19,7 @@ class ProfileOverview extends StatelessWidget { @override Widget build(BuildContext context) { return LazyConsumer( - builder: (context, sessionProvider, _) { + builder: (context, sessionProvider) { return FutureBuilder( future: loadProfilePicture(sessionProvider.session), builder: (BuildContext context, AsyncSnapshot profilePic) => diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 9b7f02144..852b6b1ab 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -36,7 +36,7 @@ class _RestaurantPageState extends GeneralPageViewState @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, restaurantProvider, _) { + builder: (context, restaurantProvider) { return Column(children: [ ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [ Container( diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 971c45eed..7943f89d3 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -21,7 +21,7 @@ class SchedulePageState extends State { @override Widget build(BuildContext context) { return LazyConsumer( - builder: (context, lectureProvider, _) { + builder: (context, lectureProvider) { return SchedulePageView( lectures: lectureProvider.lectures, scheduleStatus: lectureProvider.status, From 1beb06985e3f167826f529b92e08992412f790f2 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 16:36:40 +0100 Subject: [PATCH 06/21] Fix course units loading --- .../background_workers/notifications.dart | 2 +- .../fetchers/all_course_units_fetcher.dart | 3 + uni/lib/model/entities/profile.dart | 19 +++-- .../model/providers/bus_stop_provider.dart | 11 ++- .../model/providers/calendar_provider.dart | 3 +- uni/lib/model/providers/exam_provider.dart | 11 ++- .../providers/faculty_locations_provider.dart | 2 +- .../providers/last_user_info_provider.dart | 2 +- uni/lib/model/providers/lecture_provider.dart | 3 +- .../library_occupation_provider.dart | 4 +- uni/lib/model/providers/profile_provider.dart | 73 +++++++++---------- uni/lib/model/providers/session_provider.dart | 16 ++-- .../providers/state_provider_notifier.dart | 10 +-- uni/lib/view/course_units/course_units.dart | 5 +- uni/lib/view/lazy_consumer.dart | 20 +++-- uni/lib/view/login/login.dart | 4 +- .../profile/widgets/profile_overview.dart | 6 +- uni/lib/view/splash/splash.dart | 2 +- 18 files changed, 97 insertions(+), 99 deletions(-) diff --git a/uni/lib/controller/background_workers/notifications.dart b/uni/lib/controller/background_workers/notifications.dart index a270fa644..00d0fdef2 100644 --- a/uni/lib/controller/background_workers/notifications.dart +++ b/uni/lib/controller/background_workers/notifications.dart @@ -83,7 +83,7 @@ class NotificationManager { } void initializeNotifications() async { - //guarentees that the execution is only done once in the lifetime of the app. + // guarantees that the execution is only done once in the lifetime of the app. if (_initialized) return; _initialized = true; _initFlutterNotificationsPlugin(); diff --git a/uni/lib/controller/fetchers/all_course_units_fetcher.dart b/uni/lib/controller/fetchers/all_course_units_fetcher.dart index baa454ebf..5d876b1d7 100644 --- a/uni/lib/controller/fetchers/all_course_units_fetcher.dart +++ b/uni/lib/controller/fetchers/all_course_units_fetcher.dart @@ -10,11 +10,14 @@ class AllCourseUnitsFetcher { List courses, Session session) async { final List allCourseUnits = []; for (var course in courses) { + print("course: ${course.name}"); try { final List courseUnits = await _getAllCourseUnitsAndCourseAveragesFromCourse( course, session); + print("courseUnits: ${courseUnits.length}"); allCourseUnits.addAll(courseUnits.where((c) => c.enrollmentIsValid())); + print("allCourseUnits: ${allCourseUnits.length}"); } catch (e) { Logger().e('Failed to fetch course units for ${course.name}', e); } diff --git a/uni/lib/model/entities/profile.dart b/uni/lib/model/entities/profile.dart index b5fac913d..c2028a5f7 100644 --- a/uni/lib/model/entities/profile.dart +++ b/uni/lib/model/entities/profile.dart @@ -11,18 +11,17 @@ class Profile { final String printBalance; final String feesBalance; final String feesLimit; - late List courses; - late List currentCourseUnits; + List courses; + List courseUnits; - Profile( - {this.name = '', - this.email = '', - courses, - this.printBalance = '', - this.feesBalance = '', - this.feesLimit = ''}) + Profile({this.name = '', + this.email = '', + courses, + this.printBalance = '', + this.feesBalance = '', + this.feesLimit = ''}) : courses = courses ?? [], - currentCourseUnits = []; + courseUnits = []; /// Creates a new instance from a JSON object. static Profile fromResponse(dynamic response) { diff --git a/uni/lib/model/providers/bus_stop_provider.dart b/uni/lib/model/providers/bus_stop_provider.dart index 302347b64..f4b126fba 100644 --- a/uni/lib/model/providers/bus_stop_provider.dart +++ b/uni/lib/model/providers/bus_stop_provider.dart @@ -21,18 +21,17 @@ class BusStopProvider extends StateProviderNotifier { DateTime get timeStamp => _timeStamp; @override - void loadFromStorage() async { + Future loadFromStorage() async { final AppBusStopDatabase busStopsDb = AppBusStopDatabase(); final Map stops = await busStopsDb.busStops(); - _configuredBusStops = stops; - notifyListeners(); - getUserBusTrips(Completer()); } @override - void loadFromRemote(Session session, Profile profile) { - getUserBusTrips(Completer()); + Future loadFromRemote(Session session, Profile profile) async { + final action = Completer(); + getUserBusTrips(action); + await action.future; } getUserBusTrips(Completer action) async { diff --git a/uni/lib/model/providers/calendar_provider.dart b/uni/lib/model/providers/calendar_provider.dart index 281e1b743..add1e8a07 100644 --- a/uni/lib/model/providers/calendar_provider.dart +++ b/uni/lib/model/providers/calendar_provider.dart @@ -41,9 +41,8 @@ class CalendarProvider extends StateProviderNotifier { } @override - void loadFromStorage() async { + Future loadFromStorage() async { final CalendarDatabase db = CalendarDatabase(); _calendar = await db.calendar(); - notifyListeners(); } } diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/exam_provider.dart index 1192abfdb..0f304f6f8 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/exam_provider.dart @@ -28,26 +28,25 @@ class ExamProvider extends StateProviderNotifier { UnmodifiableMapView(_filteredExamsTypes); @override - void loadFromStorage() async { + Future loadFromStorage() async { setFilteredExams( await AppSharedPreferences.getFilteredExams(), Completer()); setHiddenExams(await AppSharedPreferences.getHiddenExams(), Completer()); final AppExamsDatabase db = AppExamsDatabase(); - final List exs = await db.exams(); - _exams = exs; - notifyListeners(); + final List exams = await db.exams(); + _exams = exams; } @override - void loadFromRemote(Session session, Profile profile) async { + Future loadFromRemote(Session session, Profile profile) async { final Completer action = Completer(); final ParserExams parserExams = ParserExams(); final Tuple2 userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); fetchUserExams(action, parserExams, userPersistentInfo, profile, session, - profile.currentCourseUnits); + profile.courseUnits); await action.future; } diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/faculty_locations_provider.dart index 0e1af6403..e02d7905a 100644 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ b/uni/lib/model/providers/faculty_locations_provider.dart @@ -14,7 +14,7 @@ class FacultyLocationsProvider extends StateProviderNotifier { UnmodifiableListView(_locations); @override - void loadFromStorage() async { + Future loadFromStorage() async { _locations = await LocationFetcherAsset().getLocations(); } diff --git a/uni/lib/model/providers/last_user_info_provider.dart b/uni/lib/model/providers/last_user_info_provider.dart index 724091265..fb9468c89 100644 --- a/uni/lib/model/providers/last_user_info_provider.dart +++ b/uni/lib/model/providers/last_user_info_provider.dart @@ -19,7 +19,7 @@ class LastUserInfoProvider extends StateProviderNotifier { } @override - void loadFromStorage() async { + Future loadFromStorage() async { final AppLastUserInfoUpdateDatabase db = AppLastUserInfoUpdateDatabase(); _lastUpdateTime = await db.getLastUserInfoUpdateTime(); notifyListeners(); diff --git a/uni/lib/model/providers/lecture_provider.dart b/uni/lib/model/providers/lecture_provider.dart index d1e26fa96..177a4bb61 100644 --- a/uni/lib/model/providers/lecture_provider.dart +++ b/uni/lib/model/providers/lecture_provider.dart @@ -20,11 +20,10 @@ class LectureProvider extends StateProviderNotifier { UnmodifiableListView get lectures => UnmodifiableListView(_lectures); @override - void loadFromStorage() async { + Future loadFromStorage() async { final AppLecturesDatabase db = AppLecturesDatabase(); final List lectures = await db.lectures(); _lectures = lectures; - notifyListeners(); } @override diff --git a/uni/lib/model/providers/library_occupation_provider.dart b/uni/lib/model/providers/library_occupation_provider.dart index 31b8092a1..6e0f58fb0 100644 --- a/uni/lib/model/providers/library_occupation_provider.dart +++ b/uni/lib/model/providers/library_occupation_provider.dart @@ -15,12 +15,10 @@ class LibraryOccupationProvider extends StateProviderNotifier { LibraryOccupation? get occupation => _occupation; @override - void loadFromStorage() async { + Future loadFromStorage() async { final LibraryOccupationDatabase db = LibraryOccupationDatabase(); final LibraryOccupation occupation = await db.occupation(); - _occupation = occupation; - notifyListeners(); } @override diff --git a/uni/lib/model/providers/profile_provider.dart b/uni/lib/model/providers/profile_provider.dart index 4ab96e5b7..456dcd781 100644 --- a/uni/lib/model/providers/profile_provider.dart +++ b/uni/lib/model/providers/profile_provider.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:logger/logger.dart'; import 'package:tuple/tuple.dart'; +import 'package:uni/controller/fetchers/all_course_units_fetcher.dart'; import 'package:uni/controller/fetchers/current_course_units_fetcher.dart'; import 'package:uni/controller/fetchers/fees_fetcher.dart'; import 'package:uni/controller/fetchers/print_fetcher.dart'; @@ -14,14 +15,12 @@ import 'package:uni/controller/local_storage/app_user_database.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; import 'package:uni/model/entities/course.dart'; +import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; -// ignore: always_use_package_imports -import '../../controller/fetchers/all_course_units_fetcher.dart'; - class ProfileProvider extends StateProviderNotifier { Profile _profile = Profile(); DateTime? _feesRefreshTime; @@ -34,14 +33,17 @@ class ProfileProvider extends StateProviderNotifier { Profile get profile => _profile; @override - void loadFromStorage() async { - loadCourses(); - loadBalanceRefreshTimes(); - loadCourseUnits(); + Future loadFromStorage() async { + await Future.wait( + [loadCourses(), loadBalanceRefreshTimes(), loadCourseUnits()]); } @override Future loadFromRemote(Session session, Profile profile) async { + final userInfoAction = Completer(); + fetchUserInfo(userInfoAction, session); + await userInfoAction.future; + final Completer userFeesAction = Completer(); fetchUserFees(userFeesAction, session); @@ -51,10 +53,14 @@ class ProfileProvider extends StateProviderNotifier { final Completer courseUnitsAction = Completer(); fetchCourseUnitsAndCourseAverages(session, courseUnitsAction); - await Future.wait([userFeesAction.future, printBalanceAction.future]); + await Future.wait([ + userFeesAction.future, + printBalanceAction.future, + courseUnitsAction.future + ]); } - void loadCourses() async { + Future loadCourses() async { final profileDb = AppUserDataDatabase(); _profile = await profileDb.getUserData(); @@ -64,10 +70,10 @@ class ProfileProvider extends StateProviderNotifier { _profile.courses = courses; } - void loadBalanceRefreshTimes() async { + Future loadBalanceRefreshTimes() async { final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); final Map refreshTimes = - await refreshTimesDb.refreshTimes(); + await refreshTimesDb.refreshTimes(); final printRefreshTime = refreshTimes['print']; final feesRefreshTime = refreshTimes['fees']; @@ -79,9 +85,9 @@ class ProfileProvider extends StateProviderNotifier { } } - void loadCourseUnits() async { + Future loadCourseUnits() async { final AppCourseUnitsDatabase db = AppCourseUnitsDatabase(); - profile.currentCourseUnits = await db.courseUnits(); + profile.courseUnits = await db.courseUnits(); } fetchUserFees(Completer action, Session session) async { @@ -93,7 +99,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('fees', currentTime.toString()); @@ -122,7 +128,7 @@ class ProfileProvider extends StateProviderNotifier { Future storeRefreshTime(String db, String currentTime) async { final AppRefreshTimesDatabase refreshTimesDatabase = - AppRefreshTimesDatabase(); + AppRefreshTimesDatabase(); refreshTimesDatabase.saveRefreshTime(db, currentTime); } @@ -133,7 +139,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('print', currentTime.toString()); @@ -161,25 +167,20 @@ class ProfileProvider extends StateProviderNotifier { } fetchUserInfo(Completer action, Session session) async { - print("fetched user info"); try { updateStatus(RequestStatus.busy); - final profile = ProfileFetcher.getProfile(session).then((res) { - _profile = res; - }); + final profile = await ProfileFetcher.getProfile(session); + final currentCourseUnits = + await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); - print("profile courses: ${_profile.courses}"); + _profile = profile; + _profile.courseUnits = currentCourseUnits; - final ucs = CurrentCourseUnitsFetcher() - .getCurrentCourseUnits(session) - .then((res) => _profile.currentCourseUnits = res); - await Future.wait([profile, ucs]); - notifyListeners(); updateStatus(RequestStatus.successful); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final profileDb = AppUserDataDatabase(); profileDb.insertUserData(_profile); @@ -192,28 +193,24 @@ class ProfileProvider extends StateProviderNotifier { action.complete(); } - fetchCourseUnitsAndCourseAverages(Session session, - Completer action) async { + fetchCourseUnitsAndCourseAverages( + Session session, Completer action) async { updateStatus(RequestStatus.busy); try { final List courses = profile.courses; - _profile.currentCourseUnits = await AllCourseUnitsFetcher() - .getAllCourseUnitsAndCourseAverages(courses, session); - updateStatus(RequestStatus.successful); - notifyListeners(); + final List allCourseUnits = await AllCourseUnitsFetcher() + .getAllCourseUnitsAndCourseAverages(profile.courses, session); - print("ola"); - print(_profile.currentCourseUnits); + _profile.courseUnits = allCourseUnits; final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final AppCoursesDatabase coursesDb = AppCoursesDatabase(); await coursesDb.saveNewCourses(courses); final courseUnitsDatabase = AppCourseUnitsDatabase(); - await courseUnitsDatabase - .saveNewCourseUnits(_profile.currentCourseUnits); + await courseUnitsDatabase.saveNewCourseUnits(_profile.courseUnits); } } catch (e) { Logger().e('Failed to get all user ucs: $e'); diff --git a/uni/lib/model/providers/session_provider.dart b/uni/lib/model/providers/session_provider.dart index 5ef686b5d..fe334db14 100644 --- a/uni/lib/model/providers/session_provider.dart +++ b/uni/lib/model/providers/session_provider.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:collection'; import 'package:uni/controller/background_workers/notifications.dart'; -import 'package:uni/controller/load_info.dart'; import 'package:uni/controller/load_static/terms_and_conditions.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/networking/network_router.dart'; @@ -24,13 +23,12 @@ class SessionProvider extends StateProviderNotifier { UnmodifiableListView(_faculties); @override - void loadFromStorage() {} + Future loadFromStorage() async {} @override Future loadFromRemote(Session session, Profile profile) async {} - login( - Completer action, + login(Completer action, String username, String password, List faculties, @@ -51,10 +49,10 @@ class SessionProvider extends StateProviderNotifier { username, password, faculties); } Future.delayed(const Duration(seconds: 20), - () => {NotificationManager().initializeNotifications()}); + () => {NotificationManager().initializeNotifications()}); //loadLocalUserInfoToState(stateProviders, skipDatabaseLookup: true); - await loadUserProfileInfoFromRemote(stateProviders); + //await loadUserProfileInfoFromRemote(stateProviders); usernameController.clear(); passwordController.clear(); @@ -63,7 +61,7 @@ class SessionProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); } else { final String responseHtml = - await NetworkRouter.loginInSigarra(username, password, faculties); + await NetworkRouter.loginInSigarra(username, password, faculties); if (isPasswordExpired(responseHtml)) { action.completeError(ExpiredCredentialsException()); } else { @@ -91,9 +89,9 @@ class SessionProvider extends StateProviderNotifier { //notifyListeners(); if (session.authenticated) { - await loadUserProfileInfoFromRemote(stateProviders); + //await loadUserProfileInfoFromRemote(stateProviders); Future.delayed(const Duration(seconds: 20), - () => {NotificationManager().initializeNotifications()}); + () => {NotificationManager().initializeNotifications()}); updateStatus(RequestStatus.successful); action?.complete(); } else { diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 265a7ad52..45d344f63 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -16,7 +16,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { notifyListeners(); } - void ensureInitialized(Session session, Profile profile) async { + Future ensureInitialized(Session session, Profile profile) async { if (_initialized) { return; } @@ -30,17 +30,17 @@ abstract class StateProviderNotifier extends ChangeNotifier { final sessionIsPersistent = userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; if (sessionIsPersistent) { - loadFromStorage(); + await loadFromStorage(); } if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - loadFromRemote(session, profile); + await loadFromRemote(session, profile); } notifyListeners(); } - void loadFromStorage(); + Future loadFromStorage(); - void loadFromRemote(Session session, Profile profile); + Future loadFromRemote(Session session, Profile profile); } diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index e815bcd1b..adbff9f5c 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -29,8 +29,7 @@ class CourseUnitsPageViewState @override Widget getBody(BuildContext context) { return LazyConsumer(builder: (context, profileProvider) { - final List courseUnits = - profileProvider.profile.currentCourseUnits; + final List courseUnits = profileProvider.profile.courseUnits; List availableYears = []; List availableSemesters = []; if (courseUnits.isNotEmpty) { @@ -56,7 +55,7 @@ class CourseUnitsPageViewState return _getPageView(courseUnits, profileProvider.status, availableYears, availableSemesters); } else { - return Container(); + return _getPageView([], profileProvider.status, [], []); } }); } diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 42b4f10d6..970b30862 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -4,6 +4,12 @@ import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; +/// Wrapper around Consumer that ensures that the provider is initialized, +/// meaning that it has loaded its data from storage and/or remote. +/// The provider will not reload its data if it has already been loaded before. +/// The user session should be valid before calling this widget. +/// There must be a SessionProvider and a ProfileProvider above this widget in +/// the widget tree. class LazyConsumer extends StatelessWidget { final Widget Function(BuildContext, T) builder; @@ -14,13 +20,15 @@ class LazyConsumer extends StatelessWidget { @override Widget build(BuildContext context) { - final session = - Provider.of(context, listen: false).session; - final profile = - Provider.of(context, listen: false).profile; + final sessionProvider = Provider.of(context); + final profileProvider = Provider.of(context); + WidgetsBinding.instance.addPostFrameCallback((_) { - Provider.of(context, listen: false) - .ensureInitialized(session, profile); + final session = sessionProvider.session; + final profile = profileProvider.profile; + profileProvider.ensureInitialized(session, profile).then((value) => + Provider.of(context, listen: false) + .ensureInitialized(session, profile)); }); return Consumer(builder: (context, provider, _) { diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 738ee8ba2..9b2b431c3 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -222,8 +222,8 @@ class LoginPageViewState extends State { /// Creates a widget for the user login depending on the status of his login. Widget createStatusWidget(BuildContext context) { - return LazyConsumer( - builder: (context, sessionProvider) { + return Consumer( + builder: (context, sessionProvider, _) { switch (sessionProvider.status) { case RequestStatus.busy: return const SizedBox( diff --git a/uni/lib/view/profile/widgets/profile_overview.dart b/uni/lib/view/profile/widgets/profile_overview.dart index ad3538caf..f59f30574 100644 --- a/uni/lib/view/profile/widgets/profile_overview.dart +++ b/uni/lib/view/profile/widgets/profile_overview.dart @@ -1,10 +1,10 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/controller/load_info.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/session_provider.dart'; -import 'package:uni/view/lazy_consumer.dart'; class ProfileOverview extends StatelessWidget { final Profile profile; @@ -18,8 +18,8 @@ class ProfileOverview extends StatelessWidget { @override Widget build(BuildContext context) { - return LazyConsumer( - builder: (context, sessionProvider) { + return Consumer( + builder: (context, sessionProvider, _) { return FutureBuilder( future: loadProfilePicture(sessionProvider.session), builder: (BuildContext context, AsyncSnapshot profilePic) => diff --git a/uni/lib/view/splash/splash.dart b/uni/lib/view/splash/splash.dart index caa578bc4..130b469fd 100644 --- a/uni/lib/view/splash/splash.dart +++ b/uni/lib/view/splash/splash.dart @@ -131,7 +131,7 @@ class SplashScreenState extends State { if (mounted) { final List faculties = await AppSharedPreferences.getUserFaculties(); - stateProviders.sessionProvider + await stateProviders.sessionProvider .reLogin(userName, password, faculties, stateProviders); } return MaterialPageRoute(builder: (context) => const HomePageView()); From d8c6730e18da5e1f10e810936cbade9fe20eb75b Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 16:58:34 +0100 Subject: [PATCH 07/21] Simplify RequestDependentWidgetBuilder --- .../fetchers/all_course_units_fetcher.dart | 3 - .../providers/faculty_locations_provider.dart | 8 ++- .../request_dependent_widget_builder.dart | 60 +++++++------------ uni/lib/view/locations/locations.dart | 15 +++-- .../view/restaurant/restaurant_page_view.dart | 1 + 5 files changed, 33 insertions(+), 54 deletions(-) diff --git a/uni/lib/controller/fetchers/all_course_units_fetcher.dart b/uni/lib/controller/fetchers/all_course_units_fetcher.dart index 5d876b1d7..baa454ebf 100644 --- a/uni/lib/controller/fetchers/all_course_units_fetcher.dart +++ b/uni/lib/controller/fetchers/all_course_units_fetcher.dart @@ -10,14 +10,11 @@ class AllCourseUnitsFetcher { List courses, Session session) async { final List allCourseUnits = []; for (var course in courses) { - print("course: ${course.name}"); try { final List courseUnits = await _getAllCourseUnitsAndCourseAveragesFromCourse( course, session); - print("courseUnits: ${courseUnits.length}"); allCourseUnits.addAll(courseUnits.where((c) => c.enrollmentIsValid())); - print("allCourseUnits: ${allCourseUnits.length}"); } catch (e) { Logger().e('Failed to fetch course units for ${course.name}', e); } diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/faculty_locations_provider.dart index e02d7905a..6d9468272 100644 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ b/uni/lib/model/providers/faculty_locations_provider.dart @@ -2,10 +2,10 @@ import 'dart:collection'; import 'package:uni/controller/fetchers/location_fetcher/location_fetcher_asset.dart'; import 'package:uni/model/entities/location_group.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; - -import '../entities/profile.dart'; -import '../entities/session.dart'; +import 'package:uni/model/request_status.dart'; class FacultyLocationsProvider extends StateProviderNotifier { List _locations = []; @@ -15,7 +15,9 @@ class FacultyLocationsProvider extends StateProviderNotifier { @override Future loadFromStorage() async { + updateStatus(RequestStatus.busy); _locations = await LocationFetcherAsset().getLocations(); + updateStatus(RequestStatus.successful); } @override diff --git a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart index edf31fa4f..a1c2c363a 100644 --- a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart +++ b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart @@ -1,11 +1,8 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; -import 'package:uni/controller/local_storage/app_last_user_info_update_database.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; -import 'package:uni/view/lazy_consumer.dart'; /// Wraps content given its fetch data from the redux store, /// hydrating the component, displaying an empty message, @@ -30,46 +27,29 @@ class RequestDependentWidgetBuilder extends StatelessWidget { final dynamic content; final bool contentChecker; final Widget onNullContent; - static final AppLastUserInfoUpdateDatabase lastUpdateDatabase = - AppLastUserInfoUpdateDatabase(); @override Widget build(BuildContext context) { - return LazyConsumer( - builder: (context, lastUserInfoProvider) { - switch (status) { - case RequestStatus.successful: - case RequestStatus.none: - return contentChecker - ? contentGenerator(content, context) - : onNullContent; - case RequestStatus.busy: - if (lastUserInfoProvider.lastUpdateTime != null) { - return contentChecker - ? contentGenerator(content, context) - : onNullContent; - } - if (contentLoadingWidget != null) { - return contentChecker - ? contentGenerator(content, context) - : Center( - child: Shimmer.fromColors( - baseColor: Theme.of(context).highlightColor, - highlightColor: - Theme.of(context).colorScheme.onPrimary, - child: contentLoadingWidget!)); - } - return contentChecker - ? contentGenerator(content, context) - : const Center(child: CircularProgressIndicator()); - case RequestStatus.failed: - default: - return contentChecker - ? contentGenerator(content, context) - : requestFailedMessage(); - } - }, - ); + if (status == RequestStatus.busy && !contentChecker) { + return loadingWidget(); + } else if (status == RequestStatus.failed) { + return requestFailedMessage(); + } + + return contentChecker ? contentGenerator(content, context) : onNullContent; + } + + Widget loadingWidget() { + return contentLoadingWidget == null + ? const Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: CircularProgressIndicator())) + : Center( + child: Shimmer.fromColors( + baseColor: Theme.of(context).highlightColor, + highlightColor: Theme.of(context).colorScheme.onPrimary, + child: contentLoadingWidget!)); } Widget requestFailedMessage() { diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index 5c7c0e7de..53b7ac05c 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -7,7 +7,6 @@ import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/locations/widgets/faculty_maps.dart'; -import 'package:uni/view/locations/widgets/map.dart'; import 'package:uni/view/locations/widgets/marker.dart'; class LocationsPage extends StatefulWidget { @@ -39,11 +38,11 @@ class LocationsPageState extends GeneralPageViewState } class LocationsPageView extends StatelessWidget { - final List? locations; - final RequestStatus? status; + final List locations; + final RequestStatus status; const LocationsPageView( - {super.key, this.locations, this.status = RequestStatus.none}); + {super.key, required this.locations, this.status = RequestStatus.none}); @override Widget build(BuildContext context) { @@ -67,11 +66,11 @@ class LocationsPageView extends StatelessWidget { //TODO:: add support for multiple faculties } - LocationsMap? getMap(BuildContext context) { - if (locations == null || status != RequestStatus.successful) { - return null; + Widget getMap(BuildContext context) { + if (status != RequestStatus.successful) { + return const Center(child: CircularProgressIndicator()); } - return FacultyMaps.getFeupMap(locations!); + return FacultyMaps.getFeupMap(locations); } String getLocation() { diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 852b6b1ab..7b8cb0174 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -115,6 +115,7 @@ class RestaurantDay extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, children: const [ + SizedBox(height: 10), Center( child: Text("Não há informação disponível sobre refeições")), ], From 0365cf968a702986a13ab7d3626d5c5f786cc060 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 17:45:48 +0100 Subject: [PATCH 08/21] Further simplify RequestDependentWidget --- uni/lib/controller/load_info.dart | 36 ------------------- uni/lib/main.dart | 4 --- .../providers/last_user_info_provider.dart | 30 ---------------- .../providers/state_provider_notifier.dart | 3 ++ uni/lib/model/providers/state_providers.dart | 6 ---- uni/lib/view/calendar/calendar.dart | 22 ++++++------ .../common_widgets/last_update_timestamp.dart | 22 +++++++----- .../request_dependent_widget_builder.dart | 25 +++++++------ uni/lib/view/course_units/course_units.dart | 7 ++-- uni/lib/view/home/widgets/exam_card.dart | 6 ++-- .../view/home/widgets/restaurant_card.dart | 7 ++-- uni/lib/view/home/widgets/schedule_card.dart | 6 ++-- uni/lib/view/lazy_consumer.dart | 28 ++++++++------- .../widgets/library_occupation_card.dart | 7 ++-- .../view/restaurant/restaurant_page_view.dart | 7 ++-- uni/lib/view/schedule/schedule.dart | 25 +++++-------- 16 files changed, 81 insertions(+), 160 deletions(-) delete mode 100644 uni/lib/model/providers/last_user_info_provider.dart diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index 746af7fd6..6432a6776 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -6,44 +6,8 @@ import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_providers.dart'; -/*Future loadReloginInfo(StateProviders stateProviders) async { - final Tuple2 userPersistentCredentials = - await AppSharedPreferences.getPersistentUserInfo(); - final String userName = userPersistentCredentials.item1; - final String password = userPersistentCredentials.item2; - final List faculties = await AppSharedPreferences.getUserFaculties(); - - if (userName != '' && password != '') { - final action = Completer(); - stateProviders.sessionProvider - .reLogin(userName, password, faculties, stateProviders, action: action); - return action.future; - } - return Future.error('No credentials stored'); -}*/ - -Future loadUserProfileInfoFromRemote(StateProviders stateProviders) async { - /*if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { - return; - } - - Logger().i('Loading remote info'); - - final session = stateProviders.sessionProvider.session; - if (!session.authenticated && session.persistentSession) { - await loadReloginInfo(stateProviders); - }*/ - - stateProviders.profileStateProvider - .fetchUserInfo(Completer(), stateProviders.sessionProvider.session); - - stateProviders.lastUserInfoProvider - .setLastUserInfoUpdateTimestamp(Completer()); -} - Future handleRefresh(StateProviders stateProviders) async { Logger().e('TODO: handleRefresh'); - // await loadRemoteUserInfoToState(stateProviders); } Future loadProfilePicture(Session session, {forceRetrieval = false}) { diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 1a61266e0..9628b2398 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -13,7 +13,6 @@ import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/providers/faculty_locations_provider.dart'; import 'package:uni/model/providers/home_page_provider.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/model/providers/profile_provider.dart'; @@ -56,7 +55,6 @@ Future main() async { CalendarProvider(), LibraryOccupationProvider(), FacultyLocationsProvider(), - LastUserInfoProvider(), HomePageProvider()); OnStartUp.onStart(stateProviders.sessionProvider); @@ -95,8 +93,6 @@ Future main() async { ChangeNotifierProvider( create: (context) => stateProviders.facultyLocationsProvider), - ChangeNotifierProvider( - create: (context) => stateProviders.lastUserInfoProvider), ChangeNotifierProvider( create: (context) => stateProviders.homePageProvider), ], diff --git a/uni/lib/model/providers/last_user_info_provider.dart b/uni/lib/model/providers/last_user_info_provider.dart deleted file mode 100644 index fb9468c89..000000000 --- a/uni/lib/model/providers/last_user_info_provider.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:async'; - -import 'package:uni/controller/local_storage/app_last_user_info_update_database.dart'; -import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/state_provider_notifier.dart'; - -class LastUserInfoProvider extends StateProviderNotifier { - DateTime? _lastUpdateTime; - - DateTime? get lastUpdateTime => _lastUpdateTime; - - setLastUserInfoUpdateTimestamp(Completer action) async { - _lastUpdateTime = DateTime.now(); - notifyListeners(); - final AppLastUserInfoUpdateDatabase db = AppLastUserInfoUpdateDatabase(); - await db.insertNewTimeStamp(_lastUpdateTime!); - action.complete(); - } - - @override - Future loadFromStorage() async { - final AppLastUserInfoUpdateDatabase db = AppLastUserInfoUpdateDatabase(); - _lastUpdateTime = await db.getLastUserInfoUpdateTime(); - notifyListeners(); - } - - @override - Future loadFromRemote(Session session, Profile profile) async {} -} diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 45d344f63..58cbcfe1a 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -8,9 +8,12 @@ import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { RequestStatus _status = RequestStatus.none; bool _initialized = false; + DateTime? _lastUpdateTime; RequestStatus get status => _status; + DateTime? get lastUpdateTime => _lastUpdateTime; + void updateStatus(RequestStatus status) { _status = status; notifyListeners(); diff --git a/uni/lib/model/providers/state_providers.dart b/uni/lib/model/providers/state_providers.dart index af0287b06..4262f541e 100644 --- a/uni/lib/model/providers/state_providers.dart +++ b/uni/lib/model/providers/state_providers.dart @@ -5,7 +5,6 @@ import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/model/providers/exam_provider.dart'; import 'package:uni/model/providers/faculty_locations_provider.dart'; import 'package:uni/model/providers/home_page_provider.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/model/providers/profile_provider.dart'; @@ -22,7 +21,6 @@ class StateProviders { final CalendarProvider calendarProvider; final LibraryOccupationProvider libraryOccupationProvider; final FacultyLocationsProvider facultyLocationsProvider; - final LastUserInfoProvider lastUserInfoProvider; final HomePageProvider homePageProvider; StateProviders( @@ -35,7 +33,6 @@ class StateProviders { this.calendarProvider, this.libraryOccupationProvider, this.facultyLocationsProvider, - this.lastUserInfoProvider, this.homePageProvider); static StateProviders fromContext(BuildContext context) { @@ -56,8 +53,6 @@ class StateProviders { Provider.of(context, listen: false); final facultyLocationsProvider = Provider.of(context, listen: false); - final lastUserInfoProvider = - Provider.of(context, listen: false); final homePageProvider = Provider.of(context, listen: false); @@ -71,7 +66,6 @@ class StateProviders { calendarProvider, libraryOccupationProvider, facultyLocationsProvider, - lastUserInfoProvider, homePageProvider); } } diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 181ec4036..8a80a3928 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -4,6 +4,7 @@ import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/calendar_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/lazy_consumer.dart'; class CalendarPageView extends StatefulWidget { @@ -17,18 +18,19 @@ class CalendarPageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { return LazyConsumer( - builder: (context, calendarProvider) => - getCalendarPage(context, calendarProvider.calendar), - ); - } - - Widget getCalendarPage(BuildContext context, List calendar) { - return ListView( - children: [_getPageTitle(), getTimeline(context, calendar)]); + builder: (context, calendarProvider) => ListView(children: [ + _getPageTitle(), + RequestDependentWidgetBuilder( + status: calendarProvider.status, + builder: () => + getTimeline(context, calendarProvider.calendar), + hasContentPredicate: calendarProvider.calendar.isNotEmpty, + onNullContent: const Center( + child: Text('Nenhum evento encontrado', + style: TextStyle(fontSize: 18.0)))) + ])); } - // TODO - Widget _getPageTitle() { return Container( padding: const EdgeInsets.only(bottom: 6.0), diff --git a/uni/lib/view/common_widgets/last_update_timestamp.dart b/uni/lib/view/common_widgets/last_update_timestamp.dart index a996352c1..b674d1f05 100644 --- a/uni/lib/view/common_widgets/last_update_timestamp.dart +++ b/uni/lib/view/common_widgets/last_update_timestamp.dart @@ -1,19 +1,21 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; +import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/view/lazy_consumer.dart'; -class LastUpdateTimeStamp extends StatefulWidget { +class LastUpdateTimeStamp + extends StatefulWidget { const LastUpdateTimeStamp({super.key}); @override State createState() { - return _LastUpdateTimeStampState(); + return _LastUpdateTimeStampState(); } } -class _LastUpdateTimeStampState extends State { +class _LastUpdateTimeStampState + extends State { DateTime currentTime = DateTime.now(); @override @@ -33,11 +35,13 @@ class _LastUpdateTimeStampState extends State { @override Widget build(BuildContext context) { - return LazyConsumer( - builder: (context, lastUserInfoProvider) => Container( - padding: const EdgeInsets.only(top: 8.0, bottom: 10.0), - child: _getContent(context, lastUserInfoProvider.lastUpdateTime!)), - ); + return LazyConsumer( + builder: (context, provider) => Container( + padding: const EdgeInsets.only(top: 8.0, bottom: 10.0), + child: provider.lastUpdateTime != null + ? _getContent(context, provider.lastUpdateTime!) + : null, + )); } Widget _getContent(BuildContext context, DateTime lastUpdateTime) { diff --git a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart index a1c2c363a..29502ddf1 100644 --- a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart +++ b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart @@ -7,39 +7,38 @@ import 'package:uni/utils/drawer_items.dart'; /// Wraps content given its fetch data from the redux store, /// hydrating the component, displaying an empty message, /// a connection error or a loading circular effect as appropriate - class RequestDependentWidgetBuilder extends StatelessWidget { const RequestDependentWidgetBuilder( {Key? key, - required this.context, required this.status, - required this.contentGenerator, - required this.content, - required this.contentChecker, + required this.builder, + required this.hasContentPredicate, required this.onNullContent, this.contentLoadingWidget}) : super(key: key); - final BuildContext context; final RequestStatus status; - final Widget Function(dynamic, BuildContext) contentGenerator; + final Widget Function() builder; final Widget? contentLoadingWidget; - final dynamic content; - final bool contentChecker; + final bool hasContentPredicate; final Widget onNullContent; @override Widget build(BuildContext context) { - if (status == RequestStatus.busy && !contentChecker) { - return loadingWidget(); + if (status == RequestStatus.busy && !hasContentPredicate) { + return loadingWidget(context); } else if (status == RequestStatus.failed) { return requestFailedMessage(); } - return contentChecker ? contentGenerator(content, context) : onNullContent; + return hasContentPredicate + ? builder() + : Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: onNullContent); } - Widget loadingWidget() { + Widget loadingWidget(BuildContext context) { return contentLoadingWidget == null ? const Center( child: Padding( diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index adbff9f5c..e6ec3ac79 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -78,11 +78,10 @@ class CourseUnitsPageViewState return Column(children: [ _getPageTitleAndFilters(availableYears, availableSemesters), RequestDependentWidgetBuilder( - context: context, status: requestStatus ?? RequestStatus.none, - contentGenerator: _generateCourseUnitsCards, - content: filteredCourseUnits ?? [], - contentChecker: courseUnits?.isNotEmpty ?? false, + builder: () => + _generateCourseUnitsCards(filteredCourseUnits, context), + hasContentPredicate: courseUnits?.isNotEmpty ?? false, onNullContent: Center( heightFactor: 10, child: Text('Não existem cadeiras para apresentar', diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index d00e962d0..9b2285100 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -39,11 +39,9 @@ class ExamCard extends GenericCard { .where((exam) => (!hiddenExams.contains(exam.id))) .toList(); return RequestDependentWidgetBuilder( - context: context, status: examProvider.status, - contentGenerator: generateExams, - content: exams, - contentChecker: exams.isNotEmpty, + builder: () => generateExams(exams, context), + hasContentPredicate: exams.isNotEmpty, onNullContent: Center( child: Text('Não existem exames para apresentar', style: Theme.of(context).textTheme.titleLarge), diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 0f7c248dc..34c892dcc 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -24,11 +24,10 @@ class RestaurantCard extends GenericCard { Widget buildCardContent(BuildContext context) { return LazyConsumer( builder: (context, restaurantProvider) => RequestDependentWidgetBuilder( - context: context, status: restaurantProvider.status, - contentGenerator: generateRestaurant, - content: restaurantProvider.restaurants, - contentChecker: restaurantProvider.restaurants.isNotEmpty, + builder: () => + generateRestaurant(restaurantProvider.restaurants, context), + hasContentPredicate: restaurantProvider.restaurants.isNotEmpty, onNullContent: Center( child: Text('Não existem cantinas para apresentar', style: Theme.of(context).textTheme.headlineMedium, diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index cf4ff2214..414d1c9e9 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -25,11 +25,9 @@ class ScheduleCard extends GenericCard { Widget buildCardContent(BuildContext context) { return LazyConsumer( builder: (context, lectureProvider) => RequestDependentWidgetBuilder( - context: context, status: lectureProvider.status, - contentGenerator: generateSchedule, - content: lectureProvider.lectures, - contentChecker: lectureProvider.lectures.isNotEmpty, + builder: () => generateSchedule(lectureProvider.lectures, context), + hasContentPredicate: lectureProvider.lectures.isNotEmpty, onNullContent: Center( child: Text('Não existem aulas para apresentar', style: Theme.of(context).textTheme.titleLarge, diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 970b30862..bcde3ae1f 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -7,9 +7,8 @@ import 'package:uni/model/providers/state_provider_notifier.dart'; /// Wrapper around Consumer that ensures that the provider is initialized, /// meaning that it has loaded its data from storage and/or remote. /// The provider will not reload its data if it has already been loaded before. -/// The user session should be valid before calling this widget. -/// There must be a SessionProvider and a ProfileProvider above this widget in -/// the widget tree. +/// There should be a SessionProvider and a ProfileProvider above this widget in +/// the widget tree to initialize the provider data the first time. class LazyConsumer extends StatelessWidget { final Widget Function(BuildContext, T) builder; @@ -20,16 +19,21 @@ class LazyConsumer extends StatelessWidget { @override Widget build(BuildContext context) { - final sessionProvider = Provider.of(context); - final profileProvider = Provider.of(context); + try { + final sessionProvider = Provider.of(context); + final profileProvider = Provider.of(context); - WidgetsBinding.instance.addPostFrameCallback((_) { - final session = sessionProvider.session; - final profile = profileProvider.profile; - profileProvider.ensureInitialized(session, profile).then((value) => - Provider.of(context, listen: false) - .ensureInitialized(session, profile)); - }); + WidgetsBinding.instance.addPostFrameCallback((_) { + final session = sessionProvider.session; + final profile = profileProvider.profile; + profileProvider.ensureInitialized(session, profile).then((value) => + Provider.of(context, listen: false) + .ensureInitialized(session, profile)); + }); + } catch (_) { + // The provider won't be initialized + // Should only happen in tests + } return Consumer(builder: (context, provider, _) { return builder(context, provider); diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index be02eee33..d4e9c6027 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -27,11 +27,10 @@ class LibraryOccupationCard extends GenericCard { return LazyConsumer( builder: (context, libraryOccupationProvider) => RequestDependentWidgetBuilder( - context: context, status: libraryOccupationProvider.status, - contentGenerator: generateOccupation, - content: libraryOccupationProvider.occupation, - contentChecker: + builder: () => generateOccupation( + libraryOccupationProvider.occupation, context), + hasContentPredicate: libraryOccupationProvider.status != RequestStatus.busy, onNullContent: const CircularProgressIndicator())); } diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 7b8cb0174..3be1417b2 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -52,11 +52,10 @@ class _RestaurantPageState extends GeneralPageViewState ]), const SizedBox(height: 10), RequestDependentWidgetBuilder( - context: context, status: restaurantProvider.status, - contentGenerator: createTabViewBuilder, - content: restaurantProvider.restaurants, - contentChecker: restaurantProvider.restaurants.isNotEmpty, + builder: () => + createTabViewBuilder(restaurantProvider.restaurants, context), + hasContentPredicate: restaurantProvider.restaurants.isNotEmpty, onNullContent: const Center(child: Text('Não há refeições disponíveis.'))) ]); diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 7943f89d3..ff5dd4f69 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -154,29 +154,22 @@ class SchedulePageViewState extends GeneralPageViewState return scheduleContent; } - Widget Function(dynamic daycontent, BuildContext context) dayColumnBuilder( - int day) { - Widget createDayColumn(dayContent, BuildContext context) { - return Container( - key: Key('schedule-page-day-column-$day'), - child: Column( - mainAxisSize: MainAxisSize.min, - children: createScheduleRows(dayContent, context), - )); - } - - return createDayColumn; + Widget dayColumnBuilder(int day, dayContent, BuildContext context) { + return Container( + key: Key('schedule-page-day-column-$day'), + child: Column( + mainAxisSize: MainAxisSize.min, + children: createScheduleRows(dayContent, context), + )); } Widget createScheduleByDay(BuildContext context, int day, List? lectures, RequestStatus? scheduleStatus) { final List aggLectures = SchedulePageView.groupLecturesByDay(lectures); return RequestDependentWidgetBuilder( - context: context, status: scheduleStatus ?? RequestStatus.none, - contentGenerator: dayColumnBuilder(day), - content: aggLectures[day], - contentChecker: aggLectures[day].isNotEmpty, + builder: () => dayColumnBuilder(day, aggLectures[day], context), + hasContentPredicate: aggLectures[day].isNotEmpty, onNullContent: Center( child: Text( 'Não possui aulas à ${SchedulePageView.daysOfTheWeek[day]}.')), From a3f4b4e3829d6afd2822d2aa58be72bcd36dae5c Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 17:49:04 +0100 Subject: [PATCH 09/21] Fix tests --- .../integration/src/schedule_page_test.dart | 2 -- .../view/Pages/schedule_page_view_test.dart | 23 ++++++------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index ba74d834a..d4ffa5e8c 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -14,7 +14,6 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/view/schedule/schedule.dart'; @@ -54,7 +53,6 @@ void main() { final providers = [ ChangeNotifierProvider(create: (_) => scheduleProvider), - ChangeNotifierProvider(create: (_) => LastUserInfoProvider()), ]; await tester.pumpWidget(testableWidget(widget, providers: providers)); diff --git a/uni/test/unit/view/Pages/schedule_page_view_test.dart b/uni/test/unit/view/Pages/schedule_page_view_test.dart index 3faa375ef..e8eea58d1 100644 --- a/uni/test/unit/view/Pages/schedule_page_view_test.dart +++ b/uni/test/unit/view/Pages/schedule_page_view_test.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/providers/last_user_info_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/view/schedule/schedule.dart'; import 'package:uni/view/schedule/widgets/schedule_slot.dart'; @@ -21,10 +19,10 @@ void main() { final lecture1 = Lecture.fromHtml( 'SOPE', 'T', day0, '10:00', blocks, 'B315', 'JAS', classNumber, 484378); - final lecture2 = Lecture.fromHtml( - 'SDIS', 'T', day0, '13:00', blocks, 'B315', 'PMMS', classNumber, 484381); - final lecture3 = Lecture.fromHtml( - 'AMAT', 'T', day1, '12:00', blocks, 'B315', 'PMMS', classNumber, 484362); + final lecture2 = Lecture.fromHtml('SDIS', 'T', day0, '13:00', blocks, + 'B315', 'PMMS', classNumber, 484381); + final lecture3 = Lecture.fromHtml('AMAT', 'T', day1, '12:00', blocks, + 'B315', 'PMMS', classNumber, 484362); final lecture4 = Lecture.fromHtml( 'PROG', 'T', day2, '10:00', blocks, 'B315', 'JAS', classNumber, 484422); final lecture5 = Lecture.fromHtml( @@ -40,17 +38,12 @@ void main() { 'Sexta-feira' ]; - final providers = [ - ChangeNotifierProvider( - create: (_) => LastUserInfoProvider()), - ]; - testWidgets('When given one lecture on a single day', (WidgetTester tester) async { final widget = SchedulePageView( lectures: [lecture1], scheduleStatus: RequestStatus.successful); - await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pumpWidget(testableWidget(widget, providers: [])); await tester.pumpAndSettle(); final SchedulePageViewState myWidgetState = tester.state(find.byType(SchedulePageView)); @@ -69,7 +62,7 @@ void main() { final widget = SchedulePageView( lectures: [lecture1, lecture2], scheduleStatus: RequestStatus.successful); - await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pumpWidget(testableWidget(widget, providers: [])); await tester.pumpAndSettle(); final SchedulePageViewState myWidgetState = tester.state(find.byType(SchedulePageView)); @@ -95,9 +88,7 @@ void main() { lecture6 ], scheduleStatus: RequestStatus.successful)); - - - await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pumpWidget(testableWidget(widget, providers: [])); await tester.pumpAndSettle(); final SchedulePageViewState myWidgetState = tester.state(find.byType(SchedulePageView)); From 4e14bdf3e513a4f49ddd735a27b525626aa77529 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 18:08:56 +0100 Subject: [PATCH 10/21] Fix last update timestamp widget --- .../local_storage/app_shared_preferences.dart | 23 +++++++++++++++---- .../providers/state_provider_notifier.dart | 6 +++++ .../bus_stop_next_arrivals.dart | 2 +- .../widgets/bus_stop_row.dart | 11 +++++---- .../bus_stop_selection.dart | 2 +- uni/lib/view/home/widgets/bus_stop_card.dart | 2 +- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index 9134e9ef4..6db64b9ed 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -12,12 +12,14 @@ import 'package:uni/utils/favorite_widget_type.dart'; /// This database stores the user's student number, password and favorite /// widgets. class AppSharedPreferences { + static const lastUpdateTimeKeySuffix = "_last_update_time"; static const String userNumber = 'user_number'; static const String userPw = 'user_password'; static const String userFaculties = 'user_faculties'; static const String termsAndConditions = 'terms_and_conditions'; static const String areTermsAndConditionsAcceptedKey = 'is_t&c_accepted'; - static const String tuitionNotificationsToggleKey = "tuition_notification_toogle"; + static const String tuitionNotificationsToggleKey = + "tuition_notification_toogle"; static const String themeMode = 'theme_mode'; static const int keyLength = 32; static const int ivLength = 16; @@ -33,6 +35,20 @@ class AppSharedPreferences { static const String filteredExamsTypes = 'filtered_exam_types'; static final List defaultFilteredExamTypes = Exam.displayedTypes; + /// Returns the last time the data with given key was updated. + static Future getLastDataClassUpdateTime(String dataKey) async { + final prefs = await SharedPreferences.getInstance(); + final lastUpdateTime = prefs.getString(dataKey + lastUpdateTimeKeySuffix); + return lastUpdateTime != null ? DateTime.parse(lastUpdateTime) : null; + } + + /// Sets the last time the data with given key was updated. + static Future setLastDataClassUpdateTime( + String dataKey, DateTime dateTime) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(dataKey + lastUpdateTimeKeySuffix, dateTime.toString()); + } + /// Saves the user's student number, password and faculties. static Future savePersistentUserInfo(user, pass, faculties) async { final prefs = await SharedPreferences.getInstance(); @@ -203,14 +219,13 @@ class AppSharedPreferences { return encrypt.Encrypter(encrypt.AES(key)); } - static Future getTuitionNotificationToggle() async{ + static Future getTuitionNotificationToggle() async { final prefs = await SharedPreferences.getInstance(); return prefs.getBool(tuitionNotificationsToggleKey) ?? true; } - static setTuitionNotificationToggle(bool value) async{ + static setTuitionNotificationToggle(bool value) async { final prefs = await SharedPreferences.getInstance(); prefs.setBool(tuitionNotificationsToggleKey, value); } - } diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 58cbcfe1a..b653cb719 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -26,6 +26,9 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initialized = true; + _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( + runtimeType.toString()); + updateStatus(RequestStatus.busy); final userPersistentInfo = @@ -38,6 +41,9 @@ abstract class StateProviderNotifier extends ChangeNotifier { if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { await loadFromRemote(session, profile); + _lastUpdateTime = DateTime.now(); + await AppSharedPreferences.setLastDataClassUpdateTime( + runtimeType.toString(), _lastUpdateTime!); } notifyListeners(); diff --git a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index ad2c15092..f730eff7c 100644 --- a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -126,7 +126,7 @@ class NextArrivalsState extends State { children: [ Container( padding: const EdgeInsets.only(left: 10.0), - child: const LastUpdateTimeStamp(), + child: const LastUpdateTimeStamp(), ), IconButton( icon: const Icon(Icons.edit), diff --git a/uni/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart b/uni/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart index f0712c2c9..ce09b350b 100644 --- a/uni/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart +++ b/uni/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart @@ -46,10 +46,13 @@ class BusStopRow extends StatelessWidget { } Widget noTripsContainer(context) { - return Text('Não há viagens planeadas de momento.', - maxLines: 3, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleMedium); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Text('Não há viagens planeadas de momento.', + maxLines: 3, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleMedium)); } Widget stopCodeRotatedContainer(context) { diff --git a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart index 08eb2dd8a..c4ee72861 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -49,7 +49,7 @@ class BusStopSelectionPageState Container( padding: const EdgeInsets.all(20.0), child: const Text( - '''Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos.''' + '''Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. ''' '''Os restantes serão apresentados apenas na página.''', textAlign: TextAlign.center)), Column(children: rows), diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index d5a12acb1..7097b8e7f 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -115,7 +115,7 @@ Widget getBusStopsInfo(context, Map stopData) { List getEachBusStopInfo(context, Map stopData) { final List rows = []; - rows.add(const LastUpdateTimeStamp()); + rows.add(const LastUpdateTimeStamp()); stopData.forEach((stopCode, stopInfo) { if (stopInfo.trips.isNotEmpty && stopInfo.favorited) { From 6aee5521c0a3b9bc8e37fe5b6a387128d50bfda4 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 18:50:26 +0100 Subject: [PATCH 11/21] Make each page responsible for refreshing --- uni/lib/controller/load_info.dart | 6 ---- .../providers/state_provider_notifier.dart | 29 +++++++++++++++---- uni/lib/view/about/about.dart | 5 +++- uni/lib/view/bug_report/bug_report.dart | 3 ++ .../bus_stop_next_arrivals.dart | 7 +++++ .../bus_stop_selection.dart | 3 ++ uni/lib/view/calendar/calendar.dart | 7 +++++ .../pages_layouts/general/general.dart | 18 ++++-------- .../course_unit_info/course_unit_info.dart | 5 +++- uni/lib/view/course_units/course_units.dart | 7 +++++ uni/lib/view/exams/exams.dart | 6 ++++ uni/lib/view/home/home.dart | 6 ++++ uni/lib/view/library/library.dart | 7 +++++ uni/lib/view/locations/locations.dart | 5 +++- uni/lib/view/login/login.dart | 2 -- uni/lib/view/profile/profile.dart | 7 +++++ .../view/restaurant/restaurant_page_view.dart | 7 +++++ uni/lib/view/schedule/schedule.dart | 7 +++++ uni/lib/view/useful_info/useful_info.dart | 5 +++- 19 files changed, 112 insertions(+), 30 deletions(-) diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index 6432a6776..92fe751c4 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -1,14 +1,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:logger/logger.dart'; import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/state_providers.dart'; - -Future handleRefresh(StateProviders stateProviders) async { - Logger().e('TODO: handleRefresh'); -} Future loadProfilePicture(Session session, {forceRetrieval = false}) { final String studentNumber = session.studentNumber; diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index b653cb719..54caedfd2 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,8 +1,11 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; +import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { @@ -14,11 +17,30 @@ abstract class StateProviderNotifier extends ChangeNotifier { DateTime? get lastUpdateTime => _lastUpdateTime; + Future _loadFromRemote(Session session, Profile profile) async { + if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { + await loadFromRemote(session, profile); + _lastUpdateTime = DateTime.now(); + await AppSharedPreferences.setLastDataClassUpdateTime( + runtimeType.toString(), _lastUpdateTime!); + } + } + void updateStatus(RequestStatus status) { _status = status; notifyListeners(); } + Future forceRefresh(BuildContext context) async { + final session = + Provider.of(context, listen: false).session; + final profile = + Provider.of(context, listen: false).profile; + + updateStatus(RequestStatus.busy); + _loadFromRemote(session, profile); + } + Future ensureInitialized(Session session, Profile profile) async { if (_initialized) { return; @@ -39,12 +61,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { await loadFromStorage(); } - if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - await loadFromRemote(session, profile); - _lastUpdateTime = DateTime.now(); - await AppSharedPreferences.setLastDataClassUpdateTime( - runtimeType.toString(), _lastUpdateTime!); - } + _loadFromRemote(session, profile); notifyListeners(); } diff --git a/uni/lib/view/about/about.dart b/uni/lib/view/about/about.dart index 411a1901d..f1a66c3e0 100644 --- a/uni/lib/view/about/about.dart +++ b/uni/lib/view/about/about.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/about/widgets/terms_and_conditions.dart'; +import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; class AboutPageView extends StatefulWidget { const AboutPageView({super.key}); @@ -38,4 +38,7 @@ class AboutPageViewState extends GeneralPageViewState { ], ); } + + @override + Future handleRefresh(BuildContext context) async {} } diff --git a/uni/lib/view/bug_report/bug_report.dart b/uni/lib/view/bug_report/bug_report.dart index 6a263d31a..32db38934 100644 --- a/uni/lib/view/bug_report/bug_report.dart +++ b/uni/lib/view/bug_report/bug_report.dart @@ -18,4 +18,7 @@ class BugReportPageViewState extends GeneralPageViewState { margin: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 20.0), child: const BugReportForm()); } + + @override + Future handleRefresh(BuildContext context) async {} } diff --git a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index f730eff7c..60677bc01 100644 --- a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; import 'package:uni/model/request_status.dart'; @@ -26,6 +27,12 @@ class BusStopNextArrivalsPageState NextArrivals(busProvider.configuredBusStops, busProvider.status) ])); } + + @override + Future handleRefresh(BuildContext context) async { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } class NextArrivals extends StatefulWidget { diff --git a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart index c4ee72861..ad4e1e5ad 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -72,4 +72,7 @@ class BusStopSelectionPageState ]); }); } + + @override + Future handleRefresh(BuildContext context) async {} } diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 8a80a3928..6b341be61 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/calendar_provider.dart'; @@ -68,4 +69,10 @@ class CalendarPageViewState extends GeneralPageViewState { ), ); } + + @override + Future handleRefresh(BuildContext context) { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } diff --git a/uni/lib/view/common_widgets/pages_layouts/general/general.dart b/uni/lib/view/common_widgets/pages_layouts/general/general.dart index ad8f9f20e..fde15635f 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -6,7 +6,6 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/load_info.dart'; import 'package:uni/model/providers/session_provider.dart'; -import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart'; import 'package:uni/view/profile/profile.dart'; @@ -16,6 +15,8 @@ abstract class GeneralPageViewState extends State { final double borderMargin = 18.0; static ImageProvider? profileImageProvider; + Future handleRefresh(BuildContext context); + @override Widget build(BuildContext context) { return getScaffold(context, getBody(context)); @@ -52,21 +53,14 @@ abstract class GeneralPageViewState extends State { Widget refreshState(BuildContext context, Widget child) { return RefreshIndicator( key: GlobalKey(), - onRefresh: refreshCallback(context), + onRefresh: () => loadProfilePicture( + Provider.of(context, listen: false).session, + forceRetrieval: true) + .then((value) => handleRefresh(context)), child: child, ); } - Future Function() refreshCallback(BuildContext context) { - return () async { - final stateProviders = StateProviders.fromContext(context); - await loadProfilePicture( - Provider.of(context, listen: false).session, - forceRetrieval: true); - return handleRefresh(stateProviders); - }; - } - Widget getScaffold(BuildContext context, Widget body) { return Scaffold( appBar: buildAppBar(context), diff --git a/uni/lib/view/course_unit_info/course_unit_info.dart b/uni/lib/view/course_unit_info/course_unit_info.dart index b9a28c8cb..37c11f505 100644 --- a/uni/lib/view/course_unit_info/course_unit_info.dart +++ b/uni/lib/view/course_unit_info/course_unit_info.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/course_unit.dart'; -import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; import 'package:uni/view/common_widgets/page_title.dart'; +import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; class CourseUnitDetailPageView extends StatefulWidget { final CourseUnit courseUnit; @@ -36,4 +36,7 @@ class CourseUnitDetailPageViewState ])) ]); } + + @override + Future handleRefresh(BuildContext context) async {} } diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index e6ec3ac79..d9be172e3 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -1,5 +1,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/model/request_status.dart'; @@ -191,4 +192,10 @@ class CourseUnitsPageViewState .sorted() + [CourseUnitsPageView.bothSemestersDropdownOption]; } + + @override + Future handleRefresh(BuildContext context) { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 5988080be..9413971dc 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -117,4 +117,10 @@ class ExamsPageViewState extends GeneralPageViewState { : Theme.of(context).scaffoldBackgroundColor, child: ExamRow(exam: exam, teacher: '', mainPage: false))); } + + @override + Future handleRefresh(BuildContext context) async { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } diff --git a/uni/lib/view/home/home.dart b/uni/lib/view/home/home.dart index 613e0c18a..f10d62063 100644 --- a/uni/lib/view/home/home.dart +++ b/uni/lib/view/home/home.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:logger/logger.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/home/widgets/main_cards_list.dart'; @@ -15,4 +16,9 @@ class HomePageViewState extends GeneralPageViewState { Widget getBody(BuildContext context) { return MainCardsList(); } + + @override + Future handleRefresh(BuildContext context) async { + Logger().e('TODO: Iterate over cards and refresh them.'); + } } diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index eb2f3bfc4..9025266e8 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/library_occupation.dart'; import 'package:uni/model/providers/library_occupation_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; @@ -21,6 +22,12 @@ class LibraryPageViewState extends GeneralPageViewState { builder: (context, libraryOccupationProvider) => LibraryPage(libraryOccupationProvider.occupation)); } + + @override + Future handleRefresh(BuildContext context) { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } class LibraryPage extends StatelessWidget { diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index 53b7ac05c..956c636be 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -35,6 +35,9 @@ class LocationsPageState extends GeneralPageViewState }, ); } + + @override + Future handleRefresh(BuildContext context) async {} } class LocationsPageView extends StatelessWidget { @@ -78,7 +81,7 @@ class LocationsPageView extends StatelessWidget { } List getMarkers() { - return locations!.map((location) { + return locations.map((location) { return LocationMarker(location.latlng, location); }).toList(); } diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 9b2b431c3..f0395c19f 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -13,8 +13,6 @@ import 'package:uni/view/login/widgets/inputs.dart'; import 'package:uni/view/theme.dart'; import 'package:url_launcher/url_launcher.dart'; -import '../lazy_consumer.dart'; - class LoginPageView extends StatefulWidget { const LoginPageView({super.key}); diff --git a/uni/lib/view/profile/profile.dart b/uni/lib/view/profile/profile.dart index 656477735..97bff9f00 100644 --- a/uni/lib/view/profile/profile.dart +++ b/uni/lib/view/profile/profile.dart @@ -1,5 +1,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/providers/profile_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; import 'package:uni/view/lazy_consumer.dart'; @@ -47,4 +48,10 @@ class ProfilePageViewState extends SecondaryPageViewState { Widget getTopRightButton(BuildContext context) { return Container(); } + + @override + Future handleRefresh(BuildContext context) async { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 3be1417b2..b568a82a6 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; @@ -95,6 +96,12 @@ class _RestaurantPageState extends GeneralPageViewState return tabs; } + + @override + Future handleRefresh(BuildContext context) { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } class RestaurantDay extends StatelessWidget { diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index ff5dd4f69..0831d96d0 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/lecture_provider.dart'; @@ -175,4 +176,10 @@ class SchedulePageViewState extends GeneralPageViewState 'Não possui aulas à ${SchedulePageView.daysOfTheWeek[day]}.')), ); } + + @override + Future handleRefresh(BuildContext context) { + return Provider.of(context, listen: false) + .forceRefresh(context); + } } diff --git a/uni/lib/view/useful_info/useful_info.dart b/uni/lib/view/useful_info/useful_info.dart index cb6b83dc7..e923a6194 100644 --- a/uni/lib/view/useful_info/useful_info.dart +++ b/uni/lib/view/useful_info/useful_info.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/useful_info/widgets/academic_services_card.dart'; import 'package:uni/view/useful_info/widgets/copy_center_card.dart'; @@ -7,7 +8,6 @@ import 'package:uni/view/useful_info/widgets/infodesk_card.dart'; import 'package:uni/view/useful_info/widgets/multimedia_center_card.dart'; import 'package:uni/view/useful_info/widgets/other_links_card.dart'; import 'package:uni/view/useful_info/widgets/sigarra_links_card.dart'; -import 'package:uni/view/common_widgets/page_title.dart'; class UsefulInfoPageView extends StatefulWidget { const UsefulInfoPageView({super.key}); @@ -37,4 +37,7 @@ class UsefulInfoPageViewState extends GeneralPageViewState { padding: const EdgeInsets.only(bottom: 6.0), child: const PageTitle(name: 'Úteis')); } + + @override + Future handleRefresh(BuildContext context) async {} } From b23fe1ba70a7a9d2c3eb2ea968030120c100358e Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 7 Jul 2023 19:21:59 +0100 Subject: [PATCH 12/21] Refresh home page --- .../providers/state_provider_notifier.dart | 3 ++ uni/lib/view/home/home.dart | 47 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 54caedfd2..54afd3938 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -59,6 +59,9 @@ abstract class StateProviderNotifier extends ChangeNotifier { userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; if (sessionIsPersistent) { await loadFromStorage(); + if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { + updateStatus(RequestStatus.none); + } } _loadFromRemote(session, profile); diff --git a/uni/lib/view/home/home.dart b/uni/lib/view/home/home.dart index f10d62063..b2f173e12 100644 --- a/uni/lib/view/home/home.dart +++ b/uni/lib/view/home/home.dart @@ -1,8 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:logger/logger.dart'; +import 'package:provider/provider.dart'; +import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/providers/library_occupation_provider.dart'; +import 'package:uni/model/providers/state_provider_notifier.dart'; +import 'package:uni/utils/favorite_widget_type.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/home/widgets/main_cards_list.dart'; +import '../../model/providers/home_page_provider.dart'; +import '../../model/providers/profile_provider.dart'; + class HomePageView extends StatefulWidget { const HomePageView({super.key}); @@ -19,6 +28,40 @@ class HomePageViewState extends GeneralPageViewState { @override Future handleRefresh(BuildContext context) async { - Logger().e('TODO: Iterate over cards and refresh them.'); + final homePageProvider = + Provider.of(context, listen: false); + + final providersToUpdate = {}; + + for (final cardType in homePageProvider.favoriteCards) { + switch (cardType) { + case FavoriteWidgetType.account: + providersToUpdate + .add(Provider.of(context, listen: false)); + break; + case FavoriteWidgetType.exams: + providersToUpdate + .add(Provider.of(context, listen: false)); + break; + case FavoriteWidgetType.schedule: + providersToUpdate + .add(Provider.of(context, listen: false)); + break; + case FavoriteWidgetType.printBalance: + providersToUpdate + .add(Provider.of(context, listen: false)); + break; + case FavoriteWidgetType.libraryOccupation: + providersToUpdate.add( + Provider.of(context, listen: false)); + break; + case FavoriteWidgetType.busStops: + providersToUpdate + .add(Provider.of(context, listen: false)); + break; + } + } + + Future.wait(providersToUpdate.map((e) => e.forceRefresh(context))); } } From 068a02a0a005d4ffdfcc912c3f5449ea6311cef3 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 10 Jul 2023 14:40:12 +0100 Subject: [PATCH 13/21] Do not wait for session provider if not dependant on it --- uni/lib/controller/on_start_up.dart | 2 +- uni/lib/main.dart | 20 +++--- .../{ => lazy}/bus_stop_provider.dart | 2 + .../{ => lazy}/calendar_provider.dart | 2 + .../providers/{ => lazy}/exam_provider.dart | 2 + .../faculty_locations_provider.dart | 2 + .../{ => lazy}/home_page_provider.dart | 5 +- .../{ => lazy}/lecture_provider.dart | 2 + .../library_occupation_provider.dart | 2 + .../{ => lazy}/restaurant_provider.dart | 2 + .../{ => startup}/profile_provider.dart | 2 + .../{ => startup}/session_provider.dart | 34 +++------- .../providers/state_provider_notifier.dart | 67 ++++++++++++------- uni/lib/model/providers/state_providers.dart | 20 +++--- .../bus_stop_next_arrivals.dart | 2 +- .../widgets/estimated_arrival_timestamp.dart | 2 +- .../bus_stop_selection.dart | 2 +- .../widgets/bus_stop_search.dart | 2 +- .../widgets/bus_stop_selection_row.dart | 2 +- .../view/bus_stop_selection/widgets/form.dart | 2 +- uni/lib/view/calendar/calendar.dart | 2 +- .../pages_layouts/general/general.dart | 2 +- .../general/widgets/navigation_drawer.dart | 2 +- uni/lib/view/course_units/course_units.dart | 2 +- uni/lib/view/exams/exams.dart | 2 +- .../view/exams/widgets/exam_filter_form.dart | 2 +- .../view/exams/widgets/exam_filter_menu.dart | 2 +- uni/lib/view/exams/widgets/exam_row.dart | 8 +-- uni/lib/view/home/home.dart | 13 ++-- uni/lib/view/home/widgets/bus_stop_card.dart | 2 +- uni/lib/view/home/widgets/exam_card.dart | 2 +- .../view/home/widgets/main_cards_list.dart | 4 +- .../view/home/widgets/restaurant_card.dart | 2 +- uni/lib/view/home/widgets/schedule_card.dart | 2 +- uni/lib/view/lazy_consumer.dart | 23 ++++--- uni/lib/view/library/library.dart | 2 +- .../widgets/library_occupation_card.dart | 2 +- uni/lib/view/locations/locations.dart | 2 +- uni/lib/view/login/login.dart | 5 +- uni/lib/view/profile/profile.dart | 2 +- .../profile/widgets/account_info_card.dart | 2 +- .../widgets/create_print_mb_dialog.dart | 2 +- .../view/profile/widgets/print_info_card.dart | 2 +- .../profile/widgets/profile_overview.dart | 2 +- .../view/restaurant/restaurant_page_view.dart | 2 +- uni/lib/view/schedule/schedule.dart | 2 +- uni/lib/view/splash/splash.dart | 2 +- uni/test/integration/src/exams_page_test.dart | 2 +- .../integration/src/schedule_page_test.dart | 2 +- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- .../unit/view/Pages/exams_page_view_test.dart | 64 +++++++----------- uni/test/unit/view/Widgets/exam_row_test.dart | 4 +- 53 files changed, 182 insertions(+), 167 deletions(-) rename uni/lib/model/providers/{ => lazy}/bus_stop_provider.dart (98%) rename uni/lib/model/providers/{ => lazy}/calendar_provider.dart (96%) rename uni/lib/model/providers/{ => lazy}/exam_provider.dart (98%) rename uni/lib/model/providers/{ => lazy}/faculty_locations_provider.dart (93%) rename uni/lib/model/providers/{ => lazy}/home_page_provider.dart (94%) rename uni/lib/model/providers/{ => lazy}/lecture_provider.dart (98%) rename uni/lib/model/providers/{ => lazy}/library_occupation_provider.dart (96%) rename uni/lib/model/providers/{ => lazy}/restaurant_provider.dart (96%) rename uni/lib/model/providers/{ => startup}/profile_provider.dart (99%) rename uni/lib/model/providers/{ => startup}/session_provider.dart (74%) diff --git a/uni/lib/controller/on_start_up.dart b/uni/lib/controller/on_start_up.dart index 48eb205a5..f51e5a032 100644 --- a/uni/lib/controller/on_start_up.dart +++ b/uni/lib/controller/on_start_up.dart @@ -1,5 +1,5 @@ import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/navigation_service.dart'; class OnStartUp { diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 9628b2398..3b5039fe7 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -8,16 +8,16 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/controller/background_workers/background_callback.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/on_start_up.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; -import 'package:uni/model/providers/calendar_provider.dart'; -import 'package:uni/model/providers/exam_provider.dart'; -import 'package:uni/model/providers/faculty_locations_provider.dart'; -import 'package:uni/model/providers/home_page_provider.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; -import 'package:uni/model/providers/library_occupation_provider.dart'; -import 'package:uni/model/providers/profile_provider.dart'; -import 'package:uni/model/providers/restaurant_provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/calendar_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/model/providers/lazy/faculty_locations_provider.dart'; +import 'package:uni/model/providers/lazy/home_page_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; +import 'package:uni/model/providers/lazy/restaurant_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/about/about.dart'; diff --git a/uni/lib/model/providers/bus_stop_provider.dart b/uni/lib/model/providers/lazy/bus_stop_provider.dart similarity index 98% rename from uni/lib/model/providers/bus_stop_provider.dart rename to uni/lib/model/providers/lazy/bus_stop_provider.dart index f4b126fba..9a160960b 100644 --- a/uni/lib/model/providers/bus_stop_provider.dart +++ b/uni/lib/model/providers/lazy/bus_stop_provider.dart @@ -15,6 +15,8 @@ class BusStopProvider extends StateProviderNotifier { Map _configuredBusStops = Map.identity(); DateTime _timeStamp = DateTime.now(); + BusStopProvider() : super(dependsOnSession: false); + UnmodifiableMapView get configuredBusStops => UnmodifiableMapView(_configuredBusStops); diff --git a/uni/lib/model/providers/calendar_provider.dart b/uni/lib/model/providers/lazy/calendar_provider.dart similarity index 96% rename from uni/lib/model/providers/calendar_provider.dart rename to uni/lib/model/providers/lazy/calendar_provider.dart index add1e8a07..544495198 100644 --- a/uni/lib/model/providers/calendar_provider.dart +++ b/uni/lib/model/providers/lazy/calendar_provider.dart @@ -13,6 +13,8 @@ import 'package:uni/model/request_status.dart'; class CalendarProvider extends StateProviderNotifier { List _calendar = []; + CalendarProvider() : super(dependsOnSession: true); + UnmodifiableListView get calendar => UnmodifiableListView(_calendar); diff --git a/uni/lib/model/providers/exam_provider.dart b/uni/lib/model/providers/lazy/exam_provider.dart similarity index 98% rename from uni/lib/model/providers/exam_provider.dart rename to uni/lib/model/providers/lazy/exam_provider.dart index 0f304f6f8..ec3bfed2c 100644 --- a/uni/lib/model/providers/exam_provider.dart +++ b/uni/lib/model/providers/lazy/exam_provider.dart @@ -19,6 +19,8 @@ class ExamProvider extends StateProviderNotifier { List _hiddenExams = []; Map _filteredExamsTypes = {}; + ExamProvider() : super(dependsOnSession: true); + UnmodifiableListView get exams => UnmodifiableListView(_exams); UnmodifiableListView get hiddenExams => diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/lazy/faculty_locations_provider.dart similarity index 93% rename from uni/lib/model/providers/faculty_locations_provider.dart rename to uni/lib/model/providers/lazy/faculty_locations_provider.dart index 6d9468272..fcd89108d 100644 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ b/uni/lib/model/providers/lazy/faculty_locations_provider.dart @@ -10,6 +10,8 @@ import 'package:uni/model/request_status.dart'; class FacultyLocationsProvider extends StateProviderNotifier { List _locations = []; + FacultyLocationsProvider() : super(dependsOnSession: false); + UnmodifiableListView get locations => UnmodifiableListView(_locations); diff --git a/uni/lib/model/providers/home_page_provider.dart b/uni/lib/model/providers/lazy/home_page_provider.dart similarity index 94% rename from uni/lib/model/providers/home_page_provider.dart rename to uni/lib/model/providers/lazy/home_page_provider.dart index 8fe189b80..483ce5b57 100644 --- a/uni/lib/model/providers/home_page_provider.dart +++ b/uni/lib/model/providers/lazy/home_page_provider.dart @@ -1,14 +1,17 @@ +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; -import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/utils/favorite_widget_type.dart'; class HomePageProvider extends StateProviderNotifier { List _favoriteCards = []; bool _isEditing = false; + HomePageProvider() : super(dependsOnSession: false); + List get favoriteCards => _favoriteCards.toList(); + bool get isEditing => _isEditing; @override diff --git a/uni/lib/model/providers/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart similarity index 98% rename from uni/lib/model/providers/lecture_provider.dart rename to uni/lib/model/providers/lazy/lecture_provider.dart index 177a4bb61..0d1408c4c 100644 --- a/uni/lib/model/providers/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -17,6 +17,8 @@ import 'package:uni/model/request_status.dart'; class LectureProvider extends StateProviderNotifier { List _lectures = []; + LectureProvider() : super(dependsOnSession: true); + UnmodifiableListView get lectures => UnmodifiableListView(_lectures); @override diff --git a/uni/lib/model/providers/library_occupation_provider.dart b/uni/lib/model/providers/lazy/library_occupation_provider.dart similarity index 96% rename from uni/lib/model/providers/library_occupation_provider.dart rename to uni/lib/model/providers/lazy/library_occupation_provider.dart index 6e0f58fb0..bd7d09517 100644 --- a/uni/lib/model/providers/library_occupation_provider.dart +++ b/uni/lib/model/providers/lazy/library_occupation_provider.dart @@ -12,6 +12,8 @@ import 'package:uni/model/request_status.dart'; class LibraryOccupationProvider extends StateProviderNotifier { LibraryOccupation? _occupation; + LibraryOccupationProvider() : super(dependsOnSession: true); + LibraryOccupation? get occupation => _occupation; @override diff --git a/uni/lib/model/providers/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart similarity index 96% rename from uni/lib/model/providers/restaurant_provider.dart rename to uni/lib/model/providers/lazy/restaurant_provider.dart index d6a7a7556..52b1c9a6b 100644 --- a/uni/lib/model/providers/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -13,6 +13,8 @@ import 'package:uni/model/request_status.dart'; class RestaurantProvider extends StateProviderNotifier { List _restaurants = []; + RestaurantProvider() : super(dependsOnSession: false); + UnmodifiableListView get restaurants => UnmodifiableListView(_restaurants); diff --git a/uni/lib/model/providers/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart similarity index 99% rename from uni/lib/model/providers/profile_provider.dart rename to uni/lib/model/providers/startup/profile_provider.dart index 456dcd781..a101e41db 100644 --- a/uni/lib/model/providers/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -26,6 +26,8 @@ class ProfileProvider extends StateProviderNotifier { DateTime? _feesRefreshTime; DateTime? _printRefreshTime; + ProfileProvider() : super(dependsOnSession: true); + String get feesRefreshTime => _feesRefreshTime.toString(); String get printRefreshTime => _printRefreshTime.toString(); diff --git a/uni/lib/model/providers/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart similarity index 74% rename from uni/lib/model/providers/session_provider.dart rename to uni/lib/model/providers/startup/session_provider.dart index fe334db14..296f70ccc 100644 --- a/uni/lib/model/providers/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -10,13 +10,14 @@ import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; -import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; class SessionProvider extends StateProviderNotifier { Session _session = Session(); List _faculties = []; + SessionProvider() : super(dependsOnSession: false); + Session get session => _session; UnmodifiableListView get faculties => @@ -28,14 +29,8 @@ class SessionProvider extends StateProviderNotifier { @override Future loadFromRemote(Session session, Profile profile) async {} - login(Completer action, - String username, - String password, - List faculties, - StateProviders stateProviders, - persistentSession, - usernameController, - passwordController) async { + login(Completer action, String username, String password, + List faculties, persistentSession) async { try { updateStatus(RequestStatus.busy); @@ -49,19 +44,14 @@ class SessionProvider extends StateProviderNotifier { username, password, faculties); } Future.delayed(const Duration(seconds: 20), - () => {NotificationManager().initializeNotifications()}); - - //loadLocalUserInfoToState(stateProviders, skipDatabaseLookup: true); - //await loadUserProfileInfoFromRemote(stateProviders); + () => {NotificationManager().initializeNotifications()}); - usernameController.clear(); - passwordController.clear(); await acceptTermsAndConditions(); updateStatus(RequestStatus.successful); } else { final String responseHtml = - await NetworkRouter.loginInSigarra(username, password, faculties); + await NetworkRouter.loginInSigarra(username, password, faculties); if (isPasswordExpired(responseHtml)) { action.completeError(ExpiredCredentialsException()); } else { @@ -80,22 +70,18 @@ class SessionProvider extends StateProviderNotifier { } reLogin(String username, String password, List faculties, - StateProviders stateProviders, {Completer? action}) async { try { - //loadLocalUserInfoToState(stateProviders); updateStatus(RequestStatus.busy); _session = await NetworkRouter.login(username, password, faculties, true); - //notifyListeners(); if (session.authenticated) { - //await loadUserProfileInfoFromRemote(stateProviders); Future.delayed(const Duration(seconds: 20), - () => {NotificationManager().initializeNotifications()}); + () => {NotificationManager().initializeNotifications()}); updateStatus(RequestStatus.successful); action?.complete(); } else { - failRelogin(action); + failReLogin(action); } } catch (e) { _session = Session( @@ -106,11 +92,11 @@ class SessionProvider extends StateProviderNotifier { cookies: '', persistentSession: true); - failRelogin(action); + failReLogin(action); } } - void failRelogin(Completer? action) { + void failReLogin(Completer? action) { notifyListeners(); updateStatus(RequestStatus.failed); action?.completeError(RequestStatus.failed); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 54afd3938..892b81216 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,29 +1,44 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:synchronized/synchronized.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/profile_provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { + static final Lock _lock = Lock(); RequestStatus _status = RequestStatus.none; bool _initialized = false; DateTime? _lastUpdateTime; + bool dependsOnSession; RequestStatus get status => _status; DateTime? get lastUpdateTime => _lastUpdateTime; + StateProviderNotifier({required this.dependsOnSession}); + Future _loadFromRemote(Session session, Profile profile) async { - if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - await loadFromRemote(session, profile); - _lastUpdateTime = DateTime.now(); - await AppSharedPreferences.setLastDataClassUpdateTime( - runtimeType.toString(), _lastUpdateTime!); + if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { + return; + } + + updateStatus(RequestStatus.busy); + + await loadFromRemote(session, profile); + + if (_status == RequestStatus.busy) { + // No online activity from provider + updateStatus(RequestStatus.successful); } + + _lastUpdateTime = DateTime.now(); + await AppSharedPreferences.setLastDataClassUpdateTime( + runtimeType.toString(), _lastUpdateTime!); } void updateStatus(RequestStatus status) { @@ -37,34 +52,36 @@ abstract class StateProviderNotifier extends ChangeNotifier { final profile = Provider.of(context, listen: false).profile; - updateStatus(RequestStatus.busy); _loadFromRemote(session, profile); } Future ensureInitialized(Session session, Profile profile) async { - if (_initialized) { - return; - } + await _lock.synchronized(() async { + if (_initialized) { + return; + } - _initialized = true; + _initialized = true; - _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( - runtimeType.toString()); + _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( + runtimeType.toString()); - updateStatus(RequestStatus.busy); + updateStatus(RequestStatus.busy); - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final sessionIsPersistent = - userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; - if (sessionIsPersistent) { - await loadFromStorage(); - if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { - updateStatus(RequestStatus.none); + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final sessionIsPersistent = + userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; + if (sessionIsPersistent) { + await loadFromStorage(); + if (await Connectivity().checkConnectivity() == + ConnectivityResult.none) { + updateStatus(RequestStatus.none); + } } - } - _loadFromRemote(session, profile); + await _loadFromRemote(session, profile); + }); notifyListeners(); } diff --git a/uni/lib/model/providers/state_providers.dart b/uni/lib/model/providers/state_providers.dart index 4262f541e..f93055941 100644 --- a/uni/lib/model/providers/state_providers.dart +++ b/uni/lib/model/providers/state_providers.dart @@ -1,15 +1,15 @@ import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; -import 'package:uni/model/providers/calendar_provider.dart'; -import 'package:uni/model/providers/exam_provider.dart'; -import 'package:uni/model/providers/faculty_locations_provider.dart'; -import 'package:uni/model/providers/home_page_provider.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; -import 'package:uni/model/providers/library_occupation_provider.dart'; -import 'package:uni/model/providers/profile_provider.dart'; -import 'package:uni/model/providers/restaurant_provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/calendar_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/model/providers/lazy/faculty_locations_provider.dart'; +import 'package:uni/model/providers/lazy/home_page_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; +import 'package:uni/model/providers/lazy/restaurant_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; class StateProviders { final LectureProvider lectureProvider; diff --git a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index 60677bc01..56366263c 100644 --- a/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/uni/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart'; import 'package:uni/view/bus_stop_selection/bus_stop_selection.dart'; diff --git a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart index a468aa2ad..d42df38a1 100644 --- a/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart +++ b/uni/lib/view/bus_stop_next_arrivals/widgets/estimated_arrival_timestamp.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/view/lazy_consumer.dart'; /// Manages the section with the estimated time for the bus arrival diff --git a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart index ad4e1e5ad..cc3af9b83 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/controller/local_storage/app_bus_stop_database.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/view/bus_stop_selection/widgets/bus_stop_search.dart'; import 'package:uni/view/bus_stop_selection/widgets/bus_stop_selection_row.dart'; import 'package:uni/view/common_widgets/page_title.dart'; diff --git a/uni/lib/view/bus_stop_selection/widgets/bus_stop_search.dart b/uni/lib/view/bus_stop_selection/widgets/bus_stop_search.dart index 7402800a7..86a619b67 100644 --- a/uni/lib/view/bus_stop_selection/widgets/bus_stop_search.dart +++ b/uni/lib/view/bus_stop_selection/widgets/bus_stop_search.dart @@ -6,7 +6,7 @@ import 'package:provider/provider.dart'; import 'package:uni/controller/fetchers/departures_fetcher.dart'; import 'package:uni/controller/local_storage/app_bus_stop_database.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/view/bus_stop_selection/widgets/form.dart'; /// Manages the section of the app displayed when the diff --git a/uni/lib/view/bus_stop_selection/widgets/bus_stop_selection_row.dart b/uni/lib/view/bus_stop_selection/widgets/bus_stop_selection_row.dart index 6c26e7fe8..4d09758b7 100644 --- a/uni/lib/view/bus_stop_selection/widgets/bus_stop_selection_row.dart +++ b/uni/lib/view/bus_stop_selection/widgets/bus_stop_selection_row.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/view/common_widgets/row_container.dart'; class BusStopSelectionRow extends StatefulWidget { diff --git a/uni/lib/view/bus_stop_selection/widgets/form.dart b/uni/lib/view/bus_stop_selection/widgets/form.dart index 6760dcc20..9c00f68b4 100644 --- a/uni/lib/view/bus_stop_selection/widgets/form.dart +++ b/uni/lib/view/bus_stop_selection/widgets/form.dart @@ -3,7 +3,7 @@ import 'package:provider/provider.dart'; import 'package:uni/controller/fetchers/departures_fetcher.dart'; import 'package:uni/model/entities/bus.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; class BusesForm extends StatefulWidget { final String stopCode; diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 6b341be61..64fa8caff 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; -import 'package:uni/model/providers/calendar_provider.dart'; +import 'package:uni/model/providers/lazy/calendar_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; diff --git a/uni/lib/view/common_widgets/pages_layouts/general/general.dart b/uni/lib/view/common_widgets/pages_layouts/general/general.dart index fde15635f..84325ea06 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/load_info.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart'; import 'package:uni/view/profile/profile.dart'; diff --git a/uni/lib/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart b/uni/lib/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart index cacfd953c..192ad6f43 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/theme_notifier.dart'; diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index d9be172e3..b4b3d4bd7 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/course_unit.dart'; -import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/page_title.dart'; diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 9413971dc..d2821097c 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/common_widgets/row_container.dart'; import 'package:uni/view/exams/widgets/day_title.dart'; diff --git a/uni/lib/view/exams/widgets/exam_filter_form.dart b/uni/lib/view/exams/widgets/exam_filter_form.dart index 766092afa..613cadecf 100644 --- a/uni/lib/view/exams/widgets/exam_filter_form.dart +++ b/uni/lib/view/exams/widgets/exam_filter_form.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; class ExamFilterForm extends StatefulWidget { final Map filteredExamsTypes; diff --git a/uni/lib/view/exams/widgets/exam_filter_menu.dart b/uni/lib/view/exams/widgets/exam_filter_menu.dart index bf747379a..0576ebe67 100644 --- a/uni/lib/view/exams/widgets/exam_filter_menu.dart +++ b/uni/lib/view/exams/widgets/exam_filter_menu.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/widgets/exam_filter_form.dart'; class ExamFilterMenu extends StatefulWidget { diff --git a/uni/lib/view/exams/widgets/exam_row.dart b/uni/lib/view/exams/widgets/exam_row.dart index 21fbc1347..ca3c13483 100644 --- a/uni/lib/view/exams/widgets/exam_row.dart +++ b/uni/lib/view/exams/widgets/exam_row.dart @@ -1,13 +1,13 @@ import 'dart:async'; +import 'package:add_2_calendar/add_2_calendar.dart'; import 'package:flutter/material.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; -import 'package:uni/view/exams/widgets/exam_title.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/widgets/exam_time.dart'; -import 'package:add_2_calendar/add_2_calendar.dart'; -import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:uni/view/exams/widgets/exam_title.dart'; class ExamRow extends StatefulWidget { final Exam exam; diff --git a/uni/lib/view/home/home.dart b/uni/lib/view/home/home.dart index b2f173e12..6a0c93a78 100644 --- a/uni/lib/view/home/home.dart +++ b/uni/lib/view/home/home.dart @@ -1,17 +1,16 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; -import 'package:uni/model/providers/exam_provider.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; -import 'package:uni/model/providers/library_occupation_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/model/providers/lazy/home_page_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/utils/favorite_widget_type.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/home/widgets/main_cards_list.dart'; -import '../../model/providers/home_page_provider.dart'; -import '../../model/providers/profile_provider.dart'; - class HomePageView extends StatefulWidget { const HomePageView({super.key}); diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index 7097b8e7f..0f981093d 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/bus_stop.dart'; -import 'package:uni/model/providers/bus_stop_provider.dart'; +import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart'; diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 9b2285100..92c10ba38 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index 11510c610..bf4156ae9 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; -import 'package:uni/model/providers/home_page_provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/lazy/home_page_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/utils/favorite_widget_type.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 34c892dcc..39c440043 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/restaurant_provider.dart'; +import 'package:uni/model/providers/lazy/restaurant_provider.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index 414d1c9e9..d0f066ec8 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index bcde3ae1f..bc3cd460a 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -1,14 +1,14 @@ import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/profile_provider.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; /// Wrapper around Consumer that ensures that the provider is initialized, /// meaning that it has loaded its data from storage and/or remote. /// The provider will not reload its data if it has already been loaded before. -/// There should be a SessionProvider and a ProfileProvider above this widget in -/// the widget tree to initialize the provider data the first time. +/// If the provider depends on the session, it will ensure that SessionProvider +/// and ProfileProvider are initialized before initializing itself. class LazyConsumer extends StatelessWidget { final Widget Function(BuildContext, T) builder; @@ -23,12 +23,19 @@ class LazyConsumer extends StatelessWidget { final sessionProvider = Provider.of(context); final profileProvider = Provider.of(context); - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { final session = sessionProvider.session; final profile = profileProvider.profile; - profileProvider.ensureInitialized(session, profile).then((value) => - Provider.of(context, listen: false) - .ensureInitialized(session, profile)); + final provider = Provider.of(context, listen: false); + + if (provider.dependsOnSession) { + sessionProvider.ensureInitialized(session, profile).then((_) => + profileProvider + .ensureInitialized(session, profile) + .then((_) => provider.ensureInitialized(session, profile))); + } else { + provider.ensureInitialized(session, profile); + } }); } catch (_) { // The provider won't be initialized diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index 9025266e8..c9581b9ef 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/library_occupation.dart'; -import 'package:uni/model/providers/library_occupation_provider.dart'; +import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/lazy_consumer.dart'; diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index d4e9c6027..b4af4b85f 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/percent_indicator.dart'; -import 'package:uni/model/providers/library_occupation_provider.dart'; +import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index 956c636be..a64ff5f6a 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:uni/model/entities/location_group.dart'; -import 'package:uni/model/providers/faculty_locations_provider.dart'; +import 'package:uni/model/providers/lazy/faculty_locations_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index f0395c19f..848247506 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/login_exceptions.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -54,8 +54,7 @@ class LoginPageViewState extends State { final pass = passwordController.text.trim(); final completer = Completer(); - sessionProvider.login(completer, user, pass, faculties, stateProviders, - _keepSignedIn, usernameController, passwordController); + sessionProvider.login(completer, user, pass, faculties, _keepSignedIn); completer.future.then((_) { handleLogin(sessionProvider.status, context); diff --git a/uni/lib/view/profile/profile.dart b/uni/lib/view/profile/profile.dart index 97bff9f00..8770b82b1 100644 --- a/uni/lib/view/profile/profile.dart +++ b/uni/lib/view/profile/profile.dart @@ -1,7 +1,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/account_info_card.dart'; diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index c759692b9..018ce766d 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/tuition_notification_switch.dart'; diff --git a/uni/lib/view/profile/widgets/create_print_mb_dialog.dart b/uni/lib/view/profile/widgets/create_print_mb_dialog.dart index c88dd2acb..5ce0adf4b 100644 --- a/uni/lib/view/profile/widgets/create_print_mb_dialog.dart +++ b/uni/lib/view/profile/widgets/create_print_mb_dialog.dart @@ -2,7 +2,7 @@ import 'package:currency_text_input_formatter/currency_text_input_formatter.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/fetchers/print_fetcher.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; Future addMoneyDialog(BuildContext context) async { diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index 0ae056c15..bb41169b5 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/model/providers/profile_provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/profile/widgets/create_print_mb_dialog.dart'; diff --git a/uni/lib/view/profile/widgets/profile_overview.dart b/uni/lib/view/profile/widgets/profile_overview.dart index f59f30574..a41d5415d 100644 --- a/uni/lib/view/profile/widgets/profile_overview.dart +++ b/uni/lib/view/profile/widgets/profile_overview.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/load_info.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/providers/session_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; class ProfileOverview extends StatelessWidget { final Profile profile; diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index b568a82a6..f72d0de0f 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; -import 'package:uni/model/providers/restaurant_provider.dart'; +import 'package:uni/model/providers/lazy/restaurant_provider.dart'; import 'package:uni/model/utils/day_of_week.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 0831d96d0..1cc4b9d65 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/page_title.dart'; diff --git a/uni/lib/view/splash/splash.dart b/uni/lib/view/splash/splash.dart index 130b469fd..5b0ad0d22 100644 --- a/uni/lib/view/splash/splash.dart +++ b/uni/lib/view/splash/splash.dart @@ -132,7 +132,7 @@ class SplashScreenState extends State { final List faculties = await AppSharedPreferences.getUserFaculties(); await stateProviders.sessionProvider - .reLogin(userName, password, faculties, stateProviders); + .reLogin(userName, password, faculties); } return MaterialPageRoute(builder: (context) => const HomePageView()); diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index f3d83b34d..74ca18090 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -16,7 +16,7 @@ import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/exams.dart'; import '../../test_widget.dart'; diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index d4ffa5e8c..7451d4b49 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -14,7 +14,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/view/schedule/schedule.dart'; import '../../test_widget.dart'; diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index ad0b4964a..1050ea09e 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -11,7 +11,7 @@ import 'package:uni/model/entities/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/request_status.dart'; import 'mocks.dart'; diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index e9dcee38f..212e68767 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -10,7 +10,7 @@ import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/providers/lecture_provider.dart'; +import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; import 'mocks.dart'; diff --git a/uni/test/unit/view/Pages/exams_page_view_test.dart b/uni/test/unit/view/Pages/exams_page_view_test.dart index 5e3a8af34..5cfbc1040 100644 --- a/uni/test/unit/view/Pages/exams_page_view_test.dart +++ b/uni/test/unit/view/Pages/exams_page_view_test.dart @@ -2,9 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; - import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/exams.dart'; import '../../../test_widget.dart'; @@ -17,16 +16,13 @@ void main() { const firstExamDate = '2019-09-11'; const secondExamSubject = 'SDIS'; const secondExamDate = '2019-09-12'; - - testWidgets('When given an empty list', (WidgetTester tester) async { + testWidgets('When given an empty list', (WidgetTester tester) async { const widget = ExamsPageView(); final examProvider = ExamProvider(); examProvider.setExams([]); - final providers = [ - ChangeNotifierProvider(create: (_) => examProvider) - ]; + final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); @@ -34,19 +30,17 @@ void main() { }); testWidgets('When given a single exam', (WidgetTester tester) async { - final DateTime firstExamBegin = DateTime.parse('$firstExamDate 09:00'); + final DateTime firstExamBegin = DateTime.parse('$firstExamDate 09:00'); final DateTime firstExamEnd = DateTime.parse('$firstExamDate 12:00'); - final firstExam = Exam('1230',firstExamBegin, firstExamEnd, firstExamSubject, - ['B119', 'B107', 'B205'], 'ER','feup'); + final firstExam = Exam('1230', firstExamBegin, firstExamEnd, + firstExamSubject, ['B119', 'B107', 'B205'], 'ER', 'feup'); const widget = ExamsPageView(); final examProvider = ExamProvider(); examProvider.setExams([firstExam]); - final providers = [ - ChangeNotifierProvider(create: (_) => examProvider) - ]; + final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); @@ -58,12 +52,12 @@ void main() { (WidgetTester tester) async { final DateTime firstExamBegin = DateTime.parse('$firstExamDate 09:00'); final DateTime firstExamEnd = DateTime.parse('$firstExamDate 12:00'); - final firstExam = Exam('1231',firstExamBegin, firstExamEnd, firstExamSubject, - ['B119', 'B107', 'B205'], 'ER', 'feup'); + final firstExam = Exam('1231', firstExamBegin, firstExamEnd, + firstExamSubject, ['B119', 'B107', 'B205'], 'ER', 'feup'); final DateTime secondExamBegin = DateTime.parse('$firstExamDate 12:00'); final DateTime secondExamEnd = DateTime.parse('$firstExamDate 15:00'); - final secondExam = Exam('1232',secondExamBegin, secondExamEnd, secondExamSubject, - ['B119', 'B107', 'B205'], 'ER', 'feup'); + final secondExam = Exam('1232', secondExamBegin, secondExamEnd, + secondExamSubject, ['B119', 'B107', 'B205'], 'ER', 'feup'); final examList = [ firstExam, @@ -75,9 +69,7 @@ void main() { final examProvider = ExamProvider(); examProvider.setExams(examList); - final providers = [ - ChangeNotifierProvider(create: (_) => examProvider) - ]; + final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); @@ -91,12 +83,12 @@ void main() { (WidgetTester tester) async { final DateTime firstExamBegin = DateTime.parse('$firstExamDate 09:00'); final DateTime firstExamEnd = DateTime.parse('$firstExamDate 12:00'); - final firstExam = Exam('1233',firstExamBegin, firstExamEnd, firstExamSubject, - ['B119', 'B107', 'B205'], 'ER','feup'); + final firstExam = Exam('1233', firstExamBegin, firstExamEnd, + firstExamSubject, ['B119', 'B107', 'B205'], 'ER', 'feup'); final DateTime secondExamBegin = DateTime.parse('$secondExamDate 12:00'); final DateTime secondExamEnd = DateTime.parse('$secondExamDate 15:00'); - final secondExam = Exam('1234',secondExamBegin, secondExamEnd, secondExamSubject, - ['B119', 'B107', 'B205'], 'ER','feup'); + final secondExam = Exam('1234', secondExamBegin, secondExamEnd, + secondExamSubject, ['B119', 'B107', 'B205'], 'ER', 'feup'); final examList = [ firstExam, secondExam, @@ -107,9 +99,7 @@ void main() { final examProvider = ExamProvider(); examProvider.setExams(examList); - final providers = [ - ChangeNotifierProvider(create: (_) => examProvider) - ]; + final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); expect(find.byKey(Key(firstExam.toString())), findsOneWidget); @@ -123,20 +113,20 @@ void main() { final List rooms = ['B119', 'B107', 'B205']; final DateTime firstExamBegin = DateTime.parse('$firstExamDate 09:00'); final DateTime firstExamEnd = DateTime.parse('$firstExamDate 12:00'); - final firstExam = Exam('1235',firstExamBegin, firstExamEnd, firstExamSubject, - rooms, 'ER', 'feup'); + final firstExam = Exam('1235', firstExamBegin, firstExamEnd, + firstExamSubject, rooms, 'ER', 'feup'); final DateTime secondExamBegin = DateTime.parse('$firstExamDate 10:00'); final DateTime secondExamEnd = DateTime.parse('$firstExamDate 12:00'); - final secondExam = Exam('1236',secondExamBegin, secondExamEnd, firstExamSubject, - rooms, 'ER', 'feup'); + final secondExam = Exam('1236', secondExamBegin, secondExamEnd, + firstExamSubject, rooms, 'ER', 'feup'); final DateTime thirdExamBegin = DateTime.parse('$secondExamDate 12:00'); final DateTime thirdExamEnd = DateTime.parse('$secondExamDate 15:00'); - final thirdExam = Exam('1237',thirdExamBegin, thirdExamEnd, secondExamSubject, - rooms, 'ER', 'feup'); + final thirdExam = Exam('1237', thirdExamBegin, thirdExamEnd, + secondExamSubject, rooms, 'ER', 'feup'); final DateTime fourthExamBegin = DateTime.parse('$secondExamDate 13:00'); final DateTime fourthExamEnd = DateTime.parse('$secondExamDate 14:00'); - final fourthExam = Exam('1238',fourthExamBegin, fourthExamEnd, secondExamSubject, - rooms, 'ER', 'feup'); + final fourthExam = Exam('1238', fourthExamBegin, fourthExamEnd, + secondExamSubject, rooms, 'ER', 'feup'); final examList = [firstExam, secondExam, thirdExam, fourthExam]; const widget = ExamsPageView(); @@ -149,9 +139,7 @@ void main() { final secondDayKey = [thirdExam, fourthExam].map((ex) => ex.toString()).join(); - final providers = [ - ChangeNotifierProvider(create: (_) => examProvider) - ]; + final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); expect(find.byKey(Key(firstDayKey)), findsOneWidget); diff --git a/uni/test/unit/view/Widgets/exam_row_test.dart b/uni/test/unit/view/Widgets/exam_row_test.dart index 79dbe3a24..62459a32f 100644 --- a/uni/test/unit/view/Widgets/exam_row_test.dart +++ b/uni/test/unit/view/Widgets/exam_row_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/model/providers/exam_provider.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/widgets/exam_row.dart'; import '../../../test_widget.dart'; @@ -37,7 +37,7 @@ void main() { testWidgets('When multiple rooms', (WidgetTester tester) async { final rooms = ['B315', 'B316', 'B330']; - final Exam exam = Exam('1230',begin, end, subject, rooms, '', 'feup'); + final Exam exam = Exam('1230', begin, end, subject, rooms, '', 'feup'); final widget = ExamRow(exam: exam, teacher: '', mainPage: true); final providers = [ From c7c6854cbda38dde0ef6b15849ea79395c2f10b7 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 10 Jul 2023 15:21:09 +0100 Subject: [PATCH 14/21] Refine request status logic --- .../providers/startup/profile_provider.dart | 24 ++++---- .../providers/state_provider_notifier.dart | 57 +++++++++---------- uni/lib/view/course_units/course_units.dart | 9 ++- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index a101e41db..dd7d42b81 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -36,6 +36,7 @@ class ProfileProvider extends StateProviderNotifier { @override Future loadFromStorage() async { + await loadProfile(); await Future.wait( [loadCourses(), loadBalanceRefreshTimes(), loadCourseUnits()]); } @@ -62,20 +63,21 @@ class ProfileProvider extends StateProviderNotifier { ]); } - Future loadCourses() async { + Future loadProfile() async { final profileDb = AppUserDataDatabase(); _profile = await profileDb.getUserData(); + } + Future loadCourses() async { final AppCoursesDatabase coursesDb = AppCoursesDatabase(); final List courses = await coursesDb.courses(); - _profile.courses = courses; } Future loadBalanceRefreshTimes() async { final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); final Map refreshTimes = - await refreshTimesDb.refreshTimes(); + await refreshTimesDb.refreshTimes(); final printRefreshTime = refreshTimes['print']; final feesRefreshTime = refreshTimes['fees']; @@ -101,7 +103,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('fees', currentTime.toString()); @@ -130,7 +132,7 @@ class ProfileProvider extends StateProviderNotifier { Future storeRefreshTime(String db, String currentTime) async { final AppRefreshTimesDatabase refreshTimesDatabase = - AppRefreshTimesDatabase(); + AppRefreshTimesDatabase(); refreshTimesDatabase.saveRefreshTime(db, currentTime); } @@ -141,7 +143,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('print', currentTime.toString()); @@ -174,7 +176,7 @@ class ProfileProvider extends StateProviderNotifier { final profile = await ProfileFetcher.getProfile(session); final currentCourseUnits = - await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); + await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); _profile = profile; _profile.courseUnits = currentCourseUnits; @@ -182,7 +184,7 @@ class ProfileProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final profileDb = AppUserDataDatabase(); profileDb.insertUserData(_profile); @@ -195,8 +197,8 @@ class ProfileProvider extends StateProviderNotifier { action.complete(); } - fetchCourseUnitsAndCourseAverages( - Session session, Completer action) async { + fetchCourseUnitsAndCourseAverages(Session session, + Completer action) async { updateStatus(RequestStatus.busy); try { final List courses = profile.courses; @@ -206,7 +208,7 @@ class ProfileProvider extends StateProviderNotifier { _profile.courseUnits = allCourseUnits; final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final AppCoursesDatabase coursesDb = AppCoursesDatabase(); await coursesDb.saveNewCourses(courses); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 892b81216..ecf5594f6 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -11,7 +11,7 @@ import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { static final Lock _lock = Lock(); - RequestStatus _status = RequestStatus.none; + RequestStatus _status = RequestStatus.busy; bool _initialized = false; DateTime? _lastUpdateTime; bool dependsOnSession; @@ -22,23 +22,36 @@ abstract class StateProviderNotifier extends ChangeNotifier { StateProviderNotifier({required this.dependsOnSession}); - Future _loadFromRemote(Session session, Profile profile) async { - if (await Connectivity().checkConnectivity() == ConnectivityResult.none) { - return; - } + Future _loadFromStorage() async { + _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( + runtimeType.toString()); - updateStatus(RequestStatus.busy); + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final sessionIsPersistent = + userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; + if (sessionIsPersistent) { + await loadFromStorage(); + } + } - await loadFromRemote(session, profile); + Future _loadFromRemote(Session session, Profile profile) async { + final bool hasConnectivity = + await Connectivity().checkConnectivity() != ConnectivityResult.none; + if (hasConnectivity) { + updateStatus(RequestStatus.busy); + await loadFromRemote(session, profile); + } - if (_status == RequestStatus.busy) { + if (!hasConnectivity || _status == RequestStatus.busy) { // No online activity from provider updateStatus(RequestStatus.successful); + } else { + _lastUpdateTime = DateTime.now(); + await AppSharedPreferences.setLastDataClassUpdateTime( + runtimeType.toString(), _lastUpdateTime!); + notifyListeners(); } - - _lastUpdateTime = DateTime.now(); - await AppSharedPreferences.setLastDataClassUpdateTime( - runtimeType.toString(), _lastUpdateTime!); } void updateStatus(RequestStatus status) { @@ -63,27 +76,9 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initialized = true; - _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( - runtimeType.toString()); - - updateStatus(RequestStatus.busy); - - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final sessionIsPersistent = - userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; - if (sessionIsPersistent) { - await loadFromStorage(); - if (await Connectivity().checkConnectivity() == - ConnectivityResult.none) { - updateStatus(RequestStatus.none); - } - } - + await _loadFromStorage(); await _loadFromRemote(session, profile); }); - - notifyListeners(); } Future loadFromStorage(); diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index b4b3d4bd7..165787618 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -33,6 +33,7 @@ class CourseUnitsPageViewState final List courseUnits = profileProvider.profile.courseUnits; List availableYears = []; List availableSemesters = []; + if (courseUnits.isNotEmpty) { availableYears = _getAvailableYears(courseUnits); if (availableYears.isNotEmpty && selectedSchoolYear == null) { @@ -52,12 +53,10 @@ class CourseUnitsPageViewState ? availableSemesters[0] : availableSemesters[1]; } - - return _getPageView(courseUnits, profileProvider.status, availableYears, - availableSemesters); - } else { - return _getPageView([], profileProvider.status, [], []); } + + return _getPageView(courseUnits, profileProvider.status, availableYears, + availableSemesters); }); } diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index 1050ea09e..fb94541a9 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -59,7 +59,7 @@ void main() { setUp(() { provider = ExamProvider(); - expect(provider.status, RequestStatus.none); + expect(provider.status, RequestStatus.busy); }); test('When given one exam', () async { diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index 212e68767..d05496119 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -39,7 +39,7 @@ void main() { LectureProvider provider; setUp(() { provider = LectureProvider(); - expect(provider.status, RequestStatus.none); + expect(provider.status, RequestStatus.busy); }); test('When given a single schedule', () async { From 5fa3a75270bc0d921e4c211e1e9b6ab5c13d8138 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 10 Jul 2023 15:29:05 +0100 Subject: [PATCH 15/21] Delete load info file --- uni/lib/controller/load_info.dart | 16 --------- .../providers/startup/profile_provider.dart | 34 ++++++++++++++----- .../pages_layouts/general/general.dart | 11 +++--- .../profile/widgets/profile_overview.dart | 5 +-- 4 files changed, 34 insertions(+), 32 deletions(-) delete mode 100644 uni/lib/controller/load_info.dart diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart deleted file mode 100644 index 92fe751c4..000000000 --- a/uni/lib/controller/load_info.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:uni/controller/local_storage/file_offline_storage.dart'; -import 'package:uni/model/entities/session.dart'; - -Future loadProfilePicture(Session session, {forceRetrieval = false}) { - final String studentNumber = session.studentNumber; - final String faculty = session.faculties[0]; - final String url = - 'https://sigarra.up.pt/$faculty/pt/fotografias_service.foto?pct_cod=$studentNumber'; - final Map headers = {}; - headers['cookie'] = session.cookies; - return loadFileFromStorageOrRetrieveNew('user_profile_picture', url, headers, - forceRetrieval: forceRetrieval); -} diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index dd7d42b81..bcb7f1984 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:logger/logger.dart'; import 'package:tuple/tuple.dart'; @@ -21,6 +22,8 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; +import '../../../controller/local_storage/file_offline_storage.dart'; + class ProfileProvider extends StateProviderNotifier { Profile _profile = Profile(); DateTime? _feesRefreshTime; @@ -77,7 +80,7 @@ class ProfileProvider extends StateProviderNotifier { Future loadBalanceRefreshTimes() async { final AppRefreshTimesDatabase refreshTimesDb = AppRefreshTimesDatabase(); final Map refreshTimes = - await refreshTimesDb.refreshTimes(); + await refreshTimesDb.refreshTimes(); final printRefreshTime = refreshTimes['print']; final feesRefreshTime = refreshTimes['fees']; @@ -103,7 +106,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('fees', currentTime.toString()); @@ -132,7 +135,7 @@ class ProfileProvider extends StateProviderNotifier { Future storeRefreshTime(String db, String currentTime) async { final AppRefreshTimesDatabase refreshTimesDatabase = - AppRefreshTimesDatabase(); + AppRefreshTimesDatabase(); refreshTimesDatabase.saveRefreshTime(db, currentTime); } @@ -143,7 +146,7 @@ class ProfileProvider extends StateProviderNotifier { final DateTime currentTime = DateTime.now(); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { await storeRefreshTime('print', currentTime.toString()); @@ -176,7 +179,7 @@ class ProfileProvider extends StateProviderNotifier { final profile = await ProfileFetcher.getProfile(session); final currentCourseUnits = - await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); + await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); _profile = profile; _profile.courseUnits = currentCourseUnits; @@ -184,7 +187,7 @@ class ProfileProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final profileDb = AppUserDataDatabase(); profileDb.insertUserData(_profile); @@ -197,8 +200,8 @@ class ProfileProvider extends StateProviderNotifier { action.complete(); } - fetchCourseUnitsAndCourseAverages(Session session, - Completer action) async { + fetchCourseUnitsAndCourseAverages( + Session session, Completer action) async { updateStatus(RequestStatus.busy); try { final List courses = profile.courses; @@ -208,7 +211,7 @@ class ProfileProvider extends StateProviderNotifier { _profile.courseUnits = allCourseUnits; final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { final AppCoursesDatabase coursesDb = AppCoursesDatabase(); await coursesDb.saveNewCourses(courses); @@ -223,4 +226,17 @@ class ProfileProvider extends StateProviderNotifier { action.complete(); } + + static Future fetchOrGetCachedProfilePicture(Session session, + {forceRetrieval = false}) { + final String studentNumber = session.studentNumber; + final String faculty = session.faculties[0]; + final String url = + 'https://sigarra.up.pt/$faculty/pt/fotografias_service.foto?pct_cod=$studentNumber'; + final Map headers = {}; + headers['cookie'] = session.cookies; + return loadFileFromStorageOrRetrieveNew( + 'user_profile_picture', url, headers, + forceRetrieval: forceRetrieval); + } } diff --git a/uni/lib/view/common_widgets/pages_layouts/general/general.dart b/uni/lib/view/common_widgets/pages_layouts/general/general.dart index 84325ea06..9ebaac4bf 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; -import 'package:uni/controller/load_info.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/widgets/navigation_drawer.dart'; @@ -28,9 +28,10 @@ abstract class GeneralPageViewState extends State { Future buildProfileDecorationImage(context, {forceRetrieval = false}) async { - final profilePictureFile = await loadProfilePicture( - Provider.of(context, listen: false).session, - forceRetrieval: forceRetrieval || profileImageProvider == null); + final profilePictureFile = + await ProfileProvider.fetchOrGetCachedProfilePicture( + Provider.of(context, listen: false).session, + forceRetrieval: forceRetrieval || profileImageProvider == null); return getProfileDecorationImage(profilePictureFile); } @@ -53,7 +54,7 @@ abstract class GeneralPageViewState extends State { Widget refreshState(BuildContext context, Widget child) { return RefreshIndicator( key: GlobalKey(), - onRefresh: () => loadProfilePicture( + onRefresh: () => ProfileProvider.fetchOrGetCachedProfilePicture( Provider.of(context, listen: false).session, forceRetrieval: true) .then((value) => handleRefresh(context)), diff --git a/uni/lib/view/profile/widgets/profile_overview.dart b/uni/lib/view/profile/widgets/profile_overview.dart index a41d5415d..5382f7006 100644 --- a/uni/lib/view/profile/widgets/profile_overview.dart +++ b/uni/lib/view/profile/widgets/profile_overview.dart @@ -2,8 +2,8 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/controller/load_info.dart'; import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; class ProfileOverview extends StatelessWidget { @@ -21,7 +21,8 @@ class ProfileOverview extends StatelessWidget { return Consumer( builder: (context, sessionProvider, _) { return FutureBuilder( - future: loadProfilePicture(sessionProvider.session), + future: ProfileProvider.fetchOrGetCachedProfilePicture( + sessionProvider.session), builder: (BuildContext context, AsyncSnapshot profilePic) => Column( mainAxisAlignment: MainAxisAlignment.center, From 1d13aa335b357b7493ee6f636390f277553dc064 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 10 Jul 2023 15:40:44 +0100 Subject: [PATCH 16/21] Delete onstartup file --- .../controller/networking/network_router.dart | 16 +++++++--------- uni/lib/controller/on_start_up.dart | 18 ------------------ uni/lib/main.dart | 2 -- .../providers/startup/profile_provider.dart | 3 +-- .../providers/startup/session_provider.dart | 14 +++++++------- 5 files changed, 15 insertions(+), 38 deletions(-) delete mode 100644 uni/lib/controller/on_start_up.dart diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index c6bba5b61..f92b85e7b 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -7,6 +7,7 @@ import 'package:logger/logger.dart'; import 'package:synchronized/synchronized.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/session.dart'; +import 'package:uni/view/navigation_service.dart'; extension UriString on String { /// Converts a [String] to an [Uri]. @@ -16,13 +17,9 @@ extension UriString on String { /// Manages the networking of the app. class NetworkRouter { static http.Client? httpClient; - static const int loginRequestTimeout = 20; - static Lock loginLock = Lock(); - static Function onReloginFail = () {}; - /// Creates an authenticated [Session] on the given [faculty] with the /// given username [user] and password [pass]. static Future login(String user, String pass, List faculties, @@ -52,7 +49,7 @@ class NetworkRouter { } /// Determines if a re-login with the [session] is possible. - static Future relogin(Session session) { + static Future reLogin(Session session) { return loginLock.synchronized(() async { if (!session.persistentSession) { return false; @@ -94,10 +91,11 @@ class NetworkRouter { /// Returns the response body of the login in Sigarra /// given username [user] and password [pass]. - static Future loginInSigarra(String user, String pass, List faculties) async { + static Future loginInSigarra( + String user, String pass, List faculties) async { final String url = '${NetworkRouter.getBaseUrls(faculties)[0]}vld_validacao.validacao'; - + final response = await http.post(url.toUri(), body: { 'p_user': user, 'p_pass': pass @@ -149,12 +147,12 @@ class NetworkRouter { return response; } else if (response.statusCode == 403 && !(await userLoggedIn(session))) { // HTTP403 - Forbidden - final bool reLoginSuccessful = await relogin(session); + final bool reLoginSuccessful = await reLogin(session); if (reLoginSuccessful) { headers['cookie'] = session.cookies; return http.get(url.toUri(), headers: headers); } else { - onReloginFail(); + NavigationService.logout(); Logger().e('Login failed'); return Future.error('Login failed'); } diff --git a/uni/lib/controller/on_start_up.dart b/uni/lib/controller/on_start_up.dart deleted file mode 100644 index f51e5a032..000000000 --- a/uni/lib/controller/on_start_up.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/providers/startup/session_provider.dart'; -import 'package:uni/view/navigation_service.dart'; - -class OnStartUp { - static onStart(SessionProvider sessionProvider) { - setHandleReloginFail(sessionProvider); - } - - static setHandleReloginFail(SessionProvider sessionProvider) { - NetworkRouter.onReloginFail = () { - if (!sessionProvider.session.persistentSession) { - return NavigationService.logout(); - } - return Future.value(); - }; - } -} diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 3b5039fe7..03248f59f 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -7,7 +7,6 @@ import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/controller/background_workers/background_callback.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; -import 'package:uni/controller/on_start_up.dart'; import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; @@ -57,7 +56,6 @@ Future main() async { FacultyLocationsProvider(), HomePageProvider()); - OnStartUp.onStart(stateProviders.sessionProvider); WidgetsFlutterBinding.ensureInitialized(); await Workmanager().initialize(workerStartCallback, diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index bcb7f1984..f2e48e0dd 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -13,6 +13,7 @@ import 'package:uni/controller/local_storage/app_courses_database.dart'; import 'package:uni/controller/local_storage/app_refresh_times_database.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/local_storage/app_user_database.dart'; +import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; import 'package:uni/model/entities/course.dart'; @@ -22,8 +23,6 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; -import '../../../controller/local_storage/file_offline_storage.dart'; - class ProfileProvider extends StateProviderNotifier { Profile _profile = Profile(); DateTime? _feesRefreshTime; diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 296f70ccc..b860c267e 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -11,6 +11,7 @@ import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/view/navigation_service.dart'; class SessionProvider extends StateProviderNotifier { Session _session = Session(); @@ -47,7 +48,6 @@ class SessionProvider extends StateProviderNotifier { () => {NotificationManager().initializeNotifications()}); await acceptTermsAndConditions(); - updateStatus(RequestStatus.successful); } else { final String responseHtml = @@ -81,7 +81,7 @@ class SessionProvider extends StateProviderNotifier { updateStatus(RequestStatus.successful); action?.complete(); } else { - failReLogin(action); + handleFailedReLogin(action); } } catch (e) { _session = Session( @@ -92,14 +92,14 @@ class SessionProvider extends StateProviderNotifier { cookies: '', persistentSession: true); - failReLogin(action); + handleFailedReLogin(action); } } - void failReLogin(Completer? action) { - notifyListeners(); - updateStatus(RequestStatus.failed); + handleFailedReLogin(Completer? action) { action?.completeError(RequestStatus.failed); - NetworkRouter.onReloginFail(); + if (!session.persistentSession) { + return NavigationService.logout(); + } } } From a231d078f01b305042c001e3e653582ed23f3c81 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 10 Jul 2023 16:35:23 +0100 Subject: [PATCH 17/21] Add provider caching --- .../providers/lazy/bus_stop_provider.dart | 2 +- .../providers/lazy/calendar_provider.dart | 3 +- .../model/providers/lazy/exam_provider.dart | 3 +- .../lazy/faculty_locations_provider.dart | 3 +- .../providers/lazy/home_page_provider.dart | 2 +- .../providers/lazy/lecture_provider.dart | 3 +- .../lazy/library_occupation_provider.dart | 3 +- .../providers/lazy/restaurant_provider.dart | 3 +- .../providers/startup/profile_provider.dart | 3 +- .../providers/startup/session_provider.dart | 6 ++- .../providers/state_provider_notifier.dart | 45 +++++++++++++++---- 11 files changed, 58 insertions(+), 18 deletions(-) diff --git a/uni/lib/model/providers/lazy/bus_stop_provider.dart b/uni/lib/model/providers/lazy/bus_stop_provider.dart index 9a160960b..628e9dc9d 100644 --- a/uni/lib/model/providers/lazy/bus_stop_provider.dart +++ b/uni/lib/model/providers/lazy/bus_stop_provider.dart @@ -15,7 +15,7 @@ class BusStopProvider extends StateProviderNotifier { Map _configuredBusStops = Map.identity(); DateTime _timeStamp = DateTime.now(); - BusStopProvider() : super(dependsOnSession: false); + BusStopProvider() : super(dependsOnSession: false, cacheDuration: null); UnmodifiableMapView get configuredBusStops => UnmodifiableMapView(_configuredBusStops); diff --git a/uni/lib/model/providers/lazy/calendar_provider.dart b/uni/lib/model/providers/lazy/calendar_provider.dart index 544495198..1a204c7d8 100644 --- a/uni/lib/model/providers/lazy/calendar_provider.dart +++ b/uni/lib/model/providers/lazy/calendar_provider.dart @@ -13,7 +13,8 @@ import 'package:uni/model/request_status.dart'; class CalendarProvider extends StateProviderNotifier { List _calendar = []; - CalendarProvider() : super(dependsOnSession: true); + CalendarProvider() + : super(dependsOnSession: true, cacheDuration: const Duration(days: 30)); UnmodifiableListView get calendar => UnmodifiableListView(_calendar); diff --git a/uni/lib/model/providers/lazy/exam_provider.dart b/uni/lib/model/providers/lazy/exam_provider.dart index ec3bfed2c..9b8ae4532 100644 --- a/uni/lib/model/providers/lazy/exam_provider.dart +++ b/uni/lib/model/providers/lazy/exam_provider.dart @@ -19,7 +19,8 @@ class ExamProvider extends StateProviderNotifier { List _hiddenExams = []; Map _filteredExamsTypes = {}; - ExamProvider() : super(dependsOnSession: true); + ExamProvider() + : super(dependsOnSession: true, cacheDuration: const Duration(days: 1)); UnmodifiableListView get exams => UnmodifiableListView(_exams); diff --git a/uni/lib/model/providers/lazy/faculty_locations_provider.dart b/uni/lib/model/providers/lazy/faculty_locations_provider.dart index fcd89108d..c0f7a57c7 100644 --- a/uni/lib/model/providers/lazy/faculty_locations_provider.dart +++ b/uni/lib/model/providers/lazy/faculty_locations_provider.dart @@ -10,7 +10,8 @@ import 'package:uni/model/request_status.dart'; class FacultyLocationsProvider extends StateProviderNotifier { List _locations = []; - FacultyLocationsProvider() : super(dependsOnSession: false); + FacultyLocationsProvider() + : super(dependsOnSession: false, cacheDuration: const Duration(days: 30)); UnmodifiableListView get locations => UnmodifiableListView(_locations); diff --git a/uni/lib/model/providers/lazy/home_page_provider.dart b/uni/lib/model/providers/lazy/home_page_provider.dart index 483ce5b57..cd5e21247 100644 --- a/uni/lib/model/providers/lazy/home_page_provider.dart +++ b/uni/lib/model/providers/lazy/home_page_provider.dart @@ -8,7 +8,7 @@ class HomePageProvider extends StateProviderNotifier { List _favoriteCards = []; bool _isEditing = false; - HomePageProvider() : super(dependsOnSession: false); + HomePageProvider() : super(dependsOnSession: false, cacheDuration: null); List get favoriteCards => _favoriteCards.toList(); diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index 0d1408c4c..80f2bfd07 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -17,7 +17,8 @@ import 'package:uni/model/request_status.dart'; class LectureProvider extends StateProviderNotifier { List _lectures = []; - LectureProvider() : super(dependsOnSession: true); + LectureProvider() + : super(dependsOnSession: true, cacheDuration: const Duration(hours: 6)); UnmodifiableListView get lectures => UnmodifiableListView(_lectures); diff --git a/uni/lib/model/providers/lazy/library_occupation_provider.dart b/uni/lib/model/providers/lazy/library_occupation_provider.dart index bd7d09517..3b2ffed9e 100644 --- a/uni/lib/model/providers/lazy/library_occupation_provider.dart +++ b/uni/lib/model/providers/lazy/library_occupation_provider.dart @@ -12,7 +12,8 @@ import 'package:uni/model/request_status.dart'; class LibraryOccupationProvider extends StateProviderNotifier { LibraryOccupation? _occupation; - LibraryOccupationProvider() : super(dependsOnSession: true); + LibraryOccupationProvider() + : super(dependsOnSession: true, cacheDuration: const Duration(hours: 1)); LibraryOccupation? get occupation => _occupation; diff --git a/uni/lib/model/providers/lazy/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart index 52b1c9a6b..e3655483e 100644 --- a/uni/lib/model/providers/lazy/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -13,7 +13,8 @@ import 'package:uni/model/request_status.dart'; class RestaurantProvider extends StateProviderNotifier { List _restaurants = []; - RestaurantProvider() : super(dependsOnSession: false); + RestaurantProvider() + : super(dependsOnSession: false, cacheDuration: const Duration(days: 1)); UnmodifiableListView get restaurants => UnmodifiableListView(_restaurants); diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index f2e48e0dd..69553c698 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -28,7 +28,8 @@ class ProfileProvider extends StateProviderNotifier { DateTime? _feesRefreshTime; DateTime? _printRefreshTime; - ProfileProvider() : super(dependsOnSession: true); + ProfileProvider() + : super(dependsOnSession: true, cacheDuration: const Duration(days: 1)); String get feesRefreshTime => _feesRefreshTime.toString(); diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index b860c267e..4c1346ebc 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -17,7 +17,11 @@ class SessionProvider extends StateProviderNotifier { Session _session = Session(); List _faculties = []; - SessionProvider() : super(dependsOnSession: false); + SessionProvider() + : super( + dependsOnSession: false, + cacheDuration: null, + initialStatus: RequestStatus.none); Session get session => _session; diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index ecf5594f6..31bfa3bdd 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -1,5 +1,6 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; +import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; import 'package:synchronized/synchronized.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; @@ -11,16 +12,21 @@ import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { static final Lock _lock = Lock(); - RequestStatus _status = RequestStatus.busy; + RequestStatus _status; bool _initialized = false; DateTime? _lastUpdateTime; bool dependsOnSession; + Duration? cacheDuration; RequestStatus get status => _status; DateTime? get lastUpdateTime => _lastUpdateTime; - StateProviderNotifier({required this.dependsOnSession}); + StateProviderNotifier( + {required this.dependsOnSession, + required this.cacheDuration, + RequestStatus? initialStatus}) + : _status = initialStatus ?? RequestStatus.busy; Future _loadFromStorage() async { _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( @@ -30,20 +36,43 @@ abstract class StateProviderNotifier extends ChangeNotifier { await AppSharedPreferences.getPersistentUserInfo(); final sessionIsPersistent = userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; + if (sessionIsPersistent) { await loadFromStorage(); + Logger().i("Loaded $runtimeType info from storage"); + } else { + Logger().i( + "Session is not persistent; skipping $runtimeType load from storage"); } } - Future _loadFromRemote(Session session, Profile profile) async { + Future _loadFromRemote(Session session, Profile profile, + {bool force = false}) async { final bool hasConnectivity = await Connectivity().checkConnectivity() != ConnectivityResult.none; - if (hasConnectivity) { - updateStatus(RequestStatus.busy); - await loadFromRemote(session, profile); + final shouldReload = force || + _lastUpdateTime == null || + cacheDuration == null || + DateTime.now().difference(_lastUpdateTime!) > cacheDuration!; + + if (shouldReload) { + if (hasConnectivity) { + updateStatus(RequestStatus.busy); + await loadFromRemote(session, profile); + if (_status == RequestStatus.successful) { + Logger().i("Loaded $runtimeType info from remote"); + } else if (_status == RequestStatus.failed) { + Logger().e("Failed to load $runtimeType info from remote"); + } + } else { + Logger().i("No internet connection; skipping $runtimeType remote load"); + } + } else { + Logger().i( + "Last info for $runtimeType is within cache period ($cacheDuration); skipping remote load"); } - if (!hasConnectivity || _status == RequestStatus.busy) { + if (!shouldReload || !hasConnectivity || _status == RequestStatus.busy) { // No online activity from provider updateStatus(RequestStatus.successful); } else { @@ -65,7 +94,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { final profile = Provider.of(context, listen: false).profile; - _loadFromRemote(session, profile); + _loadFromRemote(session, profile, force: true); } Future ensureInitialized(Session session, Profile profile) async { From c41385e2da31cc8b2cdda06320bd47e2ed88844e Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 12 Jul 2023 21:02:30 +0100 Subject: [PATCH 18/21] Make generic expansion card stateless --- .../common_widgets/generic_expansion_card.dart | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/uni/lib/view/common_widgets/generic_expansion_card.dart b/uni/lib/view/common_widgets/generic_expansion_card.dart index 072737f91..68f106ffb 100644 --- a/uni/lib/view/common_widgets/generic_expansion_card.dart +++ b/uni/lib/view/common_widgets/generic_expansion_card.dart @@ -1,25 +1,19 @@ -import 'package:flutter/material.dart'; import 'package:expansion_tile_card/expansion_tile_card.dart'; +import 'package:flutter/material.dart'; /// Card with a expansible child -abstract class GenericExpansionCard extends StatefulWidget { +abstract class GenericExpansionCard extends StatelessWidget { const GenericExpansionCard({Key? key}) : super(key: key); - @override - State createState() { - return GenericExpansionCardState(); - } - TextStyle? getTitleStyle(BuildContext context) => Theme.of(context) .textTheme .headlineSmall ?.apply(color: Theme.of(context).primaryColor); String getTitle(); + Widget buildCardContent(BuildContext context); -} -class GenericExpansionCardState extends State { @override Widget build(BuildContext context) { return Container( @@ -31,12 +25,12 @@ class GenericExpansionCardState extends State { expandedColor: (Theme.of(context).brightness == Brightness.light) ? const Color.fromARGB(0xf, 0, 0, 0) : const Color.fromARGB(255, 43, 43, 43), - title: Text(widget.getTitle(), style: widget.getTitleStyle(context)), + title: Text(getTitle(), style: getTitleStyle(context)), elevation: 0, children: [ Container( padding: const EdgeInsets.fromLTRB(12, 0, 12, 12), - child: widget.buildCardContent(context), + child: buildCardContent(context), ) ], )); From 8142b3fb60f06eca957b02d99f3b2f7c5d36f638 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 12 Jul 2023 21:38:12 +0100 Subject: [PATCH 19/21] Encapsulate card refresh logic --- .../providers/faculty_locations_provider.dart | 1 - uni/lib/view/common_widgets/generic_card.dart | 4 +- .../widgets/course_unit_card.dart | 3 ++ uni/lib/view/home/home.dart | 52 +++---------------- uni/lib/view/home/widgets/bus_stop_card.dart | 6 +++ uni/lib/view/home/widgets/exam_card.dart | 6 +++ .../view/home/widgets/main_cards_list.dart | 4 +- .../view/home/widgets/restaurant_card.dart | 9 +++- uni/lib/view/home/widgets/schedule_card.dart | 6 +++ .../widgets/library_occupation_card.dart | 7 +++ .../profile/widgets/account_info_card.dart | 8 +++ .../profile/widgets/course_info_card.dart | 50 +++++++++++++----- .../view/profile/widgets/print_info_card.dart | 6 +++ .../widgets/restaurant_page_card.dart | 5 +- 14 files changed, 103 insertions(+), 64 deletions(-) delete mode 100644 uni/lib/model/providers/faculty_locations_provider.dart diff --git a/uni/lib/model/providers/faculty_locations_provider.dart b/uni/lib/model/providers/faculty_locations_provider.dart deleted file mode 100644 index 613744d49..000000000 --- a/uni/lib/model/providers/faculty_locations_provider.dart +++ /dev/null @@ -1 +0,0 @@ -// TODO Implement this library. diff --git a/uni/lib/view/common_widgets/generic_card.dart b/uni/lib/view/common_widgets/generic_card.dart index dc92d9d04..03823f2f3 100644 --- a/uni/lib/view/common_widgets/generic_card.dart +++ b/uni/lib/view/common_widgets/generic_card.dart @@ -32,7 +32,9 @@ abstract class GenericCard extends StatefulWidget { String getTitle(); - dynamic onClick(BuildContext context); + void onClick(BuildContext context); + + void onRefresh(BuildContext context); Text getInfoText(String text, BuildContext context) { return Text(text, diff --git a/uni/lib/view/course_units/widgets/course_unit_card.dart b/uni/lib/view/course_units/widgets/course_unit_card.dart index a3df1298d..2b424fdac 100644 --- a/uni/lib/view/course_units/widgets/course_unit_card.dart +++ b/uni/lib/view/course_units/widgets/course_unit_card.dart @@ -42,4 +42,7 @@ class CourseUnitCard extends GenericCard { MaterialPageRoute( builder: (context) => CourseUnitDetailPageView(courseUnit))); } + + @override + void onRefresh(BuildContext context) {} } diff --git a/uni/lib/view/home/home.dart b/uni/lib/view/home/home.dart index 859c44d41..a1c99a25c 100644 --- a/uni/lib/view/home/home.dart +++ b/uni/lib/view/home/home.dart @@ -1,14 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; -import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/providers/lazy/home_page_provider.dart'; -import 'package:uni/model/providers/lazy/lecture_provider.dart'; -import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; -import 'package:uni/model/providers/lazy/reference_provider.dart'; -import 'package:uni/model/providers/startup/profile_provider.dart'; -import 'package:uni/model/providers/state_provider_notifier.dart'; -import 'package:uni/utils/favorite_widget_type.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; import 'package:uni/view/home/widgets/main_cards_list.dart'; @@ -23,47 +15,19 @@ class HomePageView extends StatefulWidget { class HomePageViewState extends GeneralPageViewState { @override Widget getBody(BuildContext context) { - return MainCardsList(); + return const MainCardsList(); } @override Future handleRefresh(BuildContext context) async { - final homePageProvider = - Provider.of(context, listen: false); + final favoriteCardTypes = context.read().favoriteCards; + final cards = favoriteCardTypes + .map((e) => + MainCardsList.cardCreators[e]!(const Key(""), false, () => null)) + .toList(); - final providersToUpdate = {}; - - for (final cardType in homePageProvider.favoriteCards) { - switch (cardType) { - case FavoriteWidgetType.account: - providersToUpdate - .add(Provider.of(context, listen: false)); - providersToUpdate - .add(Provider.of(context, listen: false)); - break; - case FavoriteWidgetType.exams: - providersToUpdate - .add(Provider.of(context, listen: false)); - break; - case FavoriteWidgetType.schedule: - providersToUpdate - .add(Provider.of(context, listen: false)); - break; - case FavoriteWidgetType.printBalance: - providersToUpdate - .add(Provider.of(context, listen: false)); - break; - case FavoriteWidgetType.libraryOccupation: - providersToUpdate.add( - Provider.of(context, listen: false)); - break; - case FavoriteWidgetType.busStops: - providersToUpdate - .add(Provider.of(context, listen: false)); - break; - } + for (final card in cards) { + card.onRefresh(context); } - - Future.wait(providersToUpdate.map((e) => e.forceRefresh(context))); } } diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index 0f981093d..0e66d9cae 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/model/request_status.dart'; @@ -31,6 +32,11 @@ class BusStopCard extends GenericCard { }, ); } + + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + } } /// Returns a widget with the bus stop card final content diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 92c10ba38..b7b7f4fe9 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -26,6 +27,11 @@ class ExamCard extends GenericCard { onClick(BuildContext context) => Navigator.pushNamed(context, '/${DrawerItem.navExams.title}'); + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + } + /// Returns a widget with all the exams card content. /// /// If there are no exams, a message telling the user diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index bf4156ae9..7871c81d7 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -19,7 +19,7 @@ typedef CardCreator = GenericCard Function( Key key, bool isEditingMode, dynamic Function()? onDelete); class MainCardsList extends StatelessWidget { - final Map cardCreators = { + static Map cardCreators = { FavoriteWidgetType.schedule: (k, em, od) => ScheduleCard.fromEditingInformation(k, em, od), FavoriteWidgetType.exams: (k, em, od) => @@ -37,7 +37,7 @@ class MainCardsList extends StatelessWidget { LibraryOccupationCard.fromEditingInformation(k, em, od) }; - MainCardsList({super.key}); + const MainCardsList({super.key}); @override Widget build(BuildContext context) { diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 39c440043..8efb549e8 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/providers/lazy/restaurant_provider.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; @@ -18,7 +19,13 @@ class RestaurantCard extends GenericCard { String getTitle() => 'Cantinas'; @override - onClick(BuildContext context) => null; + onClick(BuildContext context) {} + + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false) + .forceRefresh(context); + } @override Widget buildCardContent(BuildContext context) { diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index d0f066ec8..a525b8e96 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; @@ -21,6 +22,11 @@ class ScheduleCard extends GenericCard { final double leftPadding = 12.0; final List lectures = []; + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + } + @override Widget buildCardContent(BuildContext context) { return LazyConsumer( diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index b4af4b85f..d4265d2c5 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/percent_indicator.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/providers/lazy/library_occupation_provider.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -22,6 +23,12 @@ class LibraryOccupationCard extends GenericCard { onClick(BuildContext context) => Navigator.pushNamed(context, '/${DrawerItem.navLibrary.title}'); + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false) + .forceRefresh(context); + } + @override Widget buildCardContent(BuildContext context) { return LazyConsumer( diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index ad4417de3..14e2bce92 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/entities/reference.dart'; import 'package:uni/model/providers/lazy/reference_provider.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; @@ -16,6 +17,13 @@ class AccountInfoCard extends GenericCard { Key key, bool editingMode, Function()? onDelete) : super.fromEditingInformation(key, editingMode, onDelete); + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + Provider.of(context, listen: false) + .forceRefresh(context); + } + @override Widget buildCardContent(BuildContext context) { return LazyConsumer( diff --git a/uni/lib/view/profile/widgets/course_info_card.dart b/uni/lib/view/profile/widgets/course_info_card.dart index 86fb0b052..f328fbc25 100644 --- a/uni/lib/view/profile/widgets/course_info_card.dart +++ b/uni/lib/view/profile/widgets/course_info_card.dart @@ -18,11 +18,14 @@ class CourseInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 20.0, bottom: 8.0, left: 20.0), child: Text('Ano curricular atual: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 20.0, bottom: 8.0, right: 20.0), + const EdgeInsets.only(top: 20.0, bottom: 8.0, right: 20.0), child: getInfoText(course.currYear ?? 'Indisponível', context), ) ]), @@ -30,11 +33,14 @@ class CourseInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), child: Text('Estado atual: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText(course.state ?? 'Indisponível', context), ) ]), @@ -42,14 +48,18 @@ class CourseInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), child: Text('Ano da primeira inscrição: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText( course.firstEnrollment != null - ? '${course.firstEnrollment}/${course.firstEnrollment! + 1}' + ? '${course.firstEnrollment}/${course.firstEnrollment! + + 1}' : '?', context)) ]), @@ -57,11 +67,14 @@ class CourseInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), child: Text('Faculdade: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText( course.faculty?.toUpperCase() ?? 'Indisponível', context)) ]), @@ -69,11 +82,14 @@ class CourseInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), child: Text('Média: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText( course.currentAverage?.toString() ?? 'Indisponível', context)) @@ -81,13 +97,16 @@ class CourseInfoCard extends GenericCard { TableRow(children: [ Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 20.0, left: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 20.0, left: 20.0), child: Text('ECTs realizados: ', - style: Theme.of(context).textTheme.titleSmall), + style: Theme + .of(context) + .textTheme + .titleSmall), ), Container( margin: - const EdgeInsets.only(top: 10.0, bottom: 20.0, right: 20.0), + const EdgeInsets.only(top: 10.0, bottom: 20.0, right: 20.0), child: getInfoText( course.finishedEcts?.toString().replaceFirst('.0', '') ?? '?', @@ -103,4 +122,7 @@ class CourseInfoCard extends GenericCard { @override onClick(BuildContext context) {} + + @override + void onRefresh(BuildContext context) {} } diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index bb41169b5..d53c38bbb 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/view/lazy_consumer.dart'; @@ -63,4 +64,9 @@ class PrintInfoCard extends GenericCard { @override onClick(BuildContext context) {} + + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + } } diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index 062fe8a88..c615fa757 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -7,7 +7,7 @@ class RestaurantPageCard extends GenericCard { RestaurantPageCard(this.restaurantName, this.meals, {super.key}) : super.customStyle( - editingMode: false, onDelete: () => null, smallTitle: true); + editingMode: false, onDelete: () => null, smallTitle: true); @override Widget buildCardContent(BuildContext context) { @@ -21,4 +21,7 @@ class RestaurantPageCard extends GenericCard { @override onClick(BuildContext context) {} + + @override + void onRefresh(BuildContext context) {} } From 4dde44f40d748de1e75c60aed4601f6ba18cfe27 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 12 Jul 2023 21:48:55 +0100 Subject: [PATCH 20/21] Do not allow concurrent refreshes --- .../providers/state_provider_notifier.dart | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index fb56a4d51..22f81de89 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -68,7 +68,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { "$runtimeType remote load method did not update request status"); } } else { - Logger().i("No internet connection; skipping $runtimeType remote load"); + Logger().w("No internet connection; skipping $runtimeType remote load"); } } else { Logger().i( @@ -92,12 +92,22 @@ abstract class StateProviderNotifier extends ChangeNotifier { } Future forceRefresh(BuildContext context) async { - final session = - Provider.of(context, listen: false).session; - final profile = - Provider.of(context, listen: false).profile; + await _lock.synchronized(() async { + if (_lastUpdateTime != null && + DateTime.now().difference(_lastUpdateTime!) < + const Duration(minutes: 1)) { + Logger().w( + "Last update for $runtimeType was less than a minute ago; skipping refresh"); + return; + } - _loadFromRemote(session, profile, force: true); + final session = + Provider.of(context, listen: false).session; + final profile = + Provider.of(context, listen: false).profile; + + _loadFromRemote(session, profile, force: true); + }); } Future ensureInitialized(Session session, Profile profile) async { From 884e3b6fe6a0a0e7f7842f13cb0bb2ece3676dfe Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 13 Jul 2023 15:00:25 +0100 Subject: [PATCH 21/21] Always load from storage --- .../model/providers/state_provider_notifier.dart | 14 ++------------ uni/lib/view/navigation_service.dart | 3 ++- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 22f81de89..a95232d8f 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -32,18 +32,8 @@ abstract class StateProviderNotifier extends ChangeNotifier { _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( runtimeType.toString()); - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final sessionIsPersistent = - userPersistentInfo.item1 != '' && userPersistentInfo.item2 != ''; - - if (sessionIsPersistent) { - await loadFromStorage(); - Logger().i("Loaded $runtimeType info from storage"); - } else { - Logger().i( - "Session is not persistent; skipping $runtimeType load from storage"); - } + await loadFromStorage(); + Logger().i("Loaded $runtimeType info from storage"); } Future _loadFromRemote(Session session, Profile profile, diff --git a/uni/lib/view/navigation_service.dart b/uni/lib/view/navigation_service.dart index 89bf885b2..233faccf9 100644 --- a/uni/lib/view/navigation_service.dart +++ b/uni/lib/view/navigation_service.dart @@ -5,8 +5,9 @@ import 'package:uni/utils/drawer_items.dart'; class NavigationService { static final GlobalKey navigatorKey = GlobalKey(); + static logout() { - navigatorKey.currentState!.pushNamedAndRemoveUntil( + navigatorKey.currentState?.pushNamedAndRemoveUntil( '/${DrawerItem.navLogOut.title}', (_) => false); } }