From 6478dde2b137e543a5427219383893802c0a9a6b Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 1 Mar 2023 15:51:06 +0000 Subject: [PATCH 001/199] Restaurant card on the widgets menu --- uni/lib/utils/favorite_widget_type.dart | 1 + uni/lib/view/home/widgets/main_cards_list.dart | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/uni/lib/utils/favorite_widget_type.dart b/uni/lib/utils/favorite_widget_type.dart index 36510473f..ded2ca7c7 100644 --- a/uni/lib/utils/favorite_widget_type.dart +++ b/uni/lib/utils/favorite_widget_type.dart @@ -3,6 +3,7 @@ enum FavoriteWidgetType { schedule, printBalance, account, + restaurant, libraryOccupation(faculties: {"feup"}), busStops; diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index c4614fa2d..4efdd878b 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -9,6 +9,7 @@ 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/home/widgets/bus_stop_card.dart'; +import 'package:uni/view/home/widgets/restaurant_card.dart'; import 'package:uni/view/home/widgets/exam_card.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/profile/widgets/print_info_card.dart'; @@ -28,7 +29,9 @@ class MainCardsList extends StatelessWidget { FavoriteWidgetType.busStops: (k, em, od) => BusStopCard.fromEditingInformation(k, em, od), FavoriteWidgetType.libraryOccupation: (k, em, od) => - LibraryOccupationCard.fromEditingInformation(k, em, od) + LibraryOccupationCard.fromEditingInformation(k, em, od), + FavoriteWidgetType.restaurant: (k, em, od) => + RestaurantCard.fromEditingInformation(k, em, od) }; MainCardsList({super.key}); From e0df7560a913866fda49a30ac3b7e409f7c216b4 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 3 Mar 2023 22:29:33 +0000 Subject: [PATCH 002/199] Restaurants data connected to the home card --- .../view/home/widgets/restaurant_card.dart | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 69255adfa..e4816f07e 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -6,6 +6,23 @@ 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/model/entities/meal.dart'; +import 'package:uni/model/entities/restaurant.dart'; +import 'package:uni/model/utils/day_of_week.dart'; + + +final List daysOfTheWeek = [ + DayOfWeek.monday, + DayOfWeek.tuesday, + DayOfWeek.wednesday, + DayOfWeek.thursday, + DayOfWeek.friday, + DayOfWeek.saturday, + DayOfWeek.sunday +]; + +final int weekDay = DateTime.now().weekday; +final offset = (weekDay > 5) ? 0 : (weekDay - 1) % daysOfTheWeek.length; class RestaurantCard extends GenericCard { RestaurantCard({Key? key}) : super(key: key); @@ -14,6 +31,7 @@ class RestaurantCard extends GenericCard { Key key, bool editingMode, Function()? onDelete) : super.fromEditingInformation(key, editingMode, onDelete); + @override String getTitle() => 'Cantinas'; @@ -28,40 +46,41 @@ class RestaurantCard extends GenericCard { context: context, status: restaurantProvider.status, contentGenerator: generateRestaurant, - content: restaurantProvider.restaurants, + content: restaurantProvider.restaurants[2], contentChecker: restaurantProvider.restaurants.isNotEmpty, onNullContent: Center( child: Text('Não existem cantinas para apresentar', style: Theme.of(context).textTheme.headline4, textAlign: TextAlign.center)))); + } + Widget generateRestaurant(canteens, context) { return Column( mainAxisSize: MainAxisSize.min, - children: [createRowFromRestaurant(context, canteens)], + children: [createRowFromRestaurant(context, canteens, daysOfTheWeek[offset])], ); } - Widget createRowFromRestaurant(context, String canteen) { - // TODO: Issue #390 + Widget createRowFromRestaurant(context, Restaurant restaurant, DayOfWeek day) { + final List meals = restaurant.getMealsOfDay(day); return Column(children: [ - const DateRectangle(date: ''), // TODO: Issue #390 + DateRectangle(date: toString(day)), // cantine.nextSchoolDay Center( child: Container( - padding: const EdgeInsets.all(12.0), child: Text(canteen))), + padding: const EdgeInsets.all(12.0), child: Text(restaurant.name))), Card( elevation: 1, child: RowContainer( color: const Color.fromARGB(0, 0, 0, 0), child: RestaurantRow( - local: canteen, - meatMenu: '', - // TODO: Issue #390 - fishMenu: '', - vegetarianMenu: '', - dietMenu: '', + local: restaurant.name, + meatMenu: meals.isNotEmpty ? meals[0].name : 'Prato não disponível', + fishMenu: meals.length > 1 ? meals[1].name : 'Prato não disponível', + vegetarianMenu: meals.length > 2 ? meals[2].name : 'Prato não disponível', + dietMenu: meals.length > 3 ? meals[3].name : 'Prato não disponível', )), ), ]); From d179dce90dfc1d828518c1b57db0403bcb711047 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 16 Mar 2023 12:04:07 +0000 Subject: [PATCH 003/199] Favorite restaurants feature --- uni/lib/controller/load_info.dart | 8 +- .../local_storage/app_shared_preferences.dart | 14 ++- .../model/providers/restaurant_provider.dart | 33 ++++-- .../view/home/widgets/restaurant_card.dart | 47 ++++---- .../view/restaurant/restaurant_page_view.dart | 71 +++++++------ .../widgets/restaurant_page_card.dart | 100 +++++++++++++++--- 6 files changed, 200 insertions(+), 73 deletions(-) diff --git a/uni/lib/controller/load_info.dart b/uni/lib/controller/load_info.dart index 93b7c1a56..fb20f6f66 100644 --- a/uni/lib/controller/load_info.dart +++ b/uni/lib/controller/load_info.dart @@ -12,7 +12,7 @@ import 'package:uni/model/providers/state_providers.dart'; Future loadReloginInfo(StateProviders stateProviders) async { final Tuple2 userPersistentCredentials = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); final String userName = userPersistentCredentials.item1; final String password = userPersistentCredentials.item2; final List faculties = await AppSharedPreferences.getUserFaculties(); @@ -59,7 +59,7 @@ Future loadRemoteUserInfoToState(StateProviders stateProviders) async { .getLibraryOccupation(session, libraryOccupation); final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); userInfo.future.then((value) { final profile = stateProviders.profileStateProvider.profile; @@ -97,11 +97,13 @@ Future loadRemoteUserInfoToState(StateProviders stateProviders) async { void loadLocalUserInfoToState(StateProviders stateProviders, {skipDatabaseLookup = false}) async { final Tuple2 userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + await AppSharedPreferences.getPersistentUserInfo(); Logger().i('Setting up user preferences'); stateProviders.favoriteCardsProvider .setFavoriteCards(await AppSharedPreferences.getFavoriteCards()); + stateProviders.restaurantProvider + .setFavoriteRestaurants(await AppSharedPreferences.getFavoriteRestaurants(), Completer()); stateProviders.examProvider.setFilteredExams( await AppSharedPreferences.getFilteredExams(), Completer()); stateProviders.examProvider diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index aa6ae8621..4fe70c17f 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -30,6 +30,7 @@ class AppSharedPreferences { FavoriteWidgetType.busStops ]; static const String hiddenExams = 'hidden_exams'; + static const String favoriteRestaurants = 'favorite_restaurants'; static const String filteredExamsTypes = 'filtered_exam_types'; static final List defaultFilteredExamTypes = Exam.displayedTypes; @@ -150,6 +151,16 @@ class AppSharedPreferences { .toList(); } + static saveFavoriteRestaurants(List newFavoriteRestaurants) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setStringList(favoriteRestaurants, newFavoriteRestaurants); + } + + static Future> getFavoriteRestaurants() async { + final prefs = await SharedPreferences.getInstance(); + final List storedFavoriteRestaurants = prefs.getStringList(favoriteRestaurants) ?? []; + return storedFavoriteRestaurants; + } static saveHiddenExams(List newHiddenExams) async { final prefs = await SharedPreferences.getInstance(); @@ -176,7 +187,7 @@ class AppSharedPreferences { static Future> getFilteredExams() async { final prefs = await SharedPreferences.getInstance(); final List? storedFilteredExamTypes = - prefs.getStringList(filteredExamsTypes); + prefs.getStringList(filteredExamsTypes); if (storedFilteredExamTypes == null) { return Map.fromIterable(defaultFilteredExamTypes, value: (type) => true); @@ -203,3 +214,4 @@ class AppSharedPreferences { return encrypt.Encrypter(encrypt.AES(key)); } } + diff --git a/uni/lib/model/providers/restaurant_provider.dart b/uni/lib/model/providers/restaurant_provider.dart index 54765609d..4a60bfc3c 100644 --- a/uni/lib/model/providers/restaurant_provider.dart +++ b/uni/lib/model/providers/restaurant_provider.dart @@ -2,28 +2,31 @@ 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/controller/local_storage/app_shared_preferences.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 = []; + List _favoriteRestaurants = []; UnmodifiableListView get restaurants => UnmodifiableListView(_restaurants); - void getRestaurantsFromFetcher( - Completer action, Session session) async { + UnmodifiableListView get favoriteRestaurants => + UnmodifiableListView(_favoriteRestaurants); + + void getRestaurantsFromFetcher(Completer action, Session session) async { try { updateStatus(RequestStatus.busy); final List restaurants = - await RestaurantFetcher().getRestaurants(session); + await RestaurantFetcher().getRestaurants(session); // Updates local database according to information fetched -- Restaurants final RestaurantDatabase db = RestaurantDatabase(); db.saveRestaurants(restaurants); @@ -37,10 +40,28 @@ class RestaurantProvider extends StateProviderNotifier { action.complete(); } - void updateStateBasedOnLocalRestaurants() async { + setFavoriteRestaurants(List newFavoriteRestaurants, Completer action) async { + _favoriteRestaurants = List.from(newFavoriteRestaurants); + AppSharedPreferences.saveFavoriteRestaurants(favoriteRestaurants); + action.complete(); + notifyListeners(); + } + + toggleFavoriteRestaurant(String restaurantName, Completer action) async { + _favoriteRestaurants.contains(restaurantName) + ? _favoriteRestaurants.remove(restaurantName) + : _favoriteRestaurants.add(restaurantName); + notifyListeners(); + AppSharedPreferences.saveFavoriteRestaurants(favoriteRestaurants); + action.complete(); + } + + void updateStateBasedOnLocalRestaurants() async{ final RestaurantDatabase restaurantDb = RestaurantDatabase(); final List restaurants = await restaurantDb.getRestaurants(); _restaurants = restaurants; notifyListeners(); } + } + diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index e4816f07e..9a25b39f2 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,7 +1,6 @@ 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'; @@ -40,34 +39,42 @@ class RestaurantCard extends GenericCard { @override Widget buildCardContent(BuildContext context) { - return Consumer( - builder: (context, restaurantProvider, _) => - RequestDependentWidgetBuilder( - context: context, - status: restaurantProvider.status, - contentGenerator: generateRestaurant, - content: restaurantProvider.restaurants[2], - contentChecker: restaurantProvider.restaurants.isNotEmpty, - onNullContent: Center( - child: Text('Não existem cantinas para apresentar', - style: Theme.of(context).textTheme.headline4, - textAlign: TextAlign.center)))); - + return Consumer(builder: (context, restaurantProvider, _) { + final List favoriteRestaurants = restaurantProvider.restaurants.where((restaurant) => restaurantProvider.favoriteRestaurants.contains(restaurant.name)).toList(); + return RequestDependentWidgetBuilder( + context: context, + status: restaurantProvider.status, + contentGenerator: generateRestaurant, + content: favoriteRestaurants, + contentChecker: favoriteRestaurants.isNotEmpty, + onNullContent: Center( + child: Text('Não existem cantinas para apresentar', + style: Theme.of(context).textTheme.headline4, + textAlign: TextAlign.center)));}); } - Widget generateRestaurant(canteens, context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [createRowFromRestaurant(context, canteens, daysOfTheWeek[offset])], + Widget generateRestaurant(dynamic data, BuildContext context) { + final List restaurants = data; + return ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: restaurants.length, + itemBuilder: (BuildContext context, int index) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + createRowFromRestaurant(context, restaurants[index], daysOfTheWeek[offset]) + ], + ); + }, ); } + Widget createRowFromRestaurant(context, Restaurant restaurant, DayOfWeek day) { final List meals = restaurant.getMealsOfDay(day); return Column(children: [ - DateRectangle(date: toString(day)), - // cantine.nextSchoolDay Center( child: Container( padding: const EdgeInsets.all(12.0), child: Text(restaurant.name))), diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 3af637025..95bb18e34 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -16,11 +16,22 @@ class RestaurantPageView extends StatefulWidget { const RestaurantPageView({Key? key}) : super(key: key); @override - State createState() => _CanteenPageState(); + State createState() => _CantinePageState(); } -class _CanteenPageState extends GeneralPageViewState +class _CantinePageState extends GeneralPageViewState with SingleTickerProviderStateMixin { + + final List daysOfTheWeek = [ + DayOfWeek.monday, + DayOfWeek.tuesday, + DayOfWeek.wednesday, + DayOfWeek.thursday, + DayOfWeek.friday, + DayOfWeek.saturday, + DayOfWeek.sunday + ]; + late List aggRestaurant; late TabController tabController; late ScrollController scrollViewController; @@ -30,8 +41,8 @@ class _CanteenPageState extends GeneralPageViewState super.initState(); final int weekDay = DateTime.now().weekday; super.initState(); - tabController = TabController(vsync: this, length: DayOfWeek.values.length); - final offset = (weekDay > 5) ? 0 : (weekDay - 1) % DayOfWeek.values.length; + tabController = TabController(vsync: this, length: daysOfTheWeek.length); + final offset = (weekDay > 5) ? 0 : (weekDay - 1) % daysOfTheWeek.length; tabController.animateTo((tabController.index + offset)); scrollViewController = ScrollController(); } @@ -44,7 +55,7 @@ class _CanteenPageState extends GeneralPageViewState } - Widget _getPageView(List restaurants, RequestStatus? status) { + Widget _getPageView(List restaurants, RequestStatus? status) { return Column(children: [ ListView(scrollDirection: Axis.vertical, shrinkWrap: true, children: [ Container( @@ -70,30 +81,30 @@ class _CanteenPageState extends GeneralPageViewState } Widget createTabViewBuilder(dynamic restaurants, BuildContext context) { - final List dayContents = DayOfWeek.values.map((dayOfWeek) { - List cantinesWidgets = []; - if (restaurants is List) { - cantinesWidgets = restaurants - .map((restaurant) => createRestaurant(context, restaurant, dayOfWeek)) - .toList(); - } - return ListView( children: cantinesWidgets,); - }).toList(); - - return Expanded( - child: TabBarView( - controller: tabController, - children: dayContents, - )); + final List dayContents = daysOfTheWeek.map((dayOfWeek) { + List cantinesWidgets = []; + if (restaurants is List) { + cantinesWidgets = restaurants + .map((restaurant) => createRestaurant(context, restaurant, dayOfWeek)) + .toList(); + } + return ListView( children: cantinesWidgets,); + }).toList(); + + return Expanded( + child: TabBarView( + controller: tabController, + children: dayContents, + )); } List createTabs(BuildContext context) { final List tabs = []; - for (var i = 0; i < DayOfWeek.values.length; i++) { + for (var i = 0; i < daysOfTheWeek.length; i++) { tabs.add(Container( color: Theme.of(context).backgroundColor, - child: Tab(key: Key('cantine-page-tab-$i'), text: toString(DayOfWeek.values[i])), + child: Tab(key: Key('cantine-page-tab-$i'), text: toString(daysOfTheWeek[i])), )); } @@ -101,7 +112,7 @@ class _CanteenPageState extends GeneralPageViewState } Widget createRestaurant(context, Restaurant restaurant, DayOfWeek dayOfWeek) { - return RestaurantPageCard(restaurant.name, createRestaurantByDay(context, restaurant, dayOfWeek)); + return RestaurantPageCard(restaurant, createRestaurantByDay(context, restaurant, dayOfWeek)); } List createRestaurantRows(List meals, BuildContext context) { @@ -126,14 +137,14 @@ class _CanteenPageState extends GeneralPageViewState ); } else { return Container( - margin: + margin: const EdgeInsets.only(top: 5, bottom: 5), - key: Key('cantine-page-day-column-$day'), - child: Column( - mainAxisSize: MainAxisSize.min, - children: createRestaurantRows(meals, context), - ) - ); + key: Key('cantine-page-day-column-$day'), + child: Column( + mainAxisSize: MainAxisSize.min, + children: createRestaurantRows(meals, context), + ) + ); } } } diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index 9dbfd2773..bd8b20507 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -1,22 +1,96 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; -import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:uni/model/entities/restaurant.dart'; +import 'package:uni/model/providers/restaurant_provider.dart'; +import 'package:provider/provider.dart'; + -class RestaurantPageCard extends GenericCard { - final String restaurantName; + +class RestaurantPageCard extends StatefulWidget { + final Restaurant restaurant; final Widget meals; - RestaurantPageCard(this.restaurantName, this.meals, {super.key}) : super.customStyle(editingMode: false, onDelete: () => null, smallTitle: true); + RestaurantPageCard(this.restaurant, this.meals, {Key ? key}) + : super(key: key); @override - Widget buildCardContent(BuildContext context) { - return meals; - } + State createState() => RestaurantPageCardState(); +} - @override - String getTitle() { - return restaurantName; - } +class RestaurantPageCardState extends State { @override - onClick(BuildContext context) {} -} \ No newline at end of file + Widget build(BuildContext context) { + final isFavorite = Provider.of(context).favoriteRestaurants.contains(widget.restaurant.name); + return Card( + margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + child: Container( + decoration: BoxDecoration( + boxShadow: const [ + BoxShadow( + color: Color.fromARGB(0x1c, 0, 0, 0), + blurRadius: 7.0, + offset: Offset(0.0, 1.0), + ) + ], + borderRadius: BorderRadius.all(Radius.circular(10.0)), + ), + child: ConstrainedBox( + constraints: const BoxConstraints( + minHeight: 60.0, + ), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).cardColor, + borderRadius: BorderRadius.all(Radius.circular(10.0)), + ), + width: double.infinity, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: + const EdgeInsets.only(top: 15, bottom: 10), + child: Text( + widget.restaurant.name, + style: (Theme.of(context).textTheme.headline6!) + .copyWith( + color: + Theme.of(context).primaryColor), + ), + ), + ), + IconButton( + icon: isFavorite ? const Icon(MdiIcons.heart) : const Icon(MdiIcons.heartOutline), + onPressed: () => setState((){ + Provider.of(context, listen: false).toggleFavoriteRestaurant(widget.restaurant.name, Completer()); + })),], + ), + Container( + padding: EdgeInsets.only( + left: 12.0, + right: 12.0, + bottom: 12.0, + ), + child: widget.meals, + ) + ], + ), + ), + ), + )); + } +} From 6d83bc7c47cfc76965add2f45d0d74ab1f253a01 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 16 Mar 2023 12:13:51 +0000 Subject: [PATCH 004/199] Lint fixing --- uni/lib/view/home/widgets/restaurant_card.dart | 2 +- .../view/restaurant/widgets/restaurant_page_card.dart | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 9a25b39f2..ae9a20f11 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -58,7 +58,7 @@ class RestaurantCard extends GenericCard { final List restaurants = data; return ListView.builder( shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), + physics: const NeverScrollableScrollPhysics(), itemCount: restaurants.length, itemBuilder: (BuildContext context, int index) { return Column( diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index bd8b20507..f96fb1038 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -12,7 +12,7 @@ class RestaurantPageCard extends StatefulWidget { final Restaurant restaurant; final Widget meals; - RestaurantPageCard(this.restaurant, this.meals, {Key ? key}) + const RestaurantPageCard(this.restaurant, this.meals, {Key ? key}) : super(key: key); @override @@ -31,8 +31,8 @@ class RestaurantPageCardState extends State { borderRadius: BorderRadius.circular(10.0), ), child: Container( - decoration: BoxDecoration( - boxShadow: const [ + decoration: const BoxDecoration( + boxShadow: [ BoxShadow( color: Color.fromARGB(0x1c, 0, 0, 0), blurRadius: 7.0, @@ -48,7 +48,7 @@ class RestaurantPageCardState extends State { child: Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, - borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderRadius: const BorderRadius.all(Radius.circular(10.0)), ), width: double.infinity, child: Column( @@ -80,7 +80,7 @@ class RestaurantPageCardState extends State { })),], ), Container( - padding: EdgeInsets.only( + padding: const EdgeInsets.only( left: 12.0, right: 12.0, bottom: 12.0, From f9c2cfa717ab3bfd856bf42c8fbc160719708c6f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 16 Mar 2023 14:27:04 +0000 Subject: [PATCH 005/199] Minor redesign --- uni/lib/view/home/widgets/restaurant_card.dart | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index ae9a20f11..14fadcecc 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -8,6 +8,7 @@ import 'package:uni/view/home/widgets/restaurant_row.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/utils/day_of_week.dart'; +import 'package:uni/utils/drawer_items.dart'; final List daysOfTheWeek = [ @@ -47,11 +48,17 @@ class RestaurantCard extends GenericCard { contentGenerator: generateRestaurant, content: favoriteRestaurants, contentChecker: favoriteRestaurants.isNotEmpty, - onNullContent: Center( - child: Text('Não existem cantinas para apresentar', - style: Theme.of(context).textTheme.headline4, - textAlign: TextAlign.center)));}); - } + onNullContent: Column(children: [ + Padding( + padding: const EdgeInsets.only(top: 15, bottom: 10), + child: Center( + child: Text('Sem restaurantes favoritos', + style: Theme.of(context).textTheme.subtitle1))), + OutlinedButton( + onPressed: () => Navigator.pushNamed(context, '/${DrawerItem.navRestaurants.title}'), + child: const Text('Adicionar')) + ])); + });} Widget generateRestaurant(dynamic data, BuildContext context) { From 2c396e92bae4fcbb17342117bc03efc3ee8b05cc Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 16 Mar 2023 15:03:22 +0000 Subject: [PATCH 006/199] Bug fixing --- .../view/home/widgets/restaurant_card.dart | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 14fadcecc..fc34d1399 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -4,11 +4,11 @@ import 'package:uni/model/providers/restaurant_provider.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/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/utils/day_of_week.dart'; import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; final List daysOfTheWeek = [ @@ -84,19 +84,33 @@ class RestaurantCard extends GenericCard { return Column(children: [ Center( child: Container( - padding: const EdgeInsets.all(12.0), child: Text(restaurant.name))), + padding: const EdgeInsets.all(15.0), child: Text(restaurant.name)),), + if(meals.isNotEmpty) Card( elevation: 1, child: RowContainer( color: const Color.fromARGB(0, 0, 0, 0), - child: RestaurantRow( - local: restaurant.name, - meatMenu: meals.isNotEmpty ? meals[0].name : 'Prato não disponível', - fishMenu: meals.length > 1 ? meals[1].name : 'Prato não disponível', - vegetarianMenu: meals.length > 2 ? meals[2].name : 'Prato não disponível', - dietMenu: meals.length > 3 ? meals[3].name : 'Prato não disponível', + child: Column( + mainAxisSize: MainAxisSize.min, + children: createRestaurantRows(meals, context), )), - ), + ) + else + Card( + elevation: 1, + child: RowContainer( + color: const Color.fromARGB(0, 0, 0, 0), + child: Container( + padding: const EdgeInsets.all(12.0), + child: const Text('Refeições não disponíveis')) + )) ]); } + + List createRestaurantRows(List meals, BuildContext context) { + return meals + .map((meal) => RestaurantSlot(type: meal.type, name: meal.name)) + .toList(); + } + } From 24227fe6b973cbc4a9f68e61560fea89b34e45aa Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 21 Mar 2023 21:09:32 +0000 Subject: [PATCH 007/199] Implementation of card action --- uni/lib/view/common_widgets/generic_card.dart | 44 ++++--- .../widgets/restaurant_page_card.dart | 109 +++++------------- 2 files changed, 57 insertions(+), 96 deletions(-) diff --git a/uni/lib/view/common_widgets/generic_card.dart b/uni/lib/view/common_widgets/generic_card.dart index be81dd354..e2aea6e29 100644 --- a/uni/lib/view/common_widgets/generic_card.dart +++ b/uni/lib/view/common_widgets/generic_card.dart @@ -4,6 +4,7 @@ import 'package:uni/model/entities/time_utilities.dart'; /// App default card abstract class GenericCard extends StatefulWidget { final EdgeInsetsGeometry margin; + final Widget cardAction; final bool smallTitle; final bool editingMode; final Function()? onDelete; @@ -18,6 +19,7 @@ abstract class GenericCard extends StatefulWidget { const GenericCard.customStyle( {Key? key, required this.editingMode, + this.cardAction = const SizedBox.shrink(), required this.onDelete, this.margin = const EdgeInsets.symmetric(vertical: 10, horizontal: 20), this.smallTitle = false}) @@ -100,18 +102,20 @@ class GenericCardState extends State { children: [ Flexible( child: Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric(horizontal: 15), - margin: const EdgeInsets.only(top: 15, bottom: 10), - child: Text(widget.getTitle(), - style: (widget.smallTitle - ? Theme.of(context).textTheme.headline6! - : Theme.of(context) - .textTheme - .headline5!) - .copyWith( - color: Theme.of(context).primaryColor)), - )), + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(top: 15, bottom: 10), + child: Text(widget.getTitle(), + style: (widget.smallTitle + ? Theme.of(context).textTheme.headline6! + : Theme.of(context) + .textTheme + .headline5!) + .copyWith( + color: Theme.of(context).primaryColor)), + ) + ), + widget.cardAction, if (widget.editingMode) Container( alignment: Alignment.center, @@ -136,16 +140,18 @@ class GenericCardState extends State { ))); } + + Widget getDeleteIcon(context) { return Flexible( child: Container( - alignment: Alignment.centerRight, - height: 32, - child: IconButton( - iconSize: 22, - icon: const Icon(Icons.delete), - tooltip: 'Remover', - onPressed: widget.onDelete, + alignment: Alignment.centerRight, + height: 32, + child: IconButton( + iconSize: 22, + icon: const Icon(Icons.delete), + tooltip: 'Remover', + onPressed: widget.onDelete, ), )); } diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index f96fb1038..e96697fb1 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -2,95 +2,50 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/model/entities/restaurant.dart'; -import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:provider/provider.dart'; +import 'package:uni/model/providers/restaurant_provider.dart'; - -class RestaurantPageCard extends StatefulWidget { +class RestaurantPageCard extends GenericCard { final Restaurant restaurant; final Widget meals; - const RestaurantPageCard(this.restaurant, this.meals, {Key ? key}) - : super(key: key); + RestaurantPageCard(this.restaurant, this.meals, {super.key}) + : super.customStyle(editingMode: false, onDelete: () => null, smallTitle: true, cardAction: CardFavoriteButton(restaurant)); + + @override + Widget buildCardContent(BuildContext context) { + return meals; + } + @override - State createState() => RestaurantPageCardState(); + String getTitle() { + return restaurant.name; + } + + @override + onClick(BuildContext context) {} } -class RestaurantPageCardState extends State { +class CardFavoriteButton extends StatelessWidget { + final Restaurant restaurant; + + const CardFavoriteButton(this.restaurant, {super.key}); @override Widget build(BuildContext context) { - final isFavorite = Provider.of(context).favoriteRestaurants.contains(widget.restaurant.name); - return Card( - margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - decoration: const BoxDecoration( - boxShadow: [ - BoxShadow( - color: Color.fromARGB(0x1c, 0, 0, 0), - blurRadius: 7.0, - offset: Offset(0.0, 1.0), - ) - ], - borderRadius: BorderRadius.all(Radius.circular(10.0)), - ), - child: ConstrainedBox( - constraints: const BoxConstraints( - minHeight: 60.0, - ), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).cardColor, - borderRadius: const BorderRadius.all(Radius.circular(10.0)), - ), - width: double.infinity, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric(horizontal: 15), - margin: - const EdgeInsets.only(top: 15, bottom: 10), - child: Text( - widget.restaurant.name, - style: (Theme.of(context).textTheme.headline6!) - .copyWith( - color: - Theme.of(context).primaryColor), - ), - ), - ), - IconButton( - icon: isFavorite ? const Icon(MdiIcons.heart) : const Icon(MdiIcons.heartOutline), - onPressed: () => setState((){ - Provider.of(context, listen: false).toggleFavoriteRestaurant(widget.restaurant.name, Completer()); - })),], - ), - Container( - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - bottom: 12.0, - ), - child: widget.meals, - ) - ], - ), - ), - ), - )); + return Consumer( + builder: (context, restaurantProvider, _){ + final isFavorite = restaurantProvider.favoriteRestaurants.contains(restaurant.name); + return IconButton( + icon: isFavorite ? const Icon(MdiIcons.heart) : const Icon(MdiIcons.heartOutline), + onPressed: () => restaurantProvider.toggleFavoriteRestaurant(restaurant.name, Completer()) + ); + } + ); } -} + +} \ No newline at end of file From d32009bf497b1c8a632628c9e45098058b37c9bc Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 21 Mar 2023 23:58:35 +0000 Subject: [PATCH 008/199] Cleaning codespace --- .../view/restaurant/restaurant_page_view.dart | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 95bb18e34..d0ff7bdf8 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -22,16 +22,6 @@ class RestaurantPageView extends StatefulWidget { class _CantinePageState extends GeneralPageViewState with SingleTickerProviderStateMixin { - final List daysOfTheWeek = [ - DayOfWeek.monday, - DayOfWeek.tuesday, - DayOfWeek.wednesday, - DayOfWeek.thursday, - DayOfWeek.friday, - DayOfWeek.saturday, - DayOfWeek.sunday - ]; - late List aggRestaurant; late TabController tabController; late ScrollController scrollViewController; @@ -41,8 +31,8 @@ class _CantinePageState extends GeneralPageViewState super.initState(); final int weekDay = DateTime.now().weekday; super.initState(); - tabController = TabController(vsync: this, length: daysOfTheWeek.length); - final offset = (weekDay > 5) ? 0 : (weekDay - 1) % daysOfTheWeek.length; + tabController = TabController(vsync: this, length: DayOfWeek.values.length); + final offset = (weekDay > 5) ? 0 : (weekDay - 1) % DayOfWeek.values.length; tabController.animateTo((tabController.index + offset)); scrollViewController = ScrollController(); } @@ -52,7 +42,6 @@ class _CantinePageState extends GeneralPageViewState return Consumer( builder: (context, restaurantProvider, _) => _getPageView(restaurantProvider.restaurants, restaurantProvider.status)); - } Widget _getPageView(List restaurants, RequestStatus? status) { @@ -81,7 +70,7 @@ class _CantinePageState extends GeneralPageViewState } Widget createTabViewBuilder(dynamic restaurants, BuildContext context) { - final List dayContents = daysOfTheWeek.map((dayOfWeek) { + final List dayContents = DayOfWeek.values.map((dayOfWeek) { List cantinesWidgets = []; if (restaurants is List) { cantinesWidgets = restaurants @@ -100,14 +89,12 @@ class _CantinePageState extends GeneralPageViewState List createTabs(BuildContext context) { final List tabs = []; - - for (var i = 0; i < daysOfTheWeek.length; i++) { + for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add(Container( color: Theme.of(context).backgroundColor, - child: Tab(key: Key('cantine-page-tab-$i'), text: toString(daysOfTheWeek[i])), + child: Tab(key: Key('cantine-page-tab-$i'), text: toString(DayOfWeek.values[i])), )); } - return tabs; } From 8faa31db0967b37c86b9f0c94a1b6f771ade30ec Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 23 Mar 2023 09:59:04 +0000 Subject: [PATCH 009/199] Minor fixings --- .../view/home/widgets/restaurant_card.dart | 24 +++---- uni/lib/view/home/widgets/restaurant_row.dart | 69 ------------------- .../view/restaurant/restaurant_page_view.dart | 2 +- 3 files changed, 9 insertions(+), 86 deletions(-) delete mode 100644 uni/lib/view/home/widgets/restaurant_row.dart diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index fc34d1399..81bcbbd68 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:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; @@ -10,19 +11,8 @@ import 'package:uni/model/utils/day_of_week.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; - -final List daysOfTheWeek = [ - DayOfWeek.monday, - DayOfWeek.tuesday, - DayOfWeek.wednesday, - DayOfWeek.thursday, - DayOfWeek.friday, - DayOfWeek.saturday, - DayOfWeek.sunday -]; - final int weekDay = DateTime.now().weekday; -final offset = (weekDay > 5) ? 0 : (weekDay - 1) % daysOfTheWeek.length; +final offset = (weekDay > 5) ? 0 : (weekDay - 1) % DayOfWeek.values.length; class RestaurantCard extends GenericCard { RestaurantCard({Key? key}) : super(key: key); @@ -31,9 +21,8 @@ class RestaurantCard extends GenericCard { Key key, bool editingMode, Function()? onDelete) : super.fromEditingInformation(key, editingMode, onDelete); - @override - String getTitle() => 'Cantinas'; + String getTitle() => 'Restaurantes'; @override onClick(BuildContext context) => null; @@ -71,7 +60,7 @@ class RestaurantCard extends GenericCard { return Column( mainAxisSize: MainAxisSize.min, children: [ - createRowFromRestaurant(context, restaurants[index], daysOfTheWeek[offset]) + createRowFromRestaurant(context, restaurants[index], DayOfWeek.values[offset]) ], ); }, @@ -102,7 +91,10 @@ class RestaurantCard extends GenericCard { color: const Color.fromARGB(0, 0, 0, 0), child: Container( padding: const EdgeInsets.all(12.0), - child: const Text('Refeições não disponíveis')) + child: const SizedBox( + width: 400, + child: Text("Não há refeições disponíveis", textAlign: TextAlign.center), + )) )) ]); } diff --git a/uni/lib/view/home/widgets/restaurant_row.dart b/uni/lib/view/home/widgets/restaurant_row.dart deleted file mode 100644 index 0d7a23589..000000000 --- a/uni/lib/view/home/widgets/restaurant_row.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; - -class RestaurantRow extends StatelessWidget { - final String local; - final String meatMenu; - final String fishMenu; - final String vegetarianMenu; - final String dietMenu; - final double iconSize; - - const RestaurantRow({ - Key? key, - required this.local, - required this.meatMenu, - required this.fishMenu, - required this.vegetarianMenu, - required this.dietMenu, - this.iconSize = 20.0, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.only(left: 12.0, bottom: 8.0, right: 12), - margin: const EdgeInsets.only(top: 8.0), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Column( - children: getMenuRows(context), - )) - ], - ), - ); - } - - List getMenuRows(BuildContext context) { - final List widgets = []; - final List meals = [meatMenu, fishMenu, vegetarianMenu, dietMenu]; - final Map mealIcon = { - meatMenu: MdiIcons.foodDrumstickOutline, - fishMenu: MdiIcons.fish, - vegetarianMenu: MdiIcons.corn, - dietMenu: MdiIcons.nutrition - }; - - for (var element in meals) { - widgets.add(Container( - padding: const EdgeInsets.all(12.0), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - width: 0.7, - color: Theme.of(context).colorScheme.secondary))), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(mealIcon[element], size: iconSize), - Expanded(child: Text(element, textAlign: TextAlign.center)), - ]))); - } - - return widgets; - } -} diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index d0ff7bdf8..4ff21fe27 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -77,7 +77,7 @@ class _CantinePageState extends GeneralPageViewState .map((restaurant) => createRestaurant(context, restaurant, dayOfWeek)) .toList(); } - return ListView( children: cantinesWidgets,); + return ListView(children: cantinesWidgets); }).toList(); return Expanded( From 9b30a28e2480a5af6b98768ebd7a3fee73a11e0b Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 23 Mar 2023 10:44:34 +0000 Subject: [PATCH 010/199] Lint fixing --- uni/lib/view/home/widgets/restaurant_card.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 81bcbbd68..70c5f0041 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; From f4aa5d7964244e7d6338732c911a1071c12d2cd5 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 14 Apr 2023 21:04:17 +0100 Subject: [PATCH 011/199] Initial commit --- uni/lib/generated/intl/messages_all.dart | 67 +++++++++ uni/lib/generated/intl/messages_en.dart | 33 +++++ uni/lib/generated/intl/messages_pt-PT.dart | 33 +++++ uni/lib/generated/intl/messages_pt_PT.dart | 28 ++++ uni/lib/generated/l10n.dart | 129 ++++++++++++++++++ uni/lib/l10n/intl_en.arb | 13 ++ uni/lib/l10n/intl_pt_PT.arb | 13 ++ uni/lib/main.dart | 9 ++ uni/lib/view/common_widgets/generic_card.dart | 4 +- .../widgets/course_unit_card.dart | 2 +- uni/lib/view/exams/exams.dart | 3 +- uni/lib/view/home/widgets/bus_stop_card.dart | 3 +- uni/lib/view/home/widgets/exam_card.dart | 3 +- .../view/home/widgets/main_cards_list.dart | 2 +- .../view/home/widgets/restaurant_card.dart | 3 +- uni/lib/view/home/widgets/schedule_card.dart | 3 +- .../widgets/library_occupation_card.dart | 2 +- .../profile/widgets/account_info_card.dart | 3 +- .../profile/widgets/course_info_card.dart | 2 +- .../view/profile/widgets/print_info_card.dart | 2 +- .../widgets/restaurant_page_card.dart | 2 +- uni/pubspec.yaml | 7 +- 22 files changed, 351 insertions(+), 15 deletions(-) create mode 100644 uni/lib/generated/intl/messages_all.dart create mode 100644 uni/lib/generated/intl/messages_en.dart create mode 100644 uni/lib/generated/intl/messages_pt-PT.dart create mode 100644 uni/lib/generated/intl/messages_pt_PT.dart create mode 100644 uni/lib/generated/l10n.dart create mode 100644 uni/lib/l10n/intl_en.arb create mode 100644 uni/lib/l10n/intl_pt_PT.arb diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart new file mode 100644 index 000000000..171385879 --- /dev/null +++ b/uni/lib/generated/intl/messages_all.dart @@ -0,0 +1,67 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that looks up messages for specific locales by +// delegating to the appropriate library. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:implementation_imports, file_names, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering +// ignore_for_file:argument_type_not_assignable, invalid_assignment +// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases +// ignore_for_file:comment_references + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; +import 'package:intl/src/intl_helpers.dart'; + +import 'messages_en.dart' as messages_en; +import 'messages_pt-PT.dart' as messages_pt_pt; + +typedef Future LibraryLoader(); +Map _deferredLibraries = { + 'en': () => new SynchronousFuture(null), + 'pt_PT': () => new SynchronousFuture(null), +}; + +MessageLookupByLibrary? _findExact(String localeName) { + switch (localeName) { + case 'en': + return messages_en.messages; + case 'pt_PT': + return messages_pt_pt.messages; + default: + return null; + } +} + +/// User programs should call this before using [localeName] for messages. +Future initializeMessages(String localeName) { + var availableLocale = Intl.verifiedLocale( + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); + if (availableLocale == null) { + return new SynchronousFuture(false); + } + var lib = _deferredLibraries[availableLocale]; + lib == null ? new SynchronousFuture(false) : lib(); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); + messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); + return new SynchronousFuture(true); +} + +bool _messagesExistFor(String locale) { + try { + return _findExact(locale) != null; + } catch (e) { + return false; + } +} + +MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { + var actualLocale = + Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + if (actualLocale == null) return null; + return _findExact(actualLocale); +} diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart new file mode 100644 index 000000000..0b46069ec --- /dev/null +++ b/uni/lib/generated/intl/messages_en.dart @@ -0,0 +1,33 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a en locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'en'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "account_card_title": + MessageLookupByLibrary.simpleMessage("Checking account"), + "bus_card_title": MessageLookupByLibrary.simpleMessage("Buses"), + "exam_card_title": MessageLookupByLibrary.simpleMessage("Exams"), + "no_exams": MessageLookupByLibrary.simpleMessage( + "You do not have appointed exams\n"), + "schedule_card_title": MessageLookupByLibrary.simpleMessage("Schedule") + }; +} diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart new file mode 100644 index 000000000..3f7941260 --- /dev/null +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -0,0 +1,33 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a pt_PT locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'pt_PT'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "account_card_title": + MessageLookupByLibrary.simpleMessage("Conta Corrente"), + "bus_card_title": MessageLookupByLibrary.simpleMessage("Autocarros"), + "exam_card_title": MessageLookupByLibrary.simpleMessage("Exames"), + "no_exams": + MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), + "schedule_card_title": MessageLookupByLibrary.simpleMessage("Horário") + }; +} diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart new file mode 100644 index 000000000..2df3e416e --- /dev/null +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -0,0 +1,28 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a pt_PT locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'pt_PT'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "no_exams": + MessageLookupByLibrary.simpleMessage("Não possui exames marcados") + }; +} diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart new file mode 100644 index 000000000..34de502ef --- /dev/null +++ b/uni/lib/generated/l10n.dart @@ -0,0 +1,129 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'intl/messages_all.dart'; + +// ************************************************************************** +// Generator: Flutter Intl IDE plugin +// Made by Localizely +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars +// ignore_for_file: join_return_with_assignment, prefer_final_in_for_each +// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes + +class S { + S(); + + static S? _current; + + static S get current { + assert(_current != null, + 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); + return _current!; + } + + static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); + + static Future load(Locale locale) { + final name = (locale.countryCode?.isEmpty ?? false) + ? locale.languageCode + : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); + return initializeMessages(localeName).then((_) { + Intl.defaultLocale = localeName; + final instance = S(); + S._current = instance; + + return instance; + }); + } + + static S of(BuildContext context) { + final instance = S.maybeOf(context); + assert(instance != null, + 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); + return instance!; + } + + static S? maybeOf(BuildContext context) { + return Localizations.of(context, S); + } + + /// `Checking account` + String get account_card_title { + return Intl.message( + 'Checking account', + name: 'account_card_title', + desc: '', + args: [], + ); + } + + /// `Buses` + String get bus_card_title { + return Intl.message( + 'Buses', + name: 'bus_card_title', + desc: '', + args: [], + ); + } + + /// `Exams` + String get exam_card_title { + return Intl.message( + 'Exams', + name: 'exam_card_title', + desc: '', + args: [], + ); + } + + /// `You do not have appointed exams\n` + String get no_exams { + return Intl.message( + 'You do not have appointed exams\n', + name: 'no_exams', + desc: '', + args: [], + ); + } + + /// `Schedule` + String get schedule_card_title { + return Intl.message( + 'Schedule', + name: 'schedule_card_title', + desc: '', + args: [], + ); + } +} + +class AppLocalizationDelegate extends LocalizationsDelegate { + const AppLocalizationDelegate(); + + List get supportedLocales { + return const [ + Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'pt', countryCode: 'PT'), + ]; + } + + @override + bool isSupported(Locale locale) => _isSupported(locale); + @override + Future load(Locale locale) => S.load(locale); + @override + bool shouldReload(AppLocalizationDelegate old) => false; + + bool _isSupported(Locale locale) { + for (var supportedLocale in supportedLocales) { + if (supportedLocale.languageCode == locale.languageCode) { + return true; + } + } + return false; + } +} diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb new file mode 100644 index 000000000..eea78d8d4 --- /dev/null +++ b/uni/lib/l10n/intl_en.arb @@ -0,0 +1,13 @@ +{ + "@@locale": "en", + "account_card_title": "Checking account", + "@account_card_title": {}, + "bus_card_title": "Buses", + "@bus_card_title": {}, + "exam_card_title": "Exams", + "@exam_card_title": {}, + "no_exams": "You do not have appointed exams\n", + "@no_exams": {}, + "schedule_card_title": "Schedule", + "@schedule_card_title": {} +} \ No newline at end of file diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb new file mode 100644 index 000000000..2744b3608 --- /dev/null +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -0,0 +1,13 @@ +{ + "@@locale": "pt-PT", + "account_card_title": "Conta Corrente", + "@account_card_title": {}, + "bus_card_title": "Autocarros", + "@bus_card_title": {}, + "exam_card_title": "Exames", + "@exam_card_title": {}, + "no_exams": "Não possui exames marcados", + "@no_exams": {}, + "schedule_card_title": "Horário", + "@schedule_card_title": {} +} \ No newline at end of file diff --git a/uni/lib/main.dart b/uni/lib/main.dart index fa5edf566..c170a15aa 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -11,6 +11,8 @@ 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:flutter_localizations/flutter_localizations.dart'; +import 'generated/l10n.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'; @@ -142,6 +144,13 @@ class MyAppState extends State { darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), home: const SplashScreen(), + localizationsDelegates: [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: S.delegate.supportedLocales, navigatorKey: NavigationService.navigatorKey, onGenerateRoute: (RouteSettings settings) { final Map> transitions = { diff --git a/uni/lib/view/common_widgets/generic_card.dart b/uni/lib/view/common_widgets/generic_card.dart index be81dd354..76c97c888 100644 --- a/uni/lib/view/common_widgets/generic_card.dart +++ b/uni/lib/view/common_widgets/generic_card.dart @@ -30,7 +30,7 @@ abstract class GenericCard extends StatefulWidget { Widget buildCardContent(BuildContext context); - String getTitle(); + String getTitle(BuildContext context); dynamic onClick(BuildContext context); @@ -103,7 +103,7 @@ class GenericCardState extends State { alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric(horizontal: 15), margin: const EdgeInsets.only(top: 15, bottom: 10), - child: Text(widget.getTitle(), + child: Text(widget.getTitle(context), style: (widget.smallTitle ? Theme.of(context).textTheme.headline6! : Theme.of(context) 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..7a9da2e69 100644 --- a/uni/lib/view/course_units/widgets/course_unit_card.dart +++ b/uni/lib/view/course_units/widgets/course_unit_card.dart @@ -29,7 +29,7 @@ class CourseUnitCard extends GenericCard { } @override - String getTitle() { + String getTitle(context) { return courseUnit.name.length > maxTitleLength ? '${courseUnit.name.split(' ').sublist(0, 5).join(' ')}...' : courseUnit.name; diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 0d43565fb..390a09d97 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -2,6 +2,7 @@ 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/generated/l10n.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'; @@ -42,7 +43,7 @@ class ExamsPageViewState extends GeneralPageViewState { if (exams.isEmpty) { columns.add(Center( heightFactor: 2, - child: Text('Não possui exames marcados.', + child: Text(S.of(context).no_exams, style: Theme.of(context).textTheme.headline6), )); return columns; diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index 685d31101..ecb83d22e 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -4,6 +4,7 @@ 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/utils/drawer_items.dart'; +import 'package:uni/generated/l10n.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'; @@ -16,7 +17,7 @@ class BusStopCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle() => 'Autocarros'; + String getTitle(BuildContext context) => S.of(context).bus_card_title; @override onClick(BuildContext context) => diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index aa7d4f268..068f9e806 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -7,6 +7,7 @@ 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/generated/l10n.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'; @@ -20,7 +21,7 @@ class ExamCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle() => 'Exames'; + String getTitle(BuildContext context) => S.of(context).exam_card_title; @override onClick(BuildContext context) => diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index ee2fa9c63..401f5cde4 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -116,7 +116,7 @@ class MainCardsList extends StatelessWidget { decoration: const BoxDecoration(), child: ListTile( title: Text( - e.value(Key(e.key.index.toString()), false, null).getTitle(), + e.value(Key(e.key.index.toString()), false, null).getTitle(context), textAlign: TextAlign.center, ), onTap: () { diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 69255adfa..cddd6cc14 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -2,6 +2,7 @@ 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/generated/l10n.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'; @@ -15,7 +16,7 @@ class RestaurantCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle() => 'Cantinas'; + String getTitle(context) => 'Cantinas'; @override onClick(BuildContext context) => null; diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index 2ba31b108..d8c9511c7 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -2,6 +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/generated/l10n.dart'; import 'package:uni/model/providers/lecture_provider.dart'; import 'package:uni/view/common_widgets/date_rectangle.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; @@ -105,7 +106,7 @@ class ScheduleCard extends GenericCard { } @override - String getTitle() => 'Horário'; + String getTitle(context) => S.of(context).schedule_card_title; @override onClick(BuildContext context) => diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index 966d9c71d..f4745f800 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -16,7 +16,7 @@ class LibraryOccupationCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle() => 'Ocupação da Biblioteca'; + String getTitle(context) => 'Ocupação da Biblioteca'; @override onClick(BuildContext context) => diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index e690f0baf..4b952c676 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -3,6 +3,7 @@ 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/profile/widgets/tuition_notification_switch.dart'; +import 'package:uni/generated/l10n.dart'; /// Manages the 'Current account' section inside the user's page (accessible /// through the top-right widget with the user picture) @@ -69,7 +70,7 @@ class AccountInfoCard extends GenericCard { } @override - String getTitle() => 'Conta Corrente'; + String getTitle(context) => S.of(context).account_card_title; @override onClick(BuildContext context) {} diff --git a/uni/lib/view/profile/widgets/course_info_card.dart b/uni/lib/view/profile/widgets/course_info_card.dart index 4c2b14476..68dcbcdc6 100644 --- a/uni/lib/view/profile/widgets/course_info_card.dart +++ b/uni/lib/view/profile/widgets/course_info_card.dart @@ -97,7 +97,7 @@ class CourseInfoCard extends GenericCard { } @override - String getTitle() { + String getTitle(context) { return course.name ?? 'Curso sem nome'; } diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index c30e87e37..f97ebeca2 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -60,7 +60,7 @@ class PrintInfoCard extends GenericCard { } @override - String getTitle() => 'Impressões'; + String getTitle(context) => 'Impressões'; @override onClick(BuildContext context) {} diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index 9dbfd2773..2c86aee67 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -13,7 +13,7 @@ class RestaurantPageCard extends GenericCard { } @override - String getTitle() { + String getTitle(context) { return restaurantName; } diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index d0b897829..ca53121bc 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -35,6 +35,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter html: ^0.15.0 http: ^0.13.0 tuple: ^2.0.0 @@ -165,5 +167,8 @@ flutter_icons: image_path: "assets/icon/icon.png" adaptive_icon_background: "#75171E" adaptive_icon_foreground: "assets/icon/android_icon_foreground.png" - +flutter_intl: + enabled: true + localizely: + project_id: 788a209d-5f55-4f7d-ad09-6033b2b65fc1 From e7aa34f6dbc04e4179628ab4fea18fdeefbe5a2e Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 19 Apr 2023 23:33:34 +0100 Subject: [PATCH 012/199] Main page and navigation drawer translation --- uni/lib/generated/intl/messages_all.dart | 6 +- uni/lib/generated/intl/messages_en.dart | 54 ++++- uni/lib/generated/intl/messages_pt-PT.dart | 52 ++++- uni/lib/generated/intl/messages_pt_PT.dart | 28 --- uni/lib/generated/l10n.dart | 211 +++++++++++++++++- uni/lib/l10n/intl_en.arb | 50 ++++- uni/lib/l10n/intl_pt_PT.arb | 48 +++- uni/lib/main.dart | 4 +- uni/lib/model/entities/exam.dart | 64 +++--- uni/lib/model/entities/time_utilities.dart | 28 ++- uni/lib/utils/drawer_items.dart | 24 +- uni/lib/view/common_widgets/generic_card.dart | 3 +- .../common_widgets/last_update_timestamp.dart | 3 +- .../general/widgets/navigation_drawer.dart | 7 +- uni/lib/view/home/widgets/bus_stop_card.dart | 10 +- uni/lib/view/home/widgets/exam_card.dart | 12 +- .../view/home/widgets/main_cards_list.dart | 15 +- .../view/home/widgets/restaurant_card.dart | 1 - .../profile/widgets/account_info_card.dart | 6 +- 19 files changed, 517 insertions(+), 109 deletions(-) delete mode 100644 uni/lib/generated/intl/messages_pt_PT.dart diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 171385879..d06573802 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -38,13 +38,13 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) { - var availableLocale = Intl.verifiedLocale( + final availableLocale = Intl.verifiedLocale( localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { return new SynchronousFuture(false); } - var lib = _deferredLibraries[availableLocale]; + final lib = _deferredLibraries[availableLocale]; lib == null ? new SynchronousFuture(false) : lib(); initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); @@ -60,7 +60,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var actualLocale = + final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 0b46069ec..b3f9e5563 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -20,14 +20,64 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; + static String m0(time) => "last refresh at ${time}"; + + static String m1(time) => + "${Intl.plural(time, one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + + static String m2(title) => "${Intl.select(title, { + 'horario': 'Schedule', + 'exames': 'Exams', + 'area': 'Personal Area', + 'cadeiras': 'Course Units', + 'autocarros': 'Buses', + 'locais': 'Places', + 'restaurantes': 'Restaurants', + 'calendario': 'Calendar', + 'biblioteca': 'Library', + 'uteis': 'Utils', + 'sobre': 'About', + 'bugs': 'Bugs and Suggestions', + 'other': 'Other', + })}"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "account_card_title": MessageLookupByLibrary.simpleMessage("Checking account"), + "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), + "all_widgets_added": MessageLookupByLibrary.simpleMessage( + "All available widgets have already been added to your personal area!"), + "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bus_card_title": MessageLookupByLibrary.simpleMessage("Buses"), + "bus_error": + MessageLookupByLibrary.simpleMessage("Unable to get information"), + "buses_personalize": + MessageLookupByLibrary.simpleMessage("Personalize your buses here"), + "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), + "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), + "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "exam_card_title": MessageLookupByLibrary.simpleMessage("Exams"), + "fee_date": + MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), + "fee_notification": + MessageLookupByLibrary.simpleMessage("Notify next deadline:"), + "last_refresh_time": m0, + "last_timestamp": m1, + "logout": MessageLookupByLibrary.simpleMessage("Log out"), + "nav_title": m2, + "no_data": MessageLookupByLibrary.simpleMessage( + "There is no data to show at this time"), "no_exams": MessageLookupByLibrary.simpleMessage( - "You do not have appointed exams\n"), - "schedule_card_title": MessageLookupByLibrary.simpleMessage("Schedule") + "You have no exams scheduled\n"), + "no_selected_exams": MessageLookupByLibrary.simpleMessage( + "There are no exams to present"), + "restaurant_card_title": + MessageLookupByLibrary.simpleMessage("Restaurants"), + "schedule_card_title": MessageLookupByLibrary.simpleMessage("Schedule"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Choose a widget to add to your personal area:") }; } diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 3f7941260..3c93a7011 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -20,14 +20,64 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt_PT'; + static String m0(time) => "última atualização às ${time}"; + + static String m1(time) => + "${Intl.plural(time, one: '${time} minuto', other: '${time} minutos')}"; + + static String m2(title) => "${Intl.select(title, { + 'horario': 'Horário', + 'exames': 'Exames', + 'area': 'Área Pessoal', + 'cadeiras': 'Cadeiras', + 'autocarros': 'Autocarros', + 'locais': 'Locais', + 'restaurantes': 'Restaurantes', + 'calendario': 'Calendário', + 'biblioteca': 'Biblioteca', + 'uteis': 'Úteis', + 'sobre': 'Sobre', + 'bugs': 'Bugs e Sugestões', + 'other': 'Outros', + })}"; + final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { "account_card_title": MessageLookupByLibrary.simpleMessage("Conta Corrente"), + "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), + "all_widgets_added": MessageLookupByLibrary.simpleMessage( + "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), + "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bus_card_title": MessageLookupByLibrary.simpleMessage("Autocarros"), + "bus_error": MessageLookupByLibrary.simpleMessage( + "Não foi possível obter informação"), + "buses_personalize": MessageLookupByLibrary.simpleMessage( + "Configura aqui os teus autocarros"), + "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), + "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), + "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "exam_card_title": MessageLookupByLibrary.simpleMessage("Exames"), + "fee_date": MessageLookupByLibrary.simpleMessage( + "Data limite próxima prestação:"), + "fee_notification": MessageLookupByLibrary.simpleMessage( + "Notificar próxima data limite:"), + "last_refresh_time": m0, + "last_timestamp": m1, + "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), + "nav_title": m2, + "no_data": MessageLookupByLibrary.simpleMessage( + "Não há dados a mostrar neste momento"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), - "schedule_card_title": MessageLookupByLibrary.simpleMessage("Horário") + "no_selected_exams": MessageLookupByLibrary.simpleMessage( + "Não existem exames para apresentar"), + "restaurant_card_title": + MessageLookupByLibrary.simpleMessage("Restaurantes"), + "schedule_card_title": MessageLookupByLibrary.simpleMessage("Horário"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Escolhe um widget para adicionares à tua área pessoal:") }; } diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart deleted file mode 100644 index 2df3e416e..000000000 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ /dev/null @@ -1,28 +0,0 @@ -// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart -// This is a library that provides messages for a pt_PT locale. All the -// messages from the main program should be duplicated here with the same -// function name. - -// Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new -// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering -// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes -// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes - -import 'package:intl/intl.dart'; -import 'package:intl/message_lookup_by_library.dart'; - -final messages = new MessageLookup(); - -typedef String MessageIfAbsent(String messageStr, List args); - -class MessageLookup extends MessageLookupByLibrary { - String get localeName => 'pt_PT'; - - final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { - "no_exams": - MessageLookupByLibrary.simpleMessage("Não possui exames marcados") - }; -} diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 34de502ef..cd42ec413 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -60,6 +60,36 @@ class S { ); } + /// `Add widget` + String get add_widget { + return Intl.message( + 'Add widget', + name: 'add_widget', + desc: '', + args: [], + ); + } + + /// `All available widgets have already been added to your personal area!` + String get all_widgets_added { + return Intl.message( + 'All available widgets have already been added to your personal area!', + name: 'all_widgets_added', + desc: '', + args: [], + ); + } + + /// `Balance:` + String get balance { + return Intl.message( + 'Balance:', + name: 'balance', + desc: '', + args: [], + ); + } + /// `Buses` String get bus_card_title { return Intl.message( @@ -70,6 +100,56 @@ class S { ); } + /// `Unable to get information` + String get bus_error { + return Intl.message( + 'Unable to get information', + name: 'bus_error', + desc: '', + args: [], + ); + } + + /// `Personalize your buses here` + String get buses_personalize { + return Intl.message( + 'Personalize your buses here', + name: 'buses_personalize', + desc: '', + args: [], + ); + } + + /// `Cancel` + String get cancel { + return Intl.message( + 'Cancel', + name: 'cancel', + desc: '', + args: [], + ); + } + + /// `Edit` + String get edit_off { + return Intl.message( + 'Edit', + name: 'edit_off', + desc: '', + args: [], + ); + } + + /// `Finish editing` + String get edit_on { + return Intl.message( + 'Finish editing', + name: 'edit_on', + desc: '', + args: [], + ); + } + /// `Exams` String get exam_card_title { return Intl.message( @@ -80,16 +160,123 @@ class S { ); } - /// `You do not have appointed exams\n` + /// `Deadline for next fee:` + String get fee_date { + return Intl.message( + 'Deadline for next fee:', + name: 'fee_date', + desc: '', + args: [], + ); + } + + /// `Notify next deadline:` + String get fee_notification { + return Intl.message( + 'Notify next deadline:', + name: 'fee_notification', + desc: '', + args: [], + ); + } + + /// `last refresh at {time}` + String last_refresh_time(Object time) { + return Intl.message( + 'last refresh at $time', + name: 'last_refresh_time', + desc: '', + args: [time], + ); + } + + /// `{time, plural, one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}` + String last_timestamp(num time) { + return Intl.plural( + time, + one: 'Refreshed $time minute ago', + other: 'Refreshed $time minutes ago', + name: 'last_timestamp', + desc: '', + args: [time], + ); + } + + /// `Log out` + String get logout { + return Intl.message( + 'Log out', + name: 'logout', + desc: '', + args: [], + ); + } + + /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}` + String nav_title(Object title) { + return Intl.select( + title, + { + 'horario': 'Schedule', + 'exames': 'Exams', + 'area': 'Personal Area', + 'cadeiras': 'Course Units', + 'autocarros': 'Buses', + 'locais': 'Places', + 'restaurantes': 'Restaurants', + 'calendario': 'Calendar', + 'biblioteca': 'Library', + 'uteis': 'Utils', + 'sobre': 'About', + 'bugs': 'Bugs and Suggestions', + 'other': 'Other', + }, + name: 'nav_title', + desc: '', + args: [title], + ); + } + + /// `There is no data to show at this time` + String get no_data { + return Intl.message( + 'There is no data to show at this time', + name: 'no_data', + desc: '', + args: [], + ); + } + + /// `You have no exams scheduled\n` String get no_exams { return Intl.message( - 'You do not have appointed exams\n', + 'You have no exams scheduled\n', name: 'no_exams', desc: '', args: [], ); } + /// `There are no exams to present` + String get no_selected_exams { + return Intl.message( + 'There are no exams to present', + name: 'no_selected_exams', + desc: '', + args: [], + ); + } + + /// `Restaurants` + String get restaurant_card_title { + return Intl.message( + 'Restaurants', + name: 'restaurant_card_title', + desc: '', + args: [], + ); + } + /// `Schedule` String get schedule_card_title { return Intl.message( @@ -99,6 +286,26 @@ class S { args: [], ); } + + /// `STCP - Upcoming Trips` + String get stcp_stops { + return Intl.message( + 'STCP - Upcoming Trips', + name: 'stcp_stops', + desc: '', + args: [], + ); + } + + /// `Choose a widget to add to your personal area:` + String get widget_prompt { + return Intl.message( + 'Choose a widget to add to your personal area:', + name: 'widget_prompt', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index eea78d8d4..8f48675c6 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -2,12 +2,58 @@ "@@locale": "en", "account_card_title": "Checking account", "@account_card_title": {}, + "add_widget": "Add widget", + "@add_widget": {}, + "all_widgets_added": "All available widgets have already been added to your personal area!", + "@all_widgets_added": {}, + "balance": "Balance:", + "@balance": {}, "bus_card_title": "Buses", "@bus_card_title": {}, + "bus_error": "Unable to get information", + "@bus_error": {}, + "buses_personalize": "Personalize your buses here", + "@buses_personalize": {}, + "cancel": "Cancel", + "@cancel": {}, + "edit_off": "Edit", + "@edit_off": {}, + "edit_on": "Finish editing", + "@edit_on": {}, "exam_card_title": "Exams", "@exam_card_title": {}, - "no_exams": "You do not have appointed exams\n", + "fee_date": "Deadline for next fee:", + "@fee_date": {}, + "fee_notification": "Notify next deadline:", + "@fee_notification": {}, + "last_refresh_time": "last refresh at {time}", + "@last_refresh_time": { + "placeholders": { + "time": {} + } + }, + "last_timestamp": "{time, plural, one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}", + "@last_timestamp": { + "placeholders": { + "time": {} + } + }, + "logout": "Log out", + "@logout": {}, + "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}", + "@nav_title": {}, + "no_data": "There is no data to show at this time", + "@no_data": {}, + "no_exams": "You have no exams scheduled\n", "@no_exams": {}, + "no_selected_exams": "There are no exams to present", + "@no_selected_exams": {}, + "restaurant_card_title": "Restaurants", + "@restaurant_card_title": {}, "schedule_card_title": "Schedule", - "@schedule_card_title": {} + "@schedule_card_title": {}, + "stcp_stops": "STCP - Upcoming Trips", + "@stcp_stops": {}, + "widget_prompt": "Choose a widget to add to your personal area:", + "@widget_prompt": {} } \ No newline at end of file diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 2744b3608..f698d58f2 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -2,12 +2,58 @@ "@@locale": "pt-PT", "account_card_title": "Conta Corrente", "@account_card_title": {}, + "add_widget": "Adicionar widget", + "@add_widget": {}, + "all_widgets_added": "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", + "@all_widgets_added": {}, + "balance": "Saldo:", + "@balance": {}, "bus_card_title": "Autocarros", "@bus_card_title": {}, + "bus_error": "Não foi possível obter informação", + "@bus_error": {}, + "buses_personalize": "Configura aqui os teus autocarros", + "@buses_personalize": {}, + "cancel": "Cancelar\n", + "@cancel": {}, + "edit_off": "Editar\n", + "@edit_off": {}, + "edit_on": "Concluir edição", + "@edit_on": {}, "exam_card_title": "Exames", "@exam_card_title": {}, + "fee_date": "Data limite próxima prestação:", + "@fee_date": {}, + "fee_notification": "Notificar próxima data limite:", + "@fee_notification": {}, + "last_refresh_time": "última atualização às {time}", + "@last_refresh_time": { + "placeholders": { + "time": {} + } + }, + "last_timestamp": "{time, plural, one{{time} minuto} other{{time} minutos}}", + "@last_timestamp": { + "placeholders": { + "time": {} + } + }, + "logout": "Terminar sessão", + "@logout": {}, + "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} sobre{Sobre} bugs{Bugs e Sugestões} other{Outros}}", + "@nav_title": {}, + "no_data": "Não há dados a mostrar neste momento", + "@no_data": {}, "no_exams": "Não possui exames marcados", "@no_exams": {}, + "no_selected_exams": "Não existem exames para apresentar", + "@no_selected_exams": {}, + "restaurant_card_title": "Restaurantes", + "@restaurant_card_title": {}, "schedule_card_title": "Horário", - "@schedule_card_title": {} + "@schedule_card_title": {}, + "stcp_stops": "STCP - Próximas Viagens", + "@stcp_stops": {}, + "widget_prompt": "Escolhe um widget para adicionares à tua área pessoal:", + "@widget_prompt": {} } \ No newline at end of file diff --git a/uni/lib/main.dart b/uni/lib/main.dart index c170a15aa..353ac3a0c 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -12,7 +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:flutter_localizations/flutter_localizations.dart'; -import 'generated/l10n.dart'; +import 'package:uni/generated/l10n.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'; @@ -144,7 +144,7 @@ class MyAppState extends State { darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), home: const SplashScreen(), - localizationsDelegates: [ + localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index 9dce8c199..bf696bfb6 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -1,35 +1,39 @@ +import 'dart:io'; + import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; enum WeekDays { - monday("Segunda"), - tuesday("Terça"), - wednesday("Quarta"), - thursday("Quinta"), - friday("Sexta"), - saturday("Sábado"), - sunday("Domingo"); - - final String day; - const WeekDays(this.day); + monday("Segunda", "Monday"), + tuesday("Terça", "Tuesday"), + wednesday("Quarta", "Wednesday"), + thursday("Quinta", "Thursday"), + friday("Sexta", "Friday"), + saturday("Sábado", "Saturday"), + sunday("Domingo", "Sunday"); + + final String dayPT; + final String dayEN; + const WeekDays(this.dayPT, this.dayEN); } enum Months { - january("janeiro"), - february("fevereiro"), - march("março"), - april("abril"), - may("maio"), - june("junho"), - july("julho"), - august("agosto"), - september("setembro"), - october("outubro"), - november("novembro"), - december("dezembro"); - - final String month; - const Months(this.month); + january("janeiro", "January"), + february("fevereiro", "February"), + march("março", "March"), + april("abril", "April"), + may("maio", "May"), + june("junho", "June"), + july("julho", "July"), + august("agosto", "August"), + september("setembro", "September"), + october("outubro", "October"), + november("novembro", "November"), + december("dezembro", "December"); + + final String monthPT; + final String monthEN; + const Months(this.monthPT, this.monthEN); } /// Manages a generic Exam. @@ -83,9 +87,15 @@ class Exam { /// Returns whether or not this exam has already ended. bool hasEnded() => DateTime.now().compareTo(end) >= 0; - String get weekDay => WeekDays.values[begin.weekday - 1].day; + String get weekDay{ + if(Platform.localeName == 'pt_PT') return WeekDays.values[begin.weekday - 1].dayPT; + return WeekDays.values[begin.weekday - 1].dayEN; + } - String get month => Months.values[begin.month - 1].month; + String get month{ + if(Platform.localeName == 'pt_PT') return Months.values[begin.month - 1].monthPT; + return Months.values[begin.weekday - 1].monthEN; + } String get beginTime => formatTime(begin); diff --git a/uni/lib/model/entities/time_utilities.dart b/uni/lib/model/entities/time_utilities.dart index 9180392b8..6a9d2727d 100644 --- a/uni/lib/model/entities/time_utilities.dart +++ b/uni/lib/model/entities/time_utilities.dart @@ -1,10 +1,13 @@ +import 'dart:io'; + extension TimeString on DateTime { String toTimeHourMinString() { return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; } static List getWeekdaysStrings({bool startMonday = true, bool includeWeekend = true}) { - final List weekdays = [ + + final List weekdaysPT = [ 'Segunda-Feira', 'Terça-Feira', 'Quarta-Feira', @@ -14,11 +17,28 @@ extension TimeString on DateTime { 'Domingo' ]; + final List weekdaysEN = [ + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday' + ]; + + final String locale = Platform.localeName; + if (!startMonday) { - weekdays.removeAt(6); - weekdays.insert(0, 'Domingo'); + weekdaysPT.removeAt(6); + weekdaysEN.removeAt(6); + weekdaysPT.insert(0, 'Domingo'); + weekdaysEN.insert(0, 'Sunday'); } - return includeWeekend ? weekdays : weekdays.sublist(0, 5); + if(locale == 'pt_PT') return includeWeekend ? weekdaysPT : weekdaysPT.sublist(0, 5); + return includeWeekend ? weekdaysEN : weekdaysEN.sublist(0, 5); + + } } diff --git a/uni/lib/utils/drawer_items.dart b/uni/lib/utils/drawer_items.dart index a9580353c..e9bfce583 100644 --- a/uni/lib/utils/drawer_items.dart +++ b/uni/lib/utils/drawer_items.dart @@ -1,16 +1,16 @@ enum DrawerItem { - navPersonalArea('Área Pessoal'), - navSchedule('Horário'), - navExams('Exames'), - navCourseUnits('Cadeiras'), - navStops('Autocarros'), - navLocations('Locais', faculties: {'feup'}), - navRestaurants('Restaurantes'), - navCalendar('Calendário'), - navLibrary('Biblioteca', faculties: {'feup'}), - navUsefulInfo('Úteis', faculties: {'feup'}), - navAbout('Sobre'), - navBugReport('Bugs e Sugestões'), + navPersonalArea('area'), + navSchedule('horario'), + navExams('exames'), + navCourseUnits('cadeiras'), + navStops('autocarros'), + navLocations('locais', faculties: {'feup'}), + navRestaurants('restaurantes'), + navCalendar('calendario'), + navLibrary('biblioteca', faculties: {'feup'}), + navUsefulInfo('uteis', faculties: {'feup'}), + navAbout('sobre'), + navBugReport('bugs'), navLogOut('Terminar sessão'); final String title; diff --git a/uni/lib/view/common_widgets/generic_card.dart b/uni/lib/view/common_widgets/generic_card.dart index 76c97c888..4c6ae0344 100644 --- a/uni/lib/view/common_widgets/generic_card.dart +++ b/uni/lib/view/common_widgets/generic_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/time_utilities.dart'; +import 'package:uni/generated/l10n.dart'; /// App default card abstract class GenericCard extends StatefulWidget { @@ -52,7 +53,7 @@ abstract class GenericCard extends StatefulWidget { return Container( alignment: Alignment.center, - child: Text('última atualização às ${parsedTime.toTimeHourMinString()}', + child: Text(S.of(context).last_refresh_time(parsedTime.toTimeHourMinString()), style: Theme.of(context).textTheme.caption)); } } diff --git a/uni/lib/view/common_widgets/last_update_timestamp.dart b/uni/lib/view/common_widgets/last_update_timestamp.dart index 23617e16e..2935a261e 100644 --- a/uni/lib/view/common_widgets/last_update_timestamp.dart +++ b/uni/lib/view/common_widgets/last_update_timestamp.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:uni/generated/l10n.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/providers/last_user_info_provider.dart'; @@ -52,7 +53,7 @@ class _LastUpdateTimeStampState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - 'Atualizado há $elapsedTimeMinutes minuto${elapsedTimeMinutes != 1 ? 's' : ''}', + S.of(context).last_timestamp(elapsedTimeMinutes), style: Theme.of(context).textTheme.subtitle2) ]); } 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 ac5e65da2..15be8ee7c 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 @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/theme_notifier.dart'; +import 'package:uni/generated/l10n.dart'; class AppNavigationDrawer extends StatefulWidget { final BuildContext parentContext; @@ -65,7 +66,7 @@ class AppNavigationDrawerState extends State { } Widget createLogoutBtn() { - final String logOutText = DrawerItem.navLogOut.title; + final String logOutText = S.of(context).logout; return TextButton( onPressed: () => _onLogOut(logOutText), style: TextButton.styleFrom( @@ -110,8 +111,8 @@ class AppNavigationDrawerState extends State { child: ListTile( title: Container( padding: const EdgeInsets.only(bottom: 3.0, left: 20.0), - child: Text(d.title, - style: TextStyle( + child: Text(S.of(context).nav_title(d.title), + style: TextStyle( fontSize: 18.0, color: Theme.of(context).primaryColor, fontWeight: FontWeight.normal)), diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index ecb83d22e..f4160c078 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -48,7 +48,7 @@ Widget getCardContent(BuildContext context, Map stopData, b child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('Configura os teus autocarros', + Text(S.of(context).buses_personalize, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.subtitle2!.apply()), @@ -77,7 +77,7 @@ Widget getCardContent(BuildContext context, Map stopData, b getCardTitle(context), Container( padding: const EdgeInsets.all(8.0), - child: Text('Não foi possível obter informação', + child: Text(S.of(context).bus_error, style: Theme.of(context).textTheme.subtitle1)) ]); } @@ -88,7 +88,7 @@ Widget getCardTitle(context) { return Row( children: [ const Icon(Icons.directions_bus), // color lightgrey - Text('STCP - Próximas Viagens', + Text(S.of(context).stcp_stops, style: Theme.of(context).textTheme.subtitle1), ], ); @@ -103,8 +103,8 @@ Widget getBusStopsInfo(context, Map stopData) { children: getEachBusStopInfo(context, stopData), )); } else { - return const Center( - child: Text('Não há dados a mostrar neste momento', + return Center( + child: Text(S.of(context).no_data, maxLines: 2, overflow: TextOverflow.fade), ); } diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 068f9e806..91919c228 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/entities/exam.dart'; @@ -46,7 +48,7 @@ class ExamCard extends GenericCard { content: exams, contentChecker: exams.isNotEmpty, onNullContent: Center( - child: Text('Não existem exames para apresentar', + child: Text(S.of(context).no_selected_exams, style: Theme.of(context).textTheme.headline6), ), contentLoadingWidget: const ExamCardShimmer().build(context), @@ -89,8 +91,12 @@ class ExamCard extends GenericCard { /// others in the card). Widget createRowFromExam(BuildContext context, Exam exam) { return Column(children: [ - DateRectangle( - date: '${exam.weekDay}, ${exam.begin.day} de ${exam.month}'), + if (Platform.localeName == 'pt_PT') ...[ + DateRectangle( + date: '${exam.weekDay}, ${exam.begin.day} de ${exam.month}')] + else ...[ + DateRectangle( + date: '${exam.weekDay}, ${exam.begin.day} ${exam.month}')], RowContainer( child: ExamRow( exam: exam, diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index 401f5cde4..f3b373c60 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.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'; @@ -13,7 +14,6 @@ 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/schedule_card.dart'; -import 'package:uni/utils/drawer_items.dart'; typedef CardCreator = GenericCard Function( Key key, bool isEditingMode, dynamic Function()? onDelete); @@ -84,7 +84,7 @@ class MainCardsList extends StatelessWidget { builder: (BuildContext context) { return AlertDialog( title: Text( - 'Escolhe um widget para adicionares à tua área pessoal:', + S.of(context).widget_prompt, style: Theme.of(context).textTheme.headline5), content: SizedBox( height: 200.0, @@ -93,12 +93,12 @@ class MainCardsList extends StatelessWidget { ), actions: [ TextButton( - child: Text('Cancelar', + child: Text(S.of(context).cancel, style: Theme.of(context).textTheme.bodyText2), onPressed: () => Navigator.pop(context)) ]); }), //Add FAB functionality here - tooltip: 'Adicionar widget', + tooltip: S.of(context).add_widget, child: Icon(Icons.add, color: Theme.of(context).colorScheme.onPrimary), ); } @@ -129,8 +129,7 @@ class MainCardsList extends StatelessWidget { return possibleCardAdditions.isEmpty ? [ - const Text( - '''Todos os widgets disponíveis já foram adicionados à tua área pessoal!''') + Text(S.of(context).all_widgets_added) ] : possibleCardAdditions; } @@ -141,13 +140,13 @@ class MainCardsList extends StatelessWidget { padding: const EdgeInsets.fromLTRB(20, 20, 20, 5), child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ PageTitle( - name: DrawerItem.navPersonalArea.title, center: false, pad: false), + name: S.of(context).nav_title('area'), center: false, pad: false), GestureDetector( onTap: () => Provider.of(context, listen: false) .setHomePageEditingMode(!editingModeProvider.isEditing), child: Text( - editingModeProvider.isEditing ? 'Concluir Edição' : 'Editar', + editingModeProvider.isEditing ? S.of(context).edit_on : S.of(context).edit_off, style: Theme.of(context).textTheme.caption)) ]), ); diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index cddd6cc14..eaca0ed75 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -2,7 +2,6 @@ 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/generated/l10n.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'; diff --git a/uni/lib/view/profile/widgets/account_info_card.dart b/uni/lib/view/profile/widgets/account_info_card.dart index 4b952c676..2ea8ae081 100644 --- a/uni/lib/view/profile/widgets/account_info_card.dart +++ b/uni/lib/view/profile/widgets/account_info_card.dart @@ -28,7 +28,7 @@ class AccountInfoCard extends GenericCard { Container( margin: const EdgeInsets.only( top: 20.0, bottom: 8.0, left: 20.0), - child: Text('Saldo: ', + child: Text(S.of(context).balance, style: Theme.of(context).textTheme.subtitle2), ), Container( @@ -40,7 +40,7 @@ class AccountInfoCard extends GenericCard { Container( margin: const EdgeInsets.only( top: 8.0, bottom: 20.0, left: 20.0), - child: Text('Data limite próxima prestação: ', + child: Text(S.of(context).fee_date, style: Theme.of(context).textTheme.subtitle2), ), Container( @@ -52,7 +52,7 @@ class AccountInfoCard extends GenericCard { Container( margin: const EdgeInsets.only(top: 8.0, bottom: 20.0, left: 20.0), - child: Text("Notificar próxima data limite: ", + child: Text(S.of(context).fee_notification, style: Theme.of(context).textTheme.subtitle2) ), Container( From 503fdbda417bc6b00c10005aa2f3ba1594bb9feb Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 19 Apr 2023 23:40:47 +0100 Subject: [PATCH 013/199] Error and lint fixing --- uni/lib/generated/intl/messages_all.dart | 6 +++--- uni/lib/generated/intl/messages_pt-PT.dart | 2 +- uni/lib/l10n/intl_pt_PT.arb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index d06573802..171385879 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -38,13 +38,13 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) { - final availableLocale = Intl.verifiedLocale( + var availableLocale = Intl.verifiedLocale( localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { return new SynchronousFuture(false); } - final lib = _deferredLibraries[availableLocale]; + var lib = _deferredLibraries[availableLocale]; lib == null ? new SynchronousFuture(false) : lib(); initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); @@ -60,7 +60,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = + var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 3c93a7011..ba426a450 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -23,7 +23,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(time) => "última atualização às ${time}"; static String m1(time) => - "${Intl.plural(time, one: '${time} minuto', other: '${time} minutos')}"; + "${Intl.plural(time, one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; static String m2(title) => "${Intl.select(title, { 'horario': 'Horário', diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index f698d58f2..4ec03fc74 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -32,7 +32,7 @@ "time": {} } }, - "last_timestamp": "{time, plural, one{{time} minuto} other{{time} minutos}}", + "last_timestamp": "{time, plural, one{Atualizado há {time} minuto} other{Atualizado há {time} minutos}}", "@last_timestamp": { "placeholders": { "time": {} From 6ae272146680e22a42055e97253a206a246a3d1b Mon Sep 17 00:00:00 2001 From: Diogo Martins <81827192+DGoiana@users.noreply.github.com> Date: Wed, 19 Apr 2023 23:42:03 +0100 Subject: [PATCH 014/199] Update messages_all.dart --- uni/lib/generated/intl/messages_all.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 171385879..97b06cb2c 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -16,8 +16,8 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'messages_en.dart' as messages_en; -import 'messages_pt-PT.dart' as messages_pt_pt; +import 'package:uni/generated/intl/messages_en.dart' as messages_en; +import 'package:uni/generated/intl/messages_pt-PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { From fd3a3d148ac0ae6f4b49ab11f07d5583d7808dfd Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 20 Apr 2023 12:08:29 +0100 Subject: [PATCH 015/199] Buses page translation --- uni/lib/generated/intl/messages_all.dart | 6 +- uni/lib/generated/intl/messages_en.dart | 27 +++- uni/lib/generated/intl/messages_pt-PT.dart | 27 +++- uni/lib/generated/l10n.dart | 137 ++++++++++++++---- uni/lib/l10n/intl_en.arb | 36 +++-- uni/lib/l10n/intl_pt_PT.arb | 36 +++-- .../bus_stop_next_arrivals.dart | 4 +- .../bus_stop_selection.dart | 11 +- .../widgets/bus_stop_search.dart | 11 +- uni/lib/view/course_units/course_units.dart | 11 +- .../view/exams/widgets/exam_page_title.dart | 8 +- uni/lib/view/home/widgets/bus_stop_card.dart | 2 +- uni/lib/view/home/widgets/exam_card.dart | 2 +- uni/lib/view/home/widgets/schedule_card.dart | 2 +- uni/lib/view/schedule/schedule.dart | 3 +- 15 files changed, 234 insertions(+), 89 deletions(-) diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 97b06cb2c..525f677ec 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -38,13 +38,13 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) { - var availableLocale = Intl.verifiedLocale( + final availableLocale = Intl.verifiedLocale( localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { return new SynchronousFuture(false); } - var lib = _deferredLibraries[availableLocale]; + final lib = _deferredLibraries[availableLocale]; lib == null ? new SynchronousFuture(false) : lib(); initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); @@ -60,7 +60,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var actualLocale = + final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index b3f9e5563..4ad58118e 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -23,7 +23,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(time) => "last refresh at ${time}"; static String m1(time) => - "${Intl.plural(time, one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; static String m2(title) => "${Intl.select(title, { 'horario': 'Schedule', @@ -45,19 +45,28 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "account_card_title": MessageLookupByLibrary.simpleMessage("Checking account"), + "add": MessageLookupByLibrary.simpleMessage("Add"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "All available widgets have already been added to your personal area!"), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), - "bus_card_title": MessageLookupByLibrary.simpleMessage("Buses"), "bus_error": MessageLookupByLibrary.simpleMessage("Unable to get information"), + "bus_information": MessageLookupByLibrary.simpleMessage( + "Select the buses you want information about:"), "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), + "buses_text": MessageLookupByLibrary.simpleMessage( + "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page."), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), + "conclude": MessageLookupByLibrary.simpleMessage("Done"), + "configured_buses": + MessageLookupByLibrary.simpleMessage("Configured Buses"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), - "exam_card_title": MessageLookupByLibrary.simpleMessage("Exams"), + "exams_filter": + MessageLookupByLibrary.simpleMessage("Exam Filter Settings"), "fee_date": MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), "fee_notification": @@ -66,18 +75,22 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "logout": MessageLookupByLibrary.simpleMessage("Log out"), "nav_title": m2, + "no_course_units": MessageLookupByLibrary.simpleMessage( + "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( "There is no data to show at this time"), "no_exams": MessageLookupByLibrary.simpleMessage( "You have no exams scheduled\n"), + "no_results": MessageLookupByLibrary.simpleMessage("No match"), + "no_selected_courses": MessageLookupByLibrary.simpleMessage( + "There are no course units to display"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "There are no exams to present"), - "restaurant_card_title": - MessageLookupByLibrary.simpleMessage("Restaurants"), - "schedule_card_title": MessageLookupByLibrary.simpleMessage("Schedule"), + "semester": MessageLookupByLibrary.simpleMessage("Semester"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:") + "Choose a widget to add to your personal area:"), + "year": MessageLookupByLibrary.simpleMessage("Year") }; } diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index ba426a450..864d0c121 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -23,7 +23,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m0(time) => "última atualização às ${time}"; static String m1(time) => - "${Intl.plural(time, one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; static String m2(title) => "${Intl.select(title, { 'horario': 'Horário', @@ -45,19 +45,28 @@ class MessageLookup extends MessageLookupByLibrary { static Map _notInlinedMessages(_) => { "account_card_title": MessageLookupByLibrary.simpleMessage("Conta Corrente"), + "add": MessageLookupByLibrary.simpleMessage("Adicionar"), "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), - "bus_card_title": MessageLookupByLibrary.simpleMessage("Autocarros"), "bus_error": MessageLookupByLibrary.simpleMessage( "Não foi possível obter informação"), + "bus_information": MessageLookupByLibrary.simpleMessage( + "Seleciona os autocarros dos quais queres informação:"), "buses_personalize": MessageLookupByLibrary.simpleMessage( "Configura aqui os teus autocarros"), + "buses_text": MessageLookupByLibrary.simpleMessage( + "Os autocarros favoritos serão apresentados no widget \'Autocarros\' dos favoritos. Os restantes serão apresentados apenas na página."), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), + "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), + "configured_buses": + MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), - "exam_card_title": MessageLookupByLibrary.simpleMessage("Exames"), + "exams_filter": + MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), "fee_date": MessageLookupByLibrary.simpleMessage( "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( @@ -66,18 +75,22 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "nav_title": m2, + "no_course_units": MessageLookupByLibrary.simpleMessage( + "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( "Não há dados a mostrar neste momento"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), + "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), + "no_selected_courses": MessageLookupByLibrary.simpleMessage( + "Não existem cadeiras para apresentar"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "Não existem exames para apresentar"), - "restaurant_card_title": - MessageLookupByLibrary.simpleMessage("Restaurantes"), - "schedule_card_title": MessageLookupByLibrary.simpleMessage("Horário"), + "semester": MessageLookupByLibrary.simpleMessage("Semestre"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:") + "Escolhe um widget para adicionares à tua área pessoal:"), + "year": MessageLookupByLibrary.simpleMessage("Ano") }; } diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index cd42ec413..129b6e382 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'intl/messages_all.dart'; +import 'package:uni/generated/intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -60,6 +60,16 @@ class S { ); } + /// `Add` + String get add { + return Intl.message( + 'Add', + name: 'add', + desc: '', + args: [], + ); + } + /// `Add widget` String get add_widget { return Intl.message( @@ -90,16 +100,6 @@ class S { ); } - /// `Buses` - String get bus_card_title { - return Intl.message( - 'Buses', - name: 'bus_card_title', - desc: '', - args: [], - ); - } - /// `Unable to get information` String get bus_error { return Intl.message( @@ -120,6 +120,26 @@ class S { ); } + /// `Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.` + String get buses_text { + return Intl.message( + 'Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.', + name: 'buses_text', + desc: '', + args: [], + ); + } + + /// `Select the buses you want information about:` + String get bus_information { + return Intl.message( + 'Select the buses you want information about:', + name: 'bus_information', + desc: '', + args: [], + ); + } + /// `Cancel` String get cancel { return Intl.message( @@ -130,6 +150,36 @@ class S { ); } + /// `Done` + String get conclude { + return Intl.message( + 'Done', + name: 'conclude', + desc: '', + args: [], + ); + } + + /// `Configured Buses` + String get configured_buses { + return Intl.message( + 'Configured Buses', + name: 'configured_buses', + desc: '', + args: [], + ); + } + + /// `Confirm` + String get confirm { + return Intl.message( + 'Confirm', + name: 'confirm', + desc: '', + args: [], + ); + } + /// `Edit` String get edit_off { return Intl.message( @@ -150,11 +200,11 @@ class S { ); } - /// `Exams` - String get exam_card_title { + /// `Exam Filter Settings` + String get exams_filter { return Intl.message( - 'Exams', - name: 'exam_card_title', + 'Exam Filter Settings', + name: 'exams_filter', desc: '', args: [], ); @@ -190,10 +240,11 @@ class S { ); } - /// `{time, plural, one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}` + /// `{time, plural, zero{Refreshed {time} minutes ago} one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}` String last_timestamp(num time) { return Intl.plural( time, + zero: 'Refreshed $time minutes ago', one: 'Refreshed $time minute ago', other: 'Refreshed $time minutes ago', name: 'last_timestamp', @@ -237,6 +288,16 @@ class S { ); } + /// `No course units in the selected period` + String get no_course_units { + return Intl.message( + 'No course units in the selected period', + name: 'no_course_units', + desc: '', + args: [], + ); + } + /// `There is no data to show at this time` String get no_data { return Intl.message( @@ -257,31 +318,41 @@ class S { ); } - /// `There are no exams to present` - String get no_selected_exams { + /// `No match` + String get no_results { return Intl.message( - 'There are no exams to present', - name: 'no_selected_exams', + 'No match', + name: 'no_results', desc: '', args: [], ); } - /// `Restaurants` - String get restaurant_card_title { + /// `There are no course units to display` + String get no_selected_courses { return Intl.message( - 'Restaurants', - name: 'restaurant_card_title', + 'There are no course units to display', + name: 'no_selected_courses', desc: '', args: [], ); } - /// `Schedule` - String get schedule_card_title { + /// `There are no exams to present` + String get no_selected_exams { return Intl.message( - 'Schedule', - name: 'schedule_card_title', + 'There are no exams to present', + name: 'no_selected_exams', + desc: '', + args: [], + ); + } + + /// `Semester` + String get semester { + return Intl.message( + 'Semester', + name: 'semester', desc: '', args: [], ); @@ -306,6 +377,16 @@ class S { args: [], ); } + + /// `Year` + String get year { + return Intl.message( + 'Year', + name: 'year', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 8f48675c6..2984a64ff 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -2,26 +2,36 @@ "@@locale": "en", "account_card_title": "Checking account", "@account_card_title": {}, + "add": "Add", + "@add": {}, "add_widget": "Add widget", "@add_widget": {}, "all_widgets_added": "All available widgets have already been added to your personal area!", "@all_widgets_added": {}, "balance": "Balance:", "@balance": {}, - "bus_card_title": "Buses", - "@bus_card_title": {}, "bus_error": "Unable to get information", "@bus_error": {}, "buses_personalize": "Personalize your buses here", "@buses_personalize": {}, + "buses_text": "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", + "@buses_text": {}, + "bus_information": "Select the buses you want information about:", + "@bus_information": {}, "cancel": "Cancel", "@cancel": {}, + "conclude": "Done", + "@conclude": {}, + "configured_buses": "Configured Buses", + "@configured_buses": {}, + "confirm": "Confirm", + "@confirm": {}, "edit_off": "Edit", "@edit_off": {}, "edit_on": "Finish editing", "@edit_on": {}, - "exam_card_title": "Exams", - "@exam_card_title": {}, + "exams_filter": "Exam Filter Settings", + "@exams_filter": {}, "fee_date": "Deadline for next fee:", "@fee_date": {}, "fee_notification": "Notify next deadline:", @@ -32,7 +42,7 @@ "time": {} } }, - "last_timestamp": "{time, plural, one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}", + "last_timestamp": "{time, plural, zero{Refreshed {time} minutes ago} one{Refreshed {time} minute ago} other{Refreshed {time} minutes ago}}", "@last_timestamp": { "placeholders": { "time": {} @@ -42,18 +52,24 @@ "@logout": {}, "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}", "@nav_title": {}, + "no_course_units": "No course units in the selected period", + "@no_course_units": {}, "no_data": "There is no data to show at this time", "@no_data": {}, "no_exams": "You have no exams scheduled\n", "@no_exams": {}, + "no_results": "No match", + "@no_results": {}, + "no_selected_courses": "There are no course units to display", + "@no_selected_courses": {}, "no_selected_exams": "There are no exams to present", "@no_selected_exams": {}, - "restaurant_card_title": "Restaurants", - "@restaurant_card_title": {}, - "schedule_card_title": "Schedule", - "@schedule_card_title": {}, + "semester": "Semester", + "@semester": {}, "stcp_stops": "STCP - Upcoming Trips", "@stcp_stops": {}, "widget_prompt": "Choose a widget to add to your personal area:", - "@widget_prompt": {} + "@widget_prompt": {}, + "year": "Year", + "@year": {} } \ No newline at end of file diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 4ec03fc74..962d9e75b 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -2,26 +2,36 @@ "@@locale": "pt-PT", "account_card_title": "Conta Corrente", "@account_card_title": {}, + "add": "Adicionar", + "@add": {}, "add_widget": "Adicionar widget", "@add_widget": {}, "all_widgets_added": "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", "@all_widgets_added": {}, "balance": "Saldo:", "@balance": {}, - "bus_card_title": "Autocarros", - "@bus_card_title": {}, "bus_error": "Não foi possível obter informação", "@bus_error": {}, "buses_personalize": "Configura aqui os teus autocarros", "@buses_personalize": {}, + "buses_text": "Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. Os restantes serão apresentados apenas na página.", + "@buses_text": {}, + "bus_information": "Seleciona os autocarros dos quais queres informação:", + "@bus_information": {}, "cancel": "Cancelar\n", "@cancel": {}, + "conclude": "Concluído", + "@conclude": {}, + "configured_buses": "Autocarros Configurados", + "@configured_buses": {}, + "confirm": "Confirmar", + "@confirm": {}, "edit_off": "Editar\n", "@edit_off": {}, "edit_on": "Concluir edição", "@edit_on": {}, - "exam_card_title": "Exames", - "@exam_card_title": {}, + "exams_filter": "Definições Filtro de Exames", + "@exams_filter": {}, "fee_date": "Data limite próxima prestação:", "@fee_date": {}, "fee_notification": "Notificar próxima data limite:", @@ -32,7 +42,7 @@ "time": {} } }, - "last_timestamp": "{time, plural, one{Atualizado há {time} minuto} other{Atualizado há {time} minutos}}", + "last_timestamp": "{time, plural, zero{Atualizado há {time} minutos} one{Atualizado há {time} minuto} other{Atualizado há {time} minutos}}", "@last_timestamp": { "placeholders": { "time": {} @@ -42,18 +52,24 @@ "@logout": {}, "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} sobre{Sobre} bugs{Bugs e Sugestões} other{Outros}}", "@nav_title": {}, + "no_course_units": "Sem cadeiras no período selecionado", + "@no_course_units": {}, "no_data": "Não há dados a mostrar neste momento", "@no_data": {}, "no_exams": "Não possui exames marcados", "@no_exams": {}, + "no_results": "Sem resultados", + "@no_results": {}, + "no_selected_courses": "Não existem cadeiras para apresentar", + "@no_selected_courses": {}, "no_selected_exams": "Não existem exames para apresentar", "@no_selected_exams": {}, - "restaurant_card_title": "Restaurantes", - "@restaurant_card_title": {}, - "schedule_card_title": "Horário", - "@schedule_card_title": {}, + "semester": "Semestre", + "@semester": {}, "stcp_stops": "STCP - Próximas Viagens", "@stcp_stops": {}, "widget_prompt": "Escolhe um widget para adicionares à tua área pessoal:", - "@widget_prompt": {} + "@widget_prompt": {}, + "year": "Ano", + "@year": {} } \ No newline at end of file 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 5d9b5142f..2f666a051 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 @@ -2,6 +2,8 @@ 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/utils/drawer_items.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/providers/bus_stop_provider.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'; @@ -107,7 +109,7 @@ class NextArrivalsState extends State { Container getPageTitle() { return Container( padding: const EdgeInsets.only(bottom: 12.0), - child: const PageTitle(name: 'Autocarros')); + child: PageTitle(name: S.of(context).nav_title(DrawerItem.navStops.title))); } /// Returns a list of widgets for a failed request 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..b100b346c 100644 --- a/uni/lib/view/bus_stop_selection/bus_stop_selection.dart +++ b/uni/lib/view/bus_stop_selection/bus_stop_selection.dart @@ -2,6 +2,7 @@ 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/generated/l10n.dart'; import 'package:uni/model/providers/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'; @@ -45,12 +46,10 @@ class BusStopSelectionPageState bottom: 20, ), children: [ - const PageTitle(name: 'Autocarros Configurados'), + PageTitle(name: S.of(context).configured_buses), Container( padding: const EdgeInsets.all(20.0), - child: const Text( - '''Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos.''' - '''Os restantes serão apresentados apenas na página.''', + child: Text( S.of(context).buses_text, textAlign: TextAlign.center)), Column(children: rows), Container( @@ -62,11 +61,11 @@ class BusStopSelectionPageState ElevatedButton( onPressed: () => showSearch( context: context, delegate: BusStopSearch()), - child: const Text('Adicionar'), + child: Text(S.of(context).add), ), ElevatedButton( onPressed: () => Navigator.pop(context), - child: const Text('Concluído'), + child: Text(S.of(context).conclude), ), ])) ]); 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 88b58ae68..3ffc07a6e 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,6 +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/generated/l10n.dart'; import 'package:uni/model/providers/bus_stop_provider.dart'; import 'package:uni/view/bus_stop_selection/widgets/form.dart'; @@ -83,7 +84,7 @@ class BusStopSearch extends SearchDelegate { onNonMatch: (m) => ''), updateStopCallback); return AlertDialog( - title: Text('Seleciona os autocarros dos quais queres informação:', + title: Text(S.of(context).bus_information, style: Theme.of(context).textTheme.headline5), content: SizedBox( height: 200.0, @@ -92,11 +93,11 @@ class BusStopSearch extends SearchDelegate { ), actions: [ TextButton( - child: Text('Cancelar', + child: Text(S.of(context).cancel, style: Theme.of(context).textTheme.bodyText2), onPressed: () => Navigator.pop(context)), ElevatedButton( - child: const Text('Confirmar'), + child: Text(S.of(context).confirm), onPressed: () async { if (stopData!.configuredBuses.isNotEmpty) { Provider.of(context, listen: false) @@ -125,8 +126,8 @@ class BusStopSearch extends SearchDelegate { return Container( margin: const EdgeInsets.all(8.0), height: 24.0, - child: const Center( - child: Text('Sem resultados.'), + child: Center( + child: Text(S.of(context).no_results), )); } else { suggestionsList = snapshot.data!; diff --git a/uni/lib/view/course_units/course_units.dart b/uni/lib/view/course_units/course_units.dart index d45b605ce..16320b4d5 100644 --- a/uni/lib/view/course_units/course_units.dart +++ b/uni/lib/view/course_units/course_units.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.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'; @@ -86,7 +87,7 @@ class CourseUnitsPageViewState contentChecker: courseUnits?.isNotEmpty ?? false, onNullContent: Center( heightFactor: 10, - child: Text('Não existem cadeiras para apresentar', + child: Text(S.of(context).no_selected_courses, style: Theme.of(context).textTheme.headline6), )) ]); @@ -97,12 +98,12 @@ class CourseUnitsPageViewState return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ - PageTitle(name: DrawerItem.navCourseUnits.title), + PageTitle(name: S.of(context).nav_title(DrawerItem.navCourseUnits.title)), const Spacer(), DropdownButtonHideUnderline( child: DropdownButton( alignment: AlignmentDirectional.centerEnd, - disabledHint: const Text('Semestre'), + disabledHint: Text(S.of(context).semester), value: selectedSemester, icon: const Icon(Icons.arrow_drop_down), onChanged: (String? newValue) { @@ -119,7 +120,7 @@ class CourseUnitsPageViewState const SizedBox(width: 10), DropdownButtonHideUnderline( child: DropdownButton( - disabledHint: const Text('Ano'), + disabledHint: Text(S.of(context).year), value: selectedSchoolYear, icon: const Icon(Icons.arrow_drop_down), onChanged: (String? newValue) { @@ -141,7 +142,7 @@ class CourseUnitsPageViewState if ((courseUnits as List).isEmpty) { return Center( heightFactor: 10, - child: Text('Sem cadeiras no período selecionado', + child: Text(S.of(context).no_course_units, style: Theme.of(context).textTheme.headline6)); } return Expanded( diff --git a/uni/lib/view/exams/widgets/exam_page_title.dart b/uni/lib/view/exams/widgets/exam_page_title.dart index 32769c369..148494973 100644 --- a/uni/lib/view/exams/widgets/exam_page_title.dart +++ b/uni/lib/view/exams/widgets/exam_page_title.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/exams/widgets/exam_filter_menu.dart'; import 'package:uni/view/common_widgets/page_title.dart'; +import 'package:uni/generated/l10n.dart'; class ExamPageTitle extends StatelessWidget { const ExamPageTitle({Key? key}) : super(key: key); @@ -12,9 +14,9 @@ class ExamPageTitle extends StatelessWidget { alignment: Alignment.center, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: const [ - PageTitle(name: 'Exames', center: false, pad: false), - Material(child: ExamFilterMenu()), + children: [ + PageTitle(name: S.of(context).nav_title(DrawerItem.navExams.title), center: false, pad: false), + const Material(child: ExamFilterMenu()), ], ), ); diff --git a/uni/lib/view/home/widgets/bus_stop_card.dart b/uni/lib/view/home/widgets/bus_stop_card.dart index f4160c078..ffcb7609a 100644 --- a/uni/lib/view/home/widgets/bus_stop_card.dart +++ b/uni/lib/view/home/widgets/bus_stop_card.dart @@ -17,7 +17,7 @@ class BusStopCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle(BuildContext context) => S.of(context).bus_card_title; + String getTitle(BuildContext context) => S.of(context).nav_title(DrawerItem.navStops.title); @override onClick(BuildContext context) => diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 91919c228..4fab0dfa0 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -23,7 +23,7 @@ class ExamCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle(BuildContext context) => S.of(context).exam_card_title; + String getTitle(BuildContext context) => S.of(context).nav_title(DrawerItem.navExams.title); @override onClick(BuildContext context) => diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index d8c9511c7..c165aab06 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -106,7 +106,7 @@ class ScheduleCard extends GenericCard { } @override - String getTitle(context) => S.of(context).schedule_card_title; + String getTitle(context) => S.of(context).nav_title(DrawerItem.navSchedule.title); @override onClick(BuildContext context) => diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 954e6c9c6..81d77c0e1 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -4,6 +4,7 @@ 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/generated/l10n.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'; @@ -92,7 +93,7 @@ class SchedulePageViewState extends GeneralPageViewState scrollDirection: Axis.vertical, shrinkWrap: true, children: [ - PageTitle(name: DrawerItem.navSchedule.title), + PageTitle(name: S.of(context).nav_title(DrawerItem.navSchedule.title)), TabBar( controller: tabController, isScrollable: true, From 1140560d199b7c1e6558b5a5f0adbb474cec6759 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 26 Apr 2023 14:53:42 +0100 Subject: [PATCH 016/199] Library and restaurants pages translated --- uni/lib/generated/intl/messages_en.dart | 10 +++ uni/lib/generated/intl/messages_pt-PT.dart | 10 +++ uni/lib/generated/l10n.dart | 70 +++++++++++++++++++ uni/lib/l10n/intl_en.arb | 14 ++++ uni/lib/l10n/intl_pt_PT.arb | 14 ++++ uni/lib/view/library/library.dart | 8 ++- .../widgets/library_occupation_card.dart | 3 +- .../view/restaurant/restaurant_page_view.dart | 13 ++-- 8 files changed, 133 insertions(+), 9 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 4ad58118e..272a24d0c 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -71,9 +71,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), "fee_notification": MessageLookupByLibrary.simpleMessage("Notify next deadline:"), + "floor": MessageLookupByLibrary.simpleMessage("Floor"), + "floors": MessageLookupByLibrary.simpleMessage("Floors"), "last_refresh_time": m0, "last_timestamp": m1, + "library": MessageLookupByLibrary.simpleMessage("Library"), + "library_occupation": + MessageLookupByLibrary.simpleMessage("Library Occupation"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), + "menus": MessageLookupByLibrary.simpleMessage("Menus"), "nav_title": m2, "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period"), @@ -81,6 +87,10 @@ class MessageLookup extends MessageLookupByLibrary { "There is no data to show at this time"), "no_exams": MessageLookupByLibrary.simpleMessage( "You have no exams scheduled\n"), + "no_menu_info": MessageLookupByLibrary.simpleMessage( + "There is no information available about meals"), + "no_menus": MessageLookupByLibrary.simpleMessage( + "There are no meals available"), "no_results": MessageLookupByLibrary.simpleMessage("No match"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( "There are no course units to display"), diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 864d0c121..70ba3a2a7 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -71,9 +71,15 @@ class MessageLookup extends MessageLookupByLibrary { "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( "Notificar próxima data limite:"), + "floor": MessageLookupByLibrary.simpleMessage("Piso"), + "floors": MessageLookupByLibrary.simpleMessage("Pisos"), "last_refresh_time": m0, "last_timestamp": m1, + "library": MessageLookupByLibrary.simpleMessage("Biblioteca"), + "library_occupation": + MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), + "menus": MessageLookupByLibrary.simpleMessage("Ementas"), "nav_title": m2, "no_course_units": MessageLookupByLibrary.simpleMessage( "Sem cadeiras no período selecionado"), @@ -81,6 +87,10 @@ class MessageLookup extends MessageLookupByLibrary { "Não há dados a mostrar neste momento"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), + "no_menu_info": MessageLookupByLibrary.simpleMessage( + "Não há informação disponível sobre refeições"), + "no_menus": MessageLookupByLibrary.simpleMessage( + "Não há refeições disponíveis"), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( "Não existem cadeiras para apresentar"), diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 129b6e382..6767d7e46 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -230,6 +230,26 @@ class S { ); } + /// `Floor` + String get floor { + return Intl.message( + 'Floor', + name: 'floor', + desc: '', + args: [], + ); + } + + /// `Floors` + String get floors { + return Intl.message( + 'Floors', + name: 'floors', + desc: '', + args: [], + ); + } + /// `last refresh at {time}` String last_refresh_time(Object time) { return Intl.message( @@ -253,6 +273,26 @@ class S { ); } + /// `Library` + String get library { + return Intl.message( + 'Library', + name: 'library', + desc: '', + args: [], + ); + } + + /// `Library Occupation` + String get library_occupation { + return Intl.message( + 'Library Occupation', + name: 'library_occupation', + desc: '', + args: [], + ); + } + /// `Log out` String get logout { return Intl.message( @@ -263,6 +303,16 @@ class S { ); } + /// `Menus` + String get menus { + return Intl.message( + 'Menus', + name: 'menus', + desc: '', + args: [], + ); + } + /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}` String nav_title(Object title) { return Intl.select( @@ -318,6 +368,26 @@ class S { ); } + /// `There is no information available about meals` + String get no_menu_info { + return Intl.message( + 'There is no information available about meals', + name: 'no_menu_info', + desc: '', + args: [], + ); + } + + /// `There are no meals available` + String get no_menus { + return Intl.message( + 'There are no meals available', + name: 'no_menus', + desc: '', + args: [], + ); + } + /// `No match` String get no_results { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 2984a64ff..d2488eeec 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -36,6 +36,10 @@ "@fee_date": {}, "fee_notification": "Notify next deadline:", "@fee_notification": {}, + "floor": "Floor", + "@floor": {}, + "floors": "Floors", + "@floors": {}, "last_refresh_time": "last refresh at {time}", "@last_refresh_time": { "placeholders": { @@ -48,8 +52,14 @@ "time": {} } }, + "library": "Library", + "@library": {}, + "library_occupation": "Library Occupation", + "@library_occupation": {}, "logout": "Log out", "@logout": {}, + "menus": "Menus", + "@menus": {}, "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}", "@nav_title": {}, "no_course_units": "No course units in the selected period", @@ -58,6 +68,10 @@ "@no_data": {}, "no_exams": "You have no exams scheduled\n", "@no_exams": {}, + "no_menu_info": "There is no information available about meals", + "@no_menu_info": {}, + "no_menus": "There are no meals available", + "@no_menus": {}, "no_results": "No match", "@no_results": {}, "no_selected_courses": "There are no course units to display", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 962d9e75b..60fb93236 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -36,6 +36,10 @@ "@fee_date": {}, "fee_notification": "Notificar próxima data limite:", "@fee_notification": {}, + "floor": "Piso", + "@floor": {}, + "floors": "Pisos", + "@floors": {}, "last_refresh_time": "última atualização às {time}", "@last_refresh_time": { "placeholders": { @@ -48,8 +52,14 @@ "time": {} } }, + "library": "Biblioteca", + "@library": {}, + "library_occupation": "Ocupação da Biblioteca", + "@library_occupation": {}, "logout": "Terminar sessão", "@logout": {}, + "menus": "Ementas", + "@menus": {}, "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} sobre{Sobre} bugs{Bugs e Sugestões} other{Outros}}", "@nav_title": {}, "no_course_units": "Sem cadeiras no período selecionado", @@ -58,6 +68,10 @@ "@no_data": {}, "no_exams": "Não possui exames marcados", "@no_exams": {}, + "no_menu_info": "Não há informação disponível sobre refeições", + "@no_menu_info": {}, + "no_menus": "Não há refeições disponíveis", + "@no_menus": {}, "no_results": "Sem resultados", "@no_results": {}, "no_selected_courses": "Não existem cadeiras para apresentar", diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index 228110583..16632292c 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -5,6 +5,8 @@ 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/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/library/widgets/library_occupation_card.dart'; class LibraryPageView extends StatefulWidget { @@ -49,9 +51,9 @@ class LibraryPage extends StatelessWidget { scrollDirection: Axis.vertical, shrinkWrap: true, children: [ - const PageTitle(name: 'Biblioteca'), + PageTitle(name: S.of(context).nav_title(DrawerItem.navLibrary.title)), LibraryOccupationCard(), - if (occupation != null) const PageTitle(name: 'Pisos'), + if (occupation != null) PageTitle(name: S.of(context).floors), if (occupation != null) getFloorRows(context, occupation!), ]); } @@ -93,7 +95,7 @@ class LibraryPage extends StatelessWidget { ]), child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Text('Piso ${floor.number}', + Text('${S.of(context).floor} ${floor.number}', style: Theme.of(context).textTheme.headline5), Text('${floor.percentage}%', style: Theme.of(context).textTheme.headline6), diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index f4745f800..f730e445f 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -6,6 +6,7 @@ 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/generated/l10n.dart'; /// Manages the library card section inside the personal area. class LibraryOccupationCard extends GenericCard { @@ -16,7 +17,7 @@ class LibraryOccupationCard extends GenericCard { : super.fromEditingInformation(key, editingMode, onDelete); @override - String getTitle(context) => 'Ocupação da Biblioteca'; + String getTitle(context) => S.of(context).library_occupation; @override onClick(BuildContext context) => diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index aeafcf5fd..fd6bc6a30 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -1,11 +1,13 @@ import 'package:provider/provider.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:flutter/material.dart'; +import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/restaurant_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/model/utils/day_of_week.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; @@ -49,7 +51,7 @@ class _CanteenPageState extends GeneralPageViewState Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), alignment: Alignment.center, - child: const PageTitle(name: 'Ementas', center: false, pad: false), + child: PageTitle(name: S.of(context).menus , center: false, pad: false), ), TabBar( controller: tabController, @@ -64,7 +66,7 @@ class _CanteenPageState extends GeneralPageViewState contentGenerator: createTabViewBuilder, content: restaurants, contentChecker: restaurants.isNotEmpty, - onNullContent: const Center(child: Text('Não há refeições disponíveis.'))) + onNullContent: Center(child: Text(S.of(context).no_menus))) ]); } @@ -87,12 +89,14 @@ class _CanteenPageState extends GeneralPageViewState } List createTabs(BuildContext context) { + final List daysOfTheWeek = + TimeString.getWeekdaysStrings(includeWeekend: true); final List tabs = []; for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add(Container( color: Theme.of(context).backgroundColor, - child: Tab(key: Key('cantine-page-tab-$i'), text: toString(DayOfWeek.values[i])), + child: Tab(key: Key('cantine-page-tab-$i'), text: daysOfTheWeek[i]), )); } @@ -119,8 +123,7 @@ class _CanteenPageState extends GeneralPageViewState key: Key('cantine-page-day-column-$day'), child: Column( mainAxisSize: MainAxisSize.min, - children: - const [Center (child: Text("Não há informação disponível sobre refeições")),], + children: [Center (child: Text(S.of(context).no_menu_info)),], ) ); } else { From 2c746cac5911295a7045aa179469ca77a45901bc Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 2 May 2023 13:01:28 +0100 Subject: [PATCH 017/199] Name changes --- uni/lib/view/home/widgets/restaurant_card.dart | 4 ++-- uni/lib/view/restaurant/restaurant_page_view.dart | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 70c5f0041..a5f52cea2 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -33,7 +33,7 @@ class RestaurantCard extends GenericCard { return RequestDependentWidgetBuilder( context: context, status: restaurantProvider.status, - contentGenerator: generateRestaurant, + contentGenerator: generateRestaurants, content: favoriteRestaurants, contentChecker: favoriteRestaurants.isNotEmpty, onNullContent: Column(children: [ @@ -49,7 +49,7 @@ class RestaurantCard extends GenericCard { });} - Widget generateRestaurant(dynamic data, BuildContext context) { + Widget generateRestaurants(dynamic data, BuildContext context) { final List restaurants = data; return ListView.builder( shrinkWrap: true, diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 4ff21fe27..903c64ad0 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -16,10 +16,10 @@ class RestaurantPageView extends StatefulWidget { const RestaurantPageView({Key? key}) : super(key: key); @override - State createState() => _CantinePageState(); + State createState() => _RestaurantPageViewState(); } -class _CantinePageState extends GeneralPageViewState +class _RestaurantPageViewState extends GeneralPageViewState with SingleTickerProviderStateMixin { late List aggRestaurant; @@ -50,7 +50,7 @@ class _CantinePageState extends GeneralPageViewState Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), alignment: Alignment.center, - child: const PageTitle(name: 'Ementas', center: false, pad: false), + child: const PageTitle(name: 'Restaurantes', center: false, pad: false), ), TabBar( controller: tabController, @@ -71,13 +71,13 @@ class _CantinePageState extends GeneralPageViewState Widget createTabViewBuilder(dynamic restaurants, BuildContext context) { final List dayContents = DayOfWeek.values.map((dayOfWeek) { - List cantinesWidgets = []; + List restaurantsWidgets = []; if (restaurants is List) { - cantinesWidgets = restaurants + restaurantsWidgets = restaurants .map((restaurant) => createRestaurant(context, restaurant, dayOfWeek)) .toList(); } - return ListView(children: cantinesWidgets); + return ListView(children: restaurantsWidgets); }).toList(); return Expanded( From 449d780a48acd0a829c1152c6baf7e1caaf67e78 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sat, 17 Jun 2023 16:29:12 +0100 Subject: [PATCH 018/199] Utils page translation --- uni/lib/generated/intl/messages_en.dart | 33 ++- uni/lib/generated/intl/messages_pt-PT.dart | 31 ++- uni/lib/generated/l10n.dart | 194 ++++++++++++++++-- uni/lib/l10n/intl_en.arb | 40 +++- uni/lib/l10n/intl_pt_PT.arb | 38 +++- uni/lib/utils/duration_string_formatter.dart | 46 +++++ .../generic_expansion_card.dart | 4 +- uni/lib/view/useful_info/useful_info.dart | 4 +- .../widgets/academic_services_card.dart | 12 +- .../useful_info/widgets/copy_center_card.dart | 10 +- .../useful_info/widgets/dona_bia_card.dart | 10 +- .../useful_info/widgets/infodesk_card.dart | 10 +- .../widgets/multimedia_center_card.dart | 10 +- .../useful_info/widgets/other_links_card.dart | 7 +- .../widgets/sigarra_links_card.dart | 17 +- 15 files changed, 411 insertions(+), 55 deletions(-) create mode 100644 uni/lib/utils/duration_string_formatter.dart diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 272a24d0c..af42487cb 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -37,12 +37,14 @@ class MessageLookup extends MessageLookupByLibrary { 'biblioteca': 'Library', 'uteis': 'Utils', 'sobre': 'About', - 'bugs': 'Bugs and Suggestions', + 'bugs': 'Bugs/ Suggestions', 'other': 'Other', })}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { + "academic_services": + MessageLookupByLibrary.simpleMessage("Academic services"), "account_card_title": MessageLookupByLibrary.simpleMessage("Checking account"), "add": MessageLookupByLibrary.simpleMessage("Add"), @@ -59,10 +61,19 @@ class MessageLookup extends MessageLookupByLibrary { "buses_text": MessageLookupByLibrary.simpleMessage( "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page."), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), + "class_registration": + MessageLookupByLibrary.simpleMessage("Class Registration"), "conclude": MessageLookupByLibrary.simpleMessage("Done"), "configured_buses": MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), + "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), + "copy_center_building": MessageLookupByLibrary.simpleMessage( + "Floor -1 of building B | AEFEUP building"), + "dona_bia": MessageLookupByLibrary.simpleMessage( + "D. Beatriz\'s stationery store"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Floor -1 of building B (B-142)"), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "exams_filter": @@ -73,14 +84,20 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Notify next deadline:"), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), + "geral_registration": + MessageLookupByLibrary.simpleMessage("General Registration"), + "improvement_registration": + MessageLookupByLibrary.simpleMessage("Enrollment for Improvement"), "last_refresh_time": m0, "last_timestamp": m1, - "library": MessageLookupByLibrary.simpleMessage("Library"), "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), + "multimedia_center": + MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, + "news": MessageLookupByLibrary.simpleMessage("News"), "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -96,9 +113,21 @@ class MessageLookup extends MessageLookupByLibrary { "There are no course units to display"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "There are no exams to present"), + "other_links": MessageLookupByLibrary.simpleMessage("Other links"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "print": MessageLookupByLibrary.simpleMessage("Print"), + "room": MessageLookupByLibrary.simpleMessage("Room"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("School Calendar"), "semester": MessageLookupByLibrary.simpleMessage("Semester"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "tele_assistance": + MessageLookupByLibrary.simpleMessage("Telephone assistance"), + "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( + "Face-to-face and telephone assistance"), + "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Choose a widget to add to your personal area:"), "year": MessageLookupByLibrary.simpleMessage("Year") diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 70ba3a2a7..8b5b6c33a 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -43,6 +43,8 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { + "academic_services": + MessageLookupByLibrary.simpleMessage("Serviços académicos"), "account_card_title": MessageLookupByLibrary.simpleMessage("Conta Corrente"), "add": MessageLookupByLibrary.simpleMessage("Adicionar"), @@ -59,10 +61,19 @@ class MessageLookup extends MessageLookupByLibrary { "buses_text": MessageLookupByLibrary.simpleMessage( "Os autocarros favoritos serão apresentados no widget \'Autocarros\' dos favoritos. Os restantes serão apresentados apenas na página."), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), + "class_registration": + MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), + "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), + "copy_center_building": MessageLookupByLibrary.simpleMessage( + "Piso -1 do edifício B | Edifício da AEFEUP"), + "dona_bia": + MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Piso -1 do edifício B (B-142)"), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "exams_filter": @@ -73,14 +84,20 @@ class MessageLookup extends MessageLookupByLibrary { "Notificar próxima data limite:"), "floor": MessageLookupByLibrary.simpleMessage("Piso"), "floors": MessageLookupByLibrary.simpleMessage("Pisos"), + "geral_registration": + MessageLookupByLibrary.simpleMessage("Inscrição Geral"), + "improvement_registration": + MessageLookupByLibrary.simpleMessage("Inscrição para Melhoria"), "last_refresh_time": m0, "last_timestamp": m1, - "library": MessageLookupByLibrary.simpleMessage("Biblioteca"), "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), + "multimedia_center": + MessageLookupByLibrary.simpleMessage("Centro de multimédia"), "nav_title": m2, + "news": MessageLookupByLibrary.simpleMessage("Notícias"), "no_course_units": MessageLookupByLibrary.simpleMessage( "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -96,9 +113,21 @@ class MessageLookup extends MessageLookupByLibrary { "Não existem cadeiras para apresentar"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "Não existem exames para apresentar"), + "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "print": MessageLookupByLibrary.simpleMessage("Impressão"), + "room": MessageLookupByLibrary.simpleMessage("Sala"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("Calendário Escolar"), "semester": MessageLookupByLibrary.simpleMessage("Semestre"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "tele_assistance": + MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), + "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( + "Atendimento presencial e telefónico"), + "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Escolhe um widget para adicionares à tua área pessoal:"), "year": MessageLookupByLibrary.simpleMessage("Ano") diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 6767d7e46..3ec3d979b 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -50,6 +50,16 @@ class S { return Localizations.of(context, S); } + /// `Academic services` + String get academic_services { + return Intl.message( + 'Academic services', + name: 'academic_services', + desc: '', + args: [], + ); + } + /// `Checking account` String get account_card_title { return Intl.message( @@ -150,6 +160,16 @@ class S { ); } + /// `Class Registration` + String get class_registration { + return Intl.message( + 'Class Registration', + name: 'class_registration', + desc: '', + args: [], + ); + } + /// `Done` String get conclude { return Intl.message( @@ -180,6 +200,46 @@ class S { ); } + /// `Copy center` + String get copy_center { + return Intl.message( + 'Copy center', + name: 'copy_center', + desc: '', + args: [], + ); + } + + /// `Floor -1 of building B | AEFEUP building` + String get copy_center_building { + return Intl.message( + 'Floor -1 of building B | AEFEUP building', + name: 'copy_center_building', + desc: '', + args: [], + ); + } + + /// `D. Beatriz's stationery store` + String get dona_bia { + return Intl.message( + 'D. Beatriz\'s stationery store', + name: 'dona_bia', + desc: '', + args: [], + ); + } + + /// `Floor -1 of building B (B-142)` + String get dona_bia_building { + return Intl.message( + 'Floor -1 of building B (B-142)', + name: 'dona_bia_building', + desc: '', + args: [], + ); + } + /// `Edit` String get edit_off { return Intl.message( @@ -250,6 +310,26 @@ class S { ); } + /// `General Registration` + String get geral_registration { + return Intl.message( + 'General Registration', + name: 'geral_registration', + desc: '', + args: [], + ); + } + + /// `Enrollment for Improvement` + String get improvement_registration { + return Intl.message( + 'Enrollment for Improvement', + name: 'improvement_registration', + desc: '', + args: [], + ); + } + /// `last refresh at {time}` String last_refresh_time(Object time) { return Intl.message( @@ -273,16 +353,6 @@ class S { ); } - /// `Library` - String get library { - return Intl.message( - 'Library', - name: 'library', - desc: '', - args: [], - ); - } - /// `Library Occupation` String get library_occupation { return Intl.message( @@ -313,7 +383,17 @@ class S { ); } - /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}` + /// `Multimedia center` + String get multimedia_center { + return Intl.message( + 'Multimedia center', + name: 'multimedia_center', + desc: '', + args: [], + ); + } + + /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}` String nav_title(Object title) { return Intl.select( title, @@ -329,7 +409,7 @@ class S { 'biblioteca': 'Library', 'uteis': 'Utils', 'sobre': 'About', - 'bugs': 'Bugs and Suggestions', + 'bugs': 'Bugs/ Suggestions', 'other': 'Other', }, name: 'nav_title', @@ -338,6 +418,16 @@ class S { ); } + /// `News` + String get news { + return Intl.message( + 'News', + name: 'news', + desc: '', + args: [], + ); + } + /// `No course units in the selected period` String get no_course_units { return Intl.message( @@ -418,6 +508,56 @@ class S { ); } + /// `Other links` + String get other_links { + return Intl.message( + 'Other links', + name: 'other_links', + desc: '', + args: [], + ); + } + + /// `Face-to-face assistance` + String get personal_assistance { + return Intl.message( + 'Face-to-face assistance', + name: 'personal_assistance', + desc: '', + args: [], + ); + } + + /// `Print` + String get print { + return Intl.message( + 'Print', + name: 'print', + desc: '', + args: [], + ); + } + + /// `Room` + String get room { + return Intl.message( + 'Room', + name: 'room', + desc: '', + args: [], + ); + } + + /// `School Calendar` + String get school_calendar { + return Intl.message( + 'School Calendar', + name: 'school_calendar', + desc: '', + args: [], + ); + } + /// `Semester` String get semester { return Intl.message( @@ -438,6 +578,36 @@ class S { ); } + /// `Telephone assistance` + String get tele_assistance { + return Intl.message( + 'Telephone assistance', + name: 'tele_assistance', + desc: '', + args: [], + ); + } + + /// `Face-to-face and telephone assistance` + String get tele_personal_assistance { + return Intl.message( + 'Face-to-face and telephone assistance', + name: 'tele_personal_assistance', + desc: '', + args: [], + ); + } + + /// `Telephone` + String get telephone { + return Intl.message( + 'Telephone', + name: 'telephone', + desc: '', + args: [], + ); + } + /// `Choose a widget to add to your personal area:` String get widget_prompt { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index d2488eeec..d728c29f3 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -1,5 +1,7 @@ { "@@locale": "en", + "academic_services": "Academic services", + "@academic_services": {}, "account_card_title": "Checking account", "@account_card_title": {}, "add": "Add", @@ -20,12 +22,22 @@ "@bus_information": {}, "cancel": "Cancel", "@cancel": {}, + "class_registration": "Class Registration", + "@class_registration": {}, "conclude": "Done", "@conclude": {}, "configured_buses": "Configured Buses", "@configured_buses": {}, "confirm": "Confirm", "@confirm": {}, + "copy_center": "Copy center", + "@copy_center": {}, + "copy_center_building": "Floor -1 of building B | AEFEUP building", + "@copy_center_building": {}, + "dona_bia": "D. Beatriz's stationery store", + "@dona_bia": {}, + "dona_bia_building": "Floor -1 of building B (B-142)", + "@dona_bia_building": {}, "edit_off": "Edit", "@edit_off": {}, "edit_on": "Finish editing", @@ -40,6 +52,10 @@ "@floor": {}, "floors": "Floors", "@floors": {}, + "geral_registration": "General Registration", + "@geral_registration": {}, + "improvement_registration": "Enrollment for Improvement", + "@improvement_registration": {}, "last_refresh_time": "last refresh at {time}", "@last_refresh_time": { "placeholders": { @@ -52,16 +68,18 @@ "time": {} } }, - "library": "Library", - "@library": {}, "library_occupation": "Library Occupation", "@library_occupation": {}, "logout": "Log out", "@logout": {}, "menus": "Menus", "@menus": {}, - "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}", + "multimedia_center": "Multimedia center", + "@multimedia_center": {}, + "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}", "@nav_title": {}, + "news": "News", + "@news": {}, "no_course_units": "No course units in the selected period", "@no_course_units": {}, "no_data": "There is no data to show at this time", @@ -78,10 +96,26 @@ "@no_selected_courses": {}, "no_selected_exams": "There are no exams to present", "@no_selected_exams": {}, + "other_links": "Other links", + "@other_links": {}, + "personal_assistance": "Face-to-face assistance", + "@personal_assistance": {}, + "print": "Print", + "@print": {}, + "room": "Room", + "@room": {}, + "school_calendar": "School Calendar", + "@school_calendar": {}, "semester": "Semester", "@semester": {}, "stcp_stops": "STCP - Upcoming Trips", "@stcp_stops": {}, + "tele_assistance": "Telephone assistance", + "@tele_assistance": {}, + "tele_personal_assistance": "Face-to-face and telephone assistance", + "@tele_personal_assistance": {}, + "telephone": "Telephone", + "@telephone": {}, "widget_prompt": "Choose a widget to add to your personal area:", "@widget_prompt": {}, "year": "Year", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 60fb93236..c9a2cc393 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -1,5 +1,7 @@ { "@@locale": "pt-PT", + "academic_services": "Serviços académicos", + "@academic_services": {}, "account_card_title": "Conta Corrente", "@account_card_title": {}, "add": "Adicionar", @@ -20,12 +22,22 @@ "@bus_information": {}, "cancel": "Cancelar\n", "@cancel": {}, + "class_registration": "Inscrição de Turmas", + "@class_registration": {}, "conclude": "Concluído", "@conclude": {}, "configured_buses": "Autocarros Configurados", "@configured_buses": {}, "confirm": "Confirmar", "@confirm": {}, + "copy_center": "Centro de cópias", + "@copy_center": {}, + "copy_center_building": "Piso -1 do edifício B | Edifício da AEFEUP", + "@copy_center_building": {}, + "dona_bia": "Papelaria D. Beatriz", + "@dona_bia": {}, + "dona_bia_building": "Piso -1 do edifício B (B-142)", + "@dona_bia_building": {}, "edit_off": "Editar\n", "@edit_off": {}, "edit_on": "Concluir edição", @@ -40,6 +52,10 @@ "@floor": {}, "floors": "Pisos", "@floors": {}, + "geral_registration": "Inscrição Geral", + "@geral_registration": {}, + "improvement_registration": "Inscrição para Melhoria", + "@improvement_registration": {}, "last_refresh_time": "última atualização às {time}", "@last_refresh_time": { "placeholders": { @@ -52,16 +68,18 @@ "time": {} } }, - "library": "Biblioteca", - "@library": {}, "library_occupation": "Ocupação da Biblioteca", "@library_occupation": {}, "logout": "Terminar sessão", "@logout": {}, "menus": "Ementas", "@menus": {}, + "multimedia_center": "Centro de multimédia", + "@multimedia_center": {}, "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} sobre{Sobre} bugs{Bugs e Sugestões} other{Outros}}", "@nav_title": {}, + "news": "Notícias", + "@news": {}, "no_course_units": "Sem cadeiras no período selecionado", "@no_course_units": {}, "no_data": "Não há dados a mostrar neste momento", @@ -78,10 +96,26 @@ "@no_selected_courses": {}, "no_selected_exams": "Não existem exames para apresentar", "@no_selected_exams": {}, + "other_links": "Outros links", + "@other_links": {}, + "personal_assistance": "Atendimento presencial", + "@personal_assistance": {}, + "print": "Impressão", + "@print": {}, + "room": "Sala", + "@room": {}, + "school_calendar": "Calendário Escolar", + "@school_calendar": {}, "semester": "Semestre", "@semester": {}, "stcp_stops": "STCP - Próximas Viagens", "@stcp_stops": {}, + "tele_assistance": "Atendimento telefónico", + "@tele_assistance": {}, + "tele_personal_assistance": "Atendimento presencial e telefónico", + "@tele_personal_assistance": {}, + "telephone": "Telefone", + "@telephone": {}, "widget_prompt": "Escolhe um widget para adicionares à tua área pessoal:", "@widget_prompt": {}, "year": "Ano", diff --git a/uni/lib/utils/duration_string_formatter.dart b/uni/lib/utils/duration_string_formatter.dart new file mode 100644 index 000000000..6d92006f1 --- /dev/null +++ b/uni/lib/utils/duration_string_formatter.dart @@ -0,0 +1,46 @@ +extension DurationStringFormatter on Duration{ + + static final formattingRegExp = RegExp('{}'); + + String toFormattedString(String singularPhrase, String pluralPhrase, {String term = "{}"}){ + if (!singularPhrase.contains(term) || !pluralPhrase.contains(term)) { + throw ArgumentError("singularPhrase or plurarPhrase don't have a string that can be formatted..."); + } + if(inSeconds == 1){ + return singularPhrase.replaceAll(formattingRegExp, "$inSeconds segundo"); + } + if(inSeconds < 60){ + return pluralPhrase.replaceAll(formattingRegExp, "$inSeconds segundos"); + } + if(inMinutes == 1){ + return singularPhrase.replaceAll(formattingRegExp, "$inMinutes minuto"); + } + if(inMinutes < 60){ + return pluralPhrase.replaceAll(formattingRegExp, "$inMinutes minutos"); + } + if(inHours == 1){ + return singularPhrase.replaceAll(formattingRegExp, "$inHours hora"); + } + if(inHours < 24){ + return pluralPhrase.replaceAll(formattingRegExp, "$inHours horas"); + } + if(inDays == 1){ + return singularPhrase.replaceAll(formattingRegExp, "$inDays dia"); + } + if(inDays <= 7){ + return pluralPhrase.replaceAll(formattingRegExp, "$inDays dias"); + + } + if((inDays / 7).floor() == 1){ + return singularPhrase.replaceAll(formattingRegExp, "${(inDays / 7).floor()} semana"); + } + if((inDays / 7).floor() > 1){ + return pluralPhrase.replaceAll(formattingRegExp, "${(inDays / 7).floor()} semanas"); + } + if((inDays / 30).floor() == 1){ + return singularPhrase.replaceAll(formattingRegExp, "${(inDays / 30).floor()} mês"); + } + return pluralPhrase.replaceAll(formattingRegExp, "${(inDays / 30).floor()} meses"); + + } +} \ No newline at end of file diff --git a/uni/lib/view/common_widgets/generic_expansion_card.dart b/uni/lib/view/common_widgets/generic_expansion_card.dart index 9d88e714c..3189ccd62 100644 --- a/uni/lib/view/common_widgets/generic_expansion_card.dart +++ b/uni/lib/view/common_widgets/generic_expansion_card.dart @@ -10,7 +10,7 @@ abstract class GenericExpansionCard extends StatefulWidget { return GenericExpansionCardState(); } - String getTitle(); + String getTitle(context); Widget buildCardContent(BuildContext context); } @@ -26,7 +26,7 @@ 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(), + title: Text(widget.getTitle(context), style: Theme.of(context) .textTheme .headline5 diff --git a/uni/lib/view/useful_info/useful_info.dart b/uni/lib/view/useful_info/useful_info.dart index cb6b83dc7..cae99fb98 100644 --- a/uni/lib/view/useful_info/useful_info.dart +++ b/uni/lib/view/useful_info/useful_info.dart @@ -8,6 +8,8 @@ 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'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class UsefulInfoPageView extends StatefulWidget { const UsefulInfoPageView({super.key}); @@ -35,6 +37,6 @@ class UsefulInfoPageViewState extends GeneralPageViewState { Container _getPageTitle() { return Container( padding: const EdgeInsets.only(bottom: 6.0), - child: const PageTitle(name: 'Úteis')); + child: PageTitle(name: S.of(context).nav_title(DrawerItem.navUsefulInfo.title))); } } diff --git a/uni/lib/view/useful_info/widgets/academic_services_card.dart b/uni/lib/view/useful_info/widgets/academic_services_card.dart index 2b7ffc0be..f6e4c4313 100644 --- a/uni/lib/view/useful_info/widgets/academic_services_card.dart +++ b/uni/lib/view/useful_info/widgets/academic_services_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/text_components.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class AcademicServicesCard extends GenericExpansionCard { const AcademicServicesCard({Key? key}) : super(key: key); @@ -9,12 +11,12 @@ class AcademicServicesCard extends GenericExpansionCard { Widget buildCardContent(BuildContext context) { return Column( children: [ - h1('Horário', context, initial: true), - h2('Atendimento presencial', context), + h1(S.of(context).nav_title(DrawerItem.navSchedule.title), context, initial: true), + h2(S.of(context).personal_assistance, context), infoText('11:00h - 16:00h', context), - h2('Atendimento telefónico', context), + h2(S.of(context).tele_assistance, context), infoText('9:30h - 12:00h | 14:00h - 16:00h', context), - h1('Telefone', context), + h1(S.of(context).telephone, context), infoText('+351 225 081 977', context, link: 'tel:225 081 977', last: true), ], @@ -22,5 +24,5 @@ class AcademicServicesCard extends GenericExpansionCard { } @override - String getTitle() => 'Serviços Académicos'; + String getTitle(context) => S.of(context).academic_services; } diff --git a/uni/lib/view/useful_info/widgets/copy_center_card.dart b/uni/lib/view/useful_info/widgets/copy_center_card.dart index 62124f7d3..251b8b22c 100644 --- a/uni/lib/view/useful_info/widgets/copy_center_card.dart +++ b/uni/lib/view/useful_info/widgets/copy_center_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/text_components.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class CopyCenterCard extends GenericExpansionCard { const CopyCenterCard({Key? key}) : super(key: key); @@ -9,10 +11,10 @@ class CopyCenterCard extends GenericExpansionCard { Widget buildCardContent(BuildContext context) { return Column( children: [ - h1('Horário', context, initial: true), - h2('Piso -1 do edifício B | Edifício da AEFEUP', context), + h1(S.of(context).nav_title(DrawerItem.navSchedule.title), context, initial: true), + h2(S.of(context).copy_center_building, context), infoText('9:00h - 11:30h | 12:30h - 18:00h', context), - h1('Telefone', context), + h1(S.of(context).telephone, context), h2('FEUP ', context), infoText('+351 220 994 122', context, link: 'tel:220 994 122'), h2('AEFEUP ', context), @@ -25,5 +27,5 @@ class CopyCenterCard extends GenericExpansionCard { } @override - String getTitle() => 'Centro de Cópias'; + String getTitle(context) => S.of(context).copy_center; } diff --git a/uni/lib/view/useful_info/widgets/dona_bia_card.dart b/uni/lib/view/useful_info/widgets/dona_bia_card.dart index fc1abd773..7554e8617 100644 --- a/uni/lib/view/useful_info/widgets/dona_bia_card.dart +++ b/uni/lib/view/useful_info/widgets/dona_bia_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/text_components.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class DonaBiaCard extends GenericExpansionCard { const DonaBiaCard({Key? key}) : super(key: key); @@ -9,10 +11,10 @@ class DonaBiaCard extends GenericExpansionCard { Widget buildCardContent(BuildContext context) { return Column( children: [ - h1('Horário', context, initial: true), - h2('Piso -1 do edifício B (B -142)', context), + h1(S.of(context).nav_title(DrawerItem.navSchedule.title), context, initial: true), + h2(S.of(context).dona_bia_building, context), infoText('8:30h - 12:00h | 13:30h - 19:00h', context), - h1('Telefone', context), + h1(S.of(context).telephone, context), infoText('+351 225 081 416', context, link: 'tel:225 081 416'), h1('Email', context), infoText('papelaria.fe.up@gmail.com', context, @@ -22,5 +24,5 @@ class DonaBiaCard extends GenericExpansionCard { } @override - String getTitle() => 'Papelaria D. Beatriz'; + String getTitle(context) => S.of(context).dona_bia; } diff --git a/uni/lib/view/useful_info/widgets/infodesk_card.dart b/uni/lib/view/useful_info/widgets/infodesk_card.dart index 66cf8dac6..f99dfcaec 100644 --- a/uni/lib/view/useful_info/widgets/infodesk_card.dart +++ b/uni/lib/view/useful_info/widgets/infodesk_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/text_components.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class InfoDeskCard extends GenericExpansionCard { const InfoDeskCard({Key? key}) : super(key: key); @@ -9,10 +11,10 @@ class InfoDeskCard extends GenericExpansionCard { Widget buildCardContent(BuildContext context) { return Column( children: [ - h1('Horário', context, initial: true), - h2('Atendimento presencial e telefónico', context), + h1(S.of(context).nav_title(DrawerItem.navSchedule.title), context, initial: true), + h2(S.of(context).tele_personal_assistance, context), infoText('9:30h - 13:00h | 14:00h - 17:30h', context), - h1('Telefone', context), + h1(S.of(context).telephone, context), infoText('+351 225 081 400', context, link: 'tel:225 081 400'), h1('Email', context), infoText('infodesk@fe.up.pt', context, @@ -22,5 +24,5 @@ class InfoDeskCard extends GenericExpansionCard { } @override - String getTitle() => 'Infodesk'; + String getTitle(context) => 'Infodesk'; } diff --git a/uni/lib/view/useful_info/widgets/multimedia_center_card.dart b/uni/lib/view/useful_info/widgets/multimedia_center_card.dart index ce667f641..832dc84a7 100644 --- a/uni/lib/view/useful_info/widgets/multimedia_center_card.dart +++ b/uni/lib/view/useful_info/widgets/multimedia_center_card.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/text_components.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; class MultimediaCenterCard extends GenericExpansionCard { const MultimediaCenterCard({Key? key}) : super(key: key); @@ -9,10 +11,10 @@ class MultimediaCenterCard extends GenericExpansionCard { Widget buildCardContent(BuildContext context) { return Column( children: [ - h1('Horário', context, initial: true), - h2('Sala B123', context), + h1(S.of(context).nav_title(DrawerItem.navSchedule.title), context, initial: true), + h2('${S.of(context).room} B123', context), infoText('9:00h - 12:30h | 14:30h - 17:00h', context), - h1('Telefone', context), + h1(S.of(context).telephone, context), infoText('+351 225 081 466', context, link: 'tel:225 081 466'), h1('Email', context), infoText('imprimir@fe.up.pt', context, @@ -22,5 +24,5 @@ class MultimediaCenterCard extends GenericExpansionCard { } @override - String getTitle() => 'Centro de Multimédia'; + String getTitle(context) => S.of(context).multimedia_center; } diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 92561b92d..59acfd6e0 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/link_button.dart'; +import 'package:uni/generated/l10n.dart'; /// Manages the 'Current account' section inside the user's page (accessible /// through the top-right widget with the user picture) @@ -9,11 +10,11 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column(children: const [ - LinkButton(title: 'Impressão', link: 'https://print.up.pt') + return Column(children: [ + LinkButton(title: S.of(context).print, link: 'https://print.up.pt') ]); } @override - String getTitle() => 'Outros Links'; + String getTitle(context) => S.of(context).other_links; } diff --git a/uni/lib/view/useful_info/widgets/sigarra_links_card.dart b/uni/lib/view/useful_info/widgets/sigarra_links_card.dart index 90fcbe3d0..cd675ad1f 100644 --- a/uni/lib/view/useful_info/widgets/sigarra_links_card.dart +++ b/uni/lib/view/useful_info/widgets/sigarra_links_card.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; import 'package:uni/view/useful_info/widgets/link_button.dart'; +import 'package:uni/generated/l10n.dart'; /// Manages the 'Current account' section inside the user's page (accessible /// through the top-right widget with the user picture) @@ -9,31 +10,31 @@ class SigarraLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column(children: const [ + return Column(children: [ LinkButton( - title: 'Notícias', + title: S.of(context).news, link: 'https://sigarra.up.pt/feup/pt/noticias_geral.lista_noticias'), - LinkButton( + const LinkButton( title: 'Erasmus', link: 'https://sigarra.up.pt/feup/pt/web_base.gera_pagina?P_pagina=257769'), LinkButton( - title: 'Inscrição Geral', + title: S.of(context).geral_registration, link: 'https://sigarra.up.pt/feup/pt/ins_geral.inscricao'), LinkButton( - title: 'Inscrição de Turmas', + title: S.of(context).class_registration, link: 'https://sigarra.up.pt/feup/pt/it_geral.ver_insc'), LinkButton( - title: 'Inscrição para Melhoria', + title: S.of(context).improvement_registration, link: 'https://sigarra.up.pt/feup/pt/inqueritos_geral.inqueritos_list'), LinkButton( - title: 'Calendário Escolar', + title: S.of(context).school_calendar, link: 'https://sigarra.up.pt/feup/pt/web_base.gera_pagina?p_pagina=p%c3%a1gina%20est%c3%a1tica%20gen%c3%a9rica%20106') ]); } @override - String getTitle() => 'Links Sigarra'; + String getTitle(context) => 'Links Sigarra'; } From 00831a79ae52dc152e7c726082fa5ad36ccf885d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 19 Jun 2023 22:58:17 +0100 Subject: [PATCH 019/199] Error fixing --- uni/lib/model/entities/time_utilities.dart | 2 +- uni/lib/view/restaurant/restaurant_page_view.dart | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/uni/lib/model/entities/time_utilities.dart b/uni/lib/model/entities/time_utilities.dart index a253239f8..45072ba4e 100644 --- a/uni/lib/model/entities/time_utilities.dart +++ b/uni/lib/model/entities/time_utilities.dart @@ -1,5 +1,5 @@ import 'dart:io'; -import 'package:flutter/material.dart +import 'package:flutter/material.dart'; extension TimeString on DateTime { String toTimeHourMinString() { diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index ed0816644..5cdd61b5b 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -1,9 +1,9 @@ import 'package:provider/provider.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:flutter/material.dart'; -import 'package:uni/model/entities/time_utilities.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/model/entities/time_utilities.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'; @@ -89,14 +89,13 @@ class _CanteenPageState extends GeneralPageViewState } List createTabs(BuildContext context) { - final List daysOfTheWeek = - TimeString.getWeekdaysStrings(includeWeekend: true); + final List daysOfTheWeek = TimeString.getWeekdaysStrings(includeWeekend: true); final List tabs = []; for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add(Container( color: Theme.of(context).backgroundColor, - child: Tab(key: Key('cantine-page-tab-$i'), text: toString(DayOfWeek.values[i])), + child: Tab(key: Key('cantine-page-tab-$i'), text: daysOfTheWeek[i]), )); } From d018f768c8d9835f626e08a6c4b7ad0f4c19742c Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 20 Jun 2023 01:58:13 +0100 Subject: [PATCH 020/199] Bugs and suggestions page translation --- uni/lib/generated/intl/messages_en.dart | 27 +++ uni/lib/generated/intl/messages_pt-PT.dart | 27 +++ uni/lib/generated/l10n.dart | 160 ++++++++++++++++++ uni/lib/l10n/intl_en.arb | 32 ++++ uni/lib/l10n/intl_pt_PT.arb | 32 ++++ .../about/widgets/terms_and_conditions.dart | 4 +- uni/lib/view/bug_report/widgets/form.dart | 53 +++--- .../view/bug_report/widgets/text_field.dart | 5 +- .../bus_stop_next_arrivals.dart | 2 +- .../view/restaurant/restaurant_page_view.dart | 2 +- 10 files changed, 316 insertions(+), 28 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index af42487cb..961f762bb 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -52,6 +52,10 @@ class MessageLookup extends MessageLookupByLibrary { "all_widgets_added": MessageLookupByLibrary.simpleMessage( "All available widgets have already been added to your personal area!"), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), + "bs_description": MessageLookupByLibrary.simpleMessage( + "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!"), + "bug_description": MessageLookupByLibrary.simpleMessage( + "Bug found, how to reproduce it, etc."), "bus_error": MessageLookupByLibrary.simpleMessage("Unable to get information"), "bus_information": MessageLookupByLibrary.simpleMessage( @@ -67,15 +71,23 @@ class MessageLookup extends MessageLookupByLibrary { "configured_buses": MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), + "consent": MessageLookupByLibrary.simpleMessage( + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request."), + "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B | AEFEUP building"), + "description": MessageLookupByLibrary.simpleMessage("Description"), + "desired_email": MessageLookupByLibrary.simpleMessage( + "Email where you want to be contacted"), "dona_bia": MessageLookupByLibrary.simpleMessage( "D. Beatriz\'s stationery store"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B (B-142)"), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), + "empty_text": + MessageLookupByLibrary.simpleMessage("Please fill in this field"), "exams_filter": MessageLookupByLibrary.simpleMessage("Exam Filter Settings"), "fee_date": @@ -92,12 +104,16 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), + "loading_terms": MessageLookupByLibrary.simpleMessage( + "Loading Terms and Conditions..."), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), "multimedia_center": MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("News"), + "no_bus_stops": + MessageLookupByLibrary.simpleMessage("No configured stops"), "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -113,21 +129,32 @@ class MessageLookup extends MessageLookupByLibrary { "There are no course units to display"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "There are no exams to present"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), "print": MessageLookupByLibrary.simpleMessage("Print"), + "problem_id": MessageLookupByLibrary.simpleMessage( + "Brief identification of the problem"), "room": MessageLookupByLibrary.simpleMessage("Room"), "school_calendar": MessageLookupByLibrary.simpleMessage("School Calendar"), "semester": MessageLookupByLibrary.simpleMessage("Semester"), + "send": MessageLookupByLibrary.simpleMessage("Send"), + "sent_error": MessageLookupByLibrary.simpleMessage( + "An error occurred in sending"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "success": MessageLookupByLibrary.simpleMessage("Sent with success"), "tele_assistance": MessageLookupByLibrary.simpleMessage("Telephone assistance"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( "Face-to-face and telephone assistance"), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), + "title": MessageLookupByLibrary.simpleMessage("Title"), + "valid_email": + MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Choose a widget to add to your personal area:"), "year": MessageLookupByLibrary.simpleMessage("Year") diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 8b5b6c33a..c119ccd93 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -52,6 +52,10 @@ class MessageLookup extends MessageLookupByLibrary { "all_widgets_added": MessageLookupByLibrary.simpleMessage( "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), + "bs_description": MessageLookupByLibrary.simpleMessage( + "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!"), + "bug_description": MessageLookupByLibrary.simpleMessage( + "Bug encontrado, como o reproduzir, etc"), "bus_error": MessageLookupByLibrary.simpleMessage( "Não foi possível obter informação"), "bus_information": MessageLookupByLibrary.simpleMessage( @@ -67,15 +71,23 @@ class MessageLookup extends MessageLookupByLibrary { "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), + "consent": MessageLookupByLibrary.simpleMessage( + "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido."), + "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), "copy_center_building": MessageLookupByLibrary.simpleMessage( "Piso -1 do edifício B | Edifício da AEFEUP"), + "description": MessageLookupByLibrary.simpleMessage("Descrição"), + "desired_email": MessageLookupByLibrary.simpleMessage( + "Email em que desejas ser contactado"), "dona_bia": MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Piso -1 do edifício B (B-142)"), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), + "empty_text": MessageLookupByLibrary.simpleMessage( + "Por favor preenche este campo"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), "fee_date": MessageLookupByLibrary.simpleMessage( @@ -92,12 +104,16 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "loading_terms": MessageLookupByLibrary.simpleMessage( + "Carregando os Termos e Condições..."), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), "multimedia_center": MessageLookupByLibrary.simpleMessage("Centro de multimédia"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("Notícias"), + "no_bus_stops": MessageLookupByLibrary.simpleMessage( + "Não existe nenhuma paragem configurada"), "no_course_units": MessageLookupByLibrary.simpleMessage( "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -113,21 +129,32 @@ class MessageLookup extends MessageLookupByLibrary { "Não existem cadeiras para apresentar"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( "Não existem exames para apresentar"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Atendimento presencial"), "print": MessageLookupByLibrary.simpleMessage("Impressão"), + "problem_id": MessageLookupByLibrary.simpleMessage( + "Breve identificação do problema"), "room": MessageLookupByLibrary.simpleMessage("Sala"), "school_calendar": MessageLookupByLibrary.simpleMessage("Calendário Escolar"), "semester": MessageLookupByLibrary.simpleMessage("Semestre"), + "send": MessageLookupByLibrary.simpleMessage("Enviar"), + "sent_error": + MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), "tele_assistance": MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( "Atendimento presencial e telefónico"), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), + "title": MessageLookupByLibrary.simpleMessage("Título"), + "valid_email": MessageLookupByLibrary.simpleMessage( + "Por favor insere um email válido"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Escolhe um widget para adicionares à tua área pessoal:"), "year": MessageLookupByLibrary.simpleMessage("Ano") diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 3ec3d979b..0181657c7 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -110,6 +110,26 @@ class S { ); } + /// `Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!` + String get bs_description { + return Intl.message( + 'Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!', + name: 'bs_description', + desc: '', + args: [], + ); + } + + /// `Bug found, how to reproduce it, etc.` + String get bug_description { + return Intl.message( + 'Bug found, how to reproduce it, etc.', + name: 'bug_description', + desc: '', + args: [], + ); + } + /// `Unable to get information` String get bus_error { return Intl.message( @@ -200,6 +220,26 @@ class S { ); } + /// `I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.` + String get consent { + return Intl.message( + 'I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.', + name: 'consent', + desc: '', + args: [], + ); + } + + /// `Contact (optional)` + String get contact { + return Intl.message( + 'Contact (optional)', + name: 'contact', + desc: '', + args: [], + ); + } + /// `Copy center` String get copy_center { return Intl.message( @@ -220,6 +260,26 @@ class S { ); } + /// `Description` + String get description { + return Intl.message( + 'Description', + name: 'description', + desc: '', + args: [], + ); + } + + /// `Email where you want to be contacted` + String get desired_email { + return Intl.message( + 'Email where you want to be contacted', + name: 'desired_email', + desc: '', + args: [], + ); + } + /// `D. Beatriz's stationery store` String get dona_bia { return Intl.message( @@ -260,6 +320,16 @@ class S { ); } + /// `Please fill in this field` + String get empty_text { + return Intl.message( + 'Please fill in this field', + name: 'empty_text', + desc: '', + args: [], + ); + } + /// `Exam Filter Settings` String get exams_filter { return Intl.message( @@ -363,6 +433,16 @@ class S { ); } + /// `Loading Terms and Conditions...` + String get loading_terms { + return Intl.message( + 'Loading Terms and Conditions...', + name: 'loading_terms', + desc: '', + args: [], + ); + } + /// `Log out` String get logout { return Intl.message( @@ -428,6 +508,16 @@ class S { ); } + /// `No configured stops` + String get no_bus_stops { + return Intl.message( + 'No configured stops', + name: 'no_bus_stops', + desc: '', + args: [], + ); + } + /// `No course units in the selected period` String get no_course_units { return Intl.message( @@ -508,6 +598,16 @@ class S { ); } + /// `Type of occurrence` + String get occurrence_type { + return Intl.message( + 'Type of occurrence', + name: 'occurrence_type', + desc: '', + args: [], + ); + } + /// `Other links` String get other_links { return Intl.message( @@ -538,6 +638,16 @@ class S { ); } + /// `Brief identification of the problem` + String get problem_id { + return Intl.message( + 'Brief identification of the problem', + name: 'problem_id', + desc: '', + args: [], + ); + } + /// `Room` String get room { return Intl.message( @@ -568,6 +678,26 @@ class S { ); } + /// `Send` + String get send { + return Intl.message( + 'Send', + name: 'send', + desc: '', + args: [], + ); + } + + /// `An error occurred in sending` + String get sent_error { + return Intl.message( + 'An error occurred in sending', + name: 'sent_error', + desc: '', + args: [], + ); + } + /// `STCP - Upcoming Trips` String get stcp_stops { return Intl.message( @@ -578,6 +708,16 @@ class S { ); } + /// `Sent with success` + String get success { + return Intl.message( + 'Sent with success', + name: 'success', + desc: '', + args: [], + ); + } + /// `Telephone assistance` String get tele_assistance { return Intl.message( @@ -608,6 +748,26 @@ class S { ); } + /// `Title` + String get title { + return Intl.message( + 'Title', + name: 'title', + desc: '', + args: [], + ); + } + + /// `Please enter a valid email` + String get valid_email { + return Intl.message( + 'Please enter a valid email', + name: 'valid_email', + desc: '', + args: [], + ); + } + /// `Choose a widget to add to your personal area:` String get widget_prompt { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index d728c29f3..5778da1f5 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -12,6 +12,10 @@ "@all_widgets_added": {}, "balance": "Balance:", "@balance": {}, + "bs_description": "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!", + "@bs_description": {}, + "bug_description": "Bug found, how to reproduce it, etc.", + "@bug_description": {}, "bus_error": "Unable to get information", "@bus_error": {}, "buses_personalize": "Personalize your buses here", @@ -30,10 +34,18 @@ "@configured_buses": {}, "confirm": "Confirm", "@confirm": {}, + "consent": "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", + "@consent": {}, + "contact": "Contact (optional)", + "@contact": {}, "copy_center": "Copy center", "@copy_center": {}, "copy_center_building": "Floor -1 of building B | AEFEUP building", "@copy_center_building": {}, + "description": "Description", + "@description": {}, + "desired_email": "Email where you want to be contacted", + "@desired_email": {}, "dona_bia": "D. Beatriz's stationery store", "@dona_bia": {}, "dona_bia_building": "Floor -1 of building B (B-142)", @@ -42,6 +54,8 @@ "@edit_off": {}, "edit_on": "Finish editing", "@edit_on": {}, + "empty_text": "Please fill in this field", + "@empty_text": {}, "exams_filter": "Exam Filter Settings", "@exams_filter": {}, "fee_date": "Deadline for next fee:", @@ -70,6 +84,8 @@ }, "library_occupation": "Library Occupation", "@library_occupation": {}, + "loading_terms": "Loading Terms and Conditions...", + "@loading_terms": {}, "logout": "Log out", "@logout": {}, "menus": "Menus", @@ -80,6 +96,8 @@ "@nav_title": {}, "news": "News", "@news": {}, + "no_bus_stops": "No configured stops", + "@no_bus_stops": {}, "no_course_units": "No course units in the selected period", "@no_course_units": {}, "no_data": "There is no data to show at this time", @@ -96,26 +114,40 @@ "@no_selected_courses": {}, "no_selected_exams": "There are no exams to present", "@no_selected_exams": {}, + "occurrence_type": "Type of occurrence", + "@occurrence_type": {}, "other_links": "Other links", "@other_links": {}, "personal_assistance": "Face-to-face assistance", "@personal_assistance": {}, "print": "Print", "@print": {}, + "problem_id": "Brief identification of the problem", + "@problem_id": {}, "room": "Room", "@room": {}, "school_calendar": "School Calendar", "@school_calendar": {}, "semester": "Semester", "@semester": {}, + "send": "Send", + "@send": {}, + "sent_error": "An error occurred in sending", + "@sent_error": {}, "stcp_stops": "STCP - Upcoming Trips", "@stcp_stops": {}, + "success": "Sent with success", + "@success": {}, "tele_assistance": "Telephone assistance", "@tele_assistance": {}, "tele_personal_assistance": "Face-to-face and telephone assistance", "@tele_personal_assistance": {}, "telephone": "Telephone", "@telephone": {}, + "title": "Title", + "@title": {}, + "valid_email": "Please enter a valid email", + "@valid_email": {}, "widget_prompt": "Choose a widget to add to your personal area:", "@widget_prompt": {}, "year": "Year", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index c9a2cc393..4a6c48c60 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -12,6 +12,10 @@ "@all_widgets_added": {}, "balance": "Saldo:", "@balance": {}, + "bs_description": "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!", + "@bs_description": {}, + "bug_description": "Bug encontrado, como o reproduzir, etc", + "@bug_description": {}, "bus_error": "Não foi possível obter informação", "@bus_error": {}, "buses_personalize": "Configura aqui os teus autocarros", @@ -30,10 +34,18 @@ "@configured_buses": {}, "confirm": "Confirmar", "@confirm": {}, + "consent": "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.", + "@consent": {}, + "contact": "Contacto (opcional)", + "@contact": {}, "copy_center": "Centro de cópias", "@copy_center": {}, "copy_center_building": "Piso -1 do edifício B | Edifício da AEFEUP", "@copy_center_building": {}, + "description": "Descrição", + "@description": {}, + "desired_email": "Email em que desejas ser contactado", + "@desired_email": {}, "dona_bia": "Papelaria D. Beatriz", "@dona_bia": {}, "dona_bia_building": "Piso -1 do edifício B (B-142)", @@ -42,6 +54,8 @@ "@edit_off": {}, "edit_on": "Concluir edição", "@edit_on": {}, + "empty_text": "Por favor preenche este campo", + "@empty_text": {}, "exams_filter": "Definições Filtro de Exames", "@exams_filter": {}, "fee_date": "Data limite próxima prestação:", @@ -70,6 +84,8 @@ }, "library_occupation": "Ocupação da Biblioteca", "@library_occupation": {}, + "loading_terms": "Carregando os Termos e Condições...", + "@loading_terms": {}, "logout": "Terminar sessão", "@logout": {}, "menus": "Ementas", @@ -80,6 +96,8 @@ "@nav_title": {}, "news": "Notícias", "@news": {}, + "no_bus_stops": "Não existe nenhuma paragem configurada", + "@no_bus_stops": {}, "no_course_units": "Sem cadeiras no período selecionado", "@no_course_units": {}, "no_data": "Não há dados a mostrar neste momento", @@ -96,26 +114,40 @@ "@no_selected_courses": {}, "no_selected_exams": "Não existem exames para apresentar", "@no_selected_exams": {}, + "occurrence_type": "Tipo de ocorrência", + "@occurrence_type": {}, "other_links": "Outros links", "@other_links": {}, "personal_assistance": "Atendimento presencial", "@personal_assistance": {}, "print": "Impressão", "@print": {}, + "problem_id": "Breve identificação do problema", + "@problem_id": {}, "room": "Sala", "@room": {}, "school_calendar": "Calendário Escolar", "@school_calendar": {}, "semester": "Semestre", "@semester": {}, + "send": "Enviar", + "@send": {}, + "sent_error": "Ocorreu um erro no envio", + "@sent_error": {}, "stcp_stops": "STCP - Próximas Viagens", "@stcp_stops": {}, + "success": "Enviado com sucesso", + "@success": {}, "tele_assistance": "Atendimento telefónico", "@tele_assistance": {}, "tele_personal_assistance": "Atendimento presencial e telefónico", "@tele_personal_assistance": {}, "telephone": "Telefone", "@telephone": {}, + "title": "Título", + "@title": {}, + "valid_email": "Por favor insere um email válido", + "@valid_email": {}, "widget_prompt": "Escolhe um widget para adicionares à tua área pessoal:", "@widget_prompt": {}, "year": "Ano", diff --git a/uni/lib/view/about/widgets/terms_and_conditions.dart b/uni/lib/view/about/widgets/terms_and_conditions.dart index 6f1407a36..e5ae8fb91 100644 --- a/uni/lib/view/about/widgets/terms_and_conditions.dart +++ b/uni/lib/view/about/widgets/terms_and_conditions.dart @@ -3,14 +3,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:uni/controller/load_static/terms_and_conditions.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:uni/generated/l10n.dart'; + class TermsAndConditions extends StatelessWidget { - static String termsAndConditionsSaved = 'Carregando os Termos e Condições...'; const TermsAndConditions({Key? key}) : super(key: key); @override Widget build(BuildContext context) { + String termsAndConditionsSaved = S.of(context).loading_terms; final Future termsAndConditionsFuture = readTermsAndConditions(); return FutureBuilder( future: termsAndConditionsFuture, diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index f63d5b9fb..89086a02d 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:email_validator/email_validator.dart'; import 'package:flutter/material.dart'; @@ -7,6 +8,8 @@ import 'package:http/http.dart' as http; import 'package:logger/logger.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tuple/tuple.dart'; +import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/bug_report.dart'; import 'package:uni/view/bug_report/widgets/text_field.dart'; import 'package:uni/view/common_widgets/page_title.dart'; @@ -58,8 +61,11 @@ class BugReportFormState extends State { void loadBugClassList() { bugList = []; - bugDescriptions.forEach((int key, Tuple2 tup) => - {bugList.add(DropdownMenuItem(value: key, child: Text(tup.item1)))}); + + bugDescriptions.forEach((int key, Tuple2 tup){ + if(Platform.localeName == 'pt_PT') {bugList.add(DropdownMenuItem(value: key, child: Text(tup.item1)));} + else {bugList.add(DropdownMenuItem(value: key, child: Text(tup.item2)));} + }); } @override @@ -79,8 +85,8 @@ class BugReportFormState extends State { Icons.title, minLines: 1, maxLines: 2, - description: 'Título', - labelText: 'Breve identificação do problema', + description: S.of(context).title, + labelText: S.of(context).problem_id, bottomMargin: 30.0, )); @@ -89,8 +95,8 @@ class BugReportFormState extends State { Icons.description, minLines: 1, maxLines: 30, - description: 'Descrição', - labelText: 'Bug encontrado, como o reproduzir, etc', + description: S.of(context).description, + labelText: S.of(context).bug_description, bottomMargin: 30.0, )); @@ -99,14 +105,14 @@ class BugReportFormState extends State { Icons.mail, minLines: 1, maxLines: 2, - description: 'Contacto (opcional)', - labelText: 'Email em que desejas ser contactado', + description: S.of(context).contact, + labelText: S.of(context).desired_email, bottomMargin: 30.0, isOptional: true, formatValidator: (value) { return EmailValidator.validate(value) ? null - : 'Por favor insere um email válido'; + : S.of(context).valid_email; }, )); @@ -123,10 +129,10 @@ class BugReportFormState extends State { margin: const EdgeInsets.symmetric(vertical: 10.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: const [ - Icon(Icons.bug_report, size: 40.0), - PageTitle(name: 'Bugs e Sugestões', center: false), - Icon(Icons.bug_report, size: 40.0), + children: [ + const Icon(Icons.bug_report, size: 40.0), + PageTitle(name: S.of(context).nav_title(DrawerItem.navBugReport.title), center: false), + const Icon(Icons.bug_report, size: 40.0), ], )); } @@ -138,8 +144,7 @@ class BugReportFormState extends State { padding: const EdgeInsets.only(bottom: 20), child: Center( child: Text( - '''Encontraste algum bug na aplicação?\nTens alguma ''' - '''sugestão para a app?\nConta-nos para que possamos melhorar!''', + S.of(context).bs_description, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center), ), @@ -155,7 +160,7 @@ class BugReportFormState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Tipo de ocorrência', + S.of(context).occurrence_type, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.left, ), @@ -167,7 +172,7 @@ class BugReportFormState extends State { )), Expanded( child: DropdownButton( - hint: const Text('Tipo de ocorrência'), + hint: Text(S.of(context).occurrence_type), items: bugList, value: _selectedBug, onChanged: (value) { @@ -191,7 +196,7 @@ class BugReportFormState extends State { contentPadding: const EdgeInsets.all(0), child: CheckboxListTile( title: Text( - '''Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.''', + S.of(context).consent, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.left), value: _isConsentGiven, @@ -218,9 +223,9 @@ class BugReportFormState extends State { submitBugReport(); } }, - child: const Text( - 'Enviar', - style: TextStyle(/*color: Colors.white*/ fontSize: 20.0), + child: Text( + S.of(context).send, + style: const TextStyle(/*color: Colors.white*/ fontSize: 20.0), ), ); } @@ -252,11 +257,13 @@ class BugReportFormState extends State { throw Exception('Network error'); } Logger().i('Successfully submitted bug report.'); - toastMsg = 'Enviado com sucesso'; + // ignore: use_build_context_synchronously + toastMsg = S.of(context).success; status = true; } catch (e) { Logger().e('Error while posting bug report:$e'); - toastMsg = 'Ocorreu um erro no envio'; + // ignore: use_build_context_synchronously + toastMsg = S.of(context).sent_error; status = false; } diff --git a/uni/lib/view/bug_report/widgets/text_field.dart b/uni/lib/view/bug_report/widgets/text_field.dart index ae021e20c..71c50876b 100644 --- a/uni/lib/view/bug_report/widgets/text_field.dart +++ b/uni/lib/view/bug_report/widgets/text_field.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; class FormTextField extends StatelessWidget { final TextEditingController controller; @@ -19,7 +20,7 @@ class FormTextField extends StatelessWidget { this.maxLines = 1, this.labelText = '', this.hintText = '', - this.emptyText = 'Por favor preenche este campo', + this.emptyText = '', this.bottomMargin = 0, this.isOptional = false, this.formatValidator, @@ -59,7 +60,7 @@ class FormTextField extends StatelessWidget { controller: controller, validator: (value) { if (value!.isEmpty) { - return isOptional ? null : emptyText; + return isOptional ? null : S.of(context).empty_text; } return formatValidator != null ? formatValidator!(value) : null; }, 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 10ace51cb..b35d1f84d 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 @@ -86,7 +86,7 @@ class NextArrivalsState extends State { if (widget.buses.isNotEmpty) { result.addAll(getContent(context)); } else { - result.add(Text('Não existe nenhuma paragem configurada', + result.add(Text(S.of(context).no_bus_stops, style: Theme.of(context).textTheme.titleLarge)); } diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 5cdd61b5b..c47129ddf 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -94,7 +94,7 @@ class _CanteenPageState extends GeneralPageViewState for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add(Container( - color: Theme.of(context).backgroundColor, + color: Theme.of(context).colorScheme.background, child: Tab(key: Key('cantine-page-tab-$i'), text: daysOfTheWeek[i]), )); } From 095168db6e19bd472e5ddc043a441b09fd1b0d83 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 25 Jun 2023 16:05:10 +0100 Subject: [PATCH 021/199] Translation button --- .../local_storage/app_shared_preferences.dart | 12 +++ uni/lib/generated/intl/messages_all.dart | 10 +- uni/lib/generated/intl/messages_en.dart | 16 +++ uni/lib/generated/intl/messages_pt-PT.dart | 15 +++ uni/lib/generated/l10n.dart | 102 +++++++++++++++++- uni/lib/l10n/intl_en.arb | 20 ++++ uni/lib/l10n/intl_pt_PT.arb | 20 ++++ uni/lib/main.dart | 4 +- .../general/widgets/navigation_drawer.dart | 41 ++++++- uni/lib/view/home/widgets/schedule_card.dart | 2 +- .../profile/widgets/course_info_card.dart | 23 ++-- uni/lib/view/schedule/schedule.dart | 2 +- uni/lib/view/theme_notifier.dart | 24 ++++- 13 files changed, 269 insertions(+), 22 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..e9c49d2e3 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -19,6 +19,7 @@ class AppSharedPreferences { static const String areTermsAndConditionsAcceptedKey = 'is_t&c_accepted'; static const String tuitionNotificationsToggleKey = "tuition_notification_toogle"; static const String themeMode = 'theme_mode'; + static const String locale = 'app_locale'; static const int keyLength = 32; static const int ivLength = 16; static final iv = encrypt.IV.fromLength(ivLength); @@ -87,6 +88,17 @@ class AppSharedPreferences { return prefs.setInt(themeMode, (themeIndex + 1) % 3); } + static setLocale(Locale app_locale) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(locale, app_locale.toString()); + } + + static Future getLocale() async { + final prefs = await SharedPreferences.getInstance(); + final test = prefs.getString(locale) ?? 'en_US'; + return Locale.fromSubtags(languageCode: test.substring(0,3), countryCode: test.substring(0,3)); + } + /// Deletes the user's student number and password. static Future removePersistentUserInfo() async { final prefs = await SharedPreferences.getInstance(); diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 525f677ec..171385879 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -16,8 +16,8 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'package:uni/generated/intl/messages_en.dart' as messages_en; -import 'package:uni/generated/intl/messages_pt-PT.dart' as messages_pt_pt; +import 'messages_en.dart' as messages_en; +import 'messages_pt-PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { @@ -38,13 +38,13 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) { - final availableLocale = Intl.verifiedLocale( + var availableLocale = Intl.verifiedLocale( localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { return new SynchronousFuture(false); } - final lib = _deferredLibraries[availableLocale]; + var lib = _deferredLibraries[availableLocale]; lib == null ? new SynchronousFuture(false) : lib(); initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); @@ -60,7 +60,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = + var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 961f762bb..880c8856e 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -51,6 +51,7 @@ class MessageLookup extends MessageLookupByLibrary { "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "All available widgets have already been added to your personal area!"), + "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!"), @@ -67,6 +68,7 @@ class MessageLookup extends MessageLookupByLibrary { "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), + "college": MessageLookupByLibrary.simpleMessage("College: "), "conclude": MessageLookupByLibrary.simpleMessage("Done"), "configured_buses": MessageLookupByLibrary.simpleMessage("Configured Buses"), @@ -77,6 +79,10 @@ class MessageLookup extends MessageLookupByLibrary { "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B | AEFEUP building"), + "current_state": + MessageLookupByLibrary.simpleMessage("Current state: "), + "current_year": + MessageLookupByLibrary.simpleMessage("Current academic year: "), "description": MessageLookupByLibrary.simpleMessage("Description"), "desired_email": MessageLookupByLibrary.simpleMessage( "Email where you want to be contacted"), @@ -84,6 +90,7 @@ class MessageLookup extends MessageLookupByLibrary { "D. Beatriz\'s stationery store"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B (B-142)"), + "ects": MessageLookupByLibrary.simpleMessage("ECTs performed: "), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "empty_text": @@ -94,6 +101,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), "fee_notification": MessageLookupByLibrary.simpleMessage("Notify next deadline:"), + "first_year_registration": MessageLookupByLibrary.simpleMessage( + "Year of first registration: "), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), "geral_registration": @@ -114,6 +123,10 @@ class MessageLookup extends MessageLookupByLibrary { "news": MessageLookupByLibrary.simpleMessage("News"), "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), + "no_classes": + MessageLookupByLibrary.simpleMessage("No classes to present"), + "no_classes_on": + MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -124,6 +137,8 @@ class MessageLookup extends MessageLookupByLibrary { "There is no information available about meals"), "no_menus": MessageLookupByLibrary.simpleMessage( "There are no meals available"), + "no_name_course": + MessageLookupByLibrary.simpleMessage("Unnamed course"), "no_results": MessageLookupByLibrary.simpleMessage("No match"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( "There are no course units to display"), @@ -153,6 +168,7 @@ class MessageLookup extends MessageLookupByLibrary { "Face-to-face and telephone assistance"), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), "title": MessageLookupByLibrary.simpleMessage("Title"), + "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), "valid_email": MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index c119ccd93..787b2fe25 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -51,6 +51,7 @@ class MessageLookup extends MessageLookupByLibrary { "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), + "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!"), @@ -67,6 +68,7 @@ class MessageLookup extends MessageLookupByLibrary { "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), + "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), @@ -77,6 +79,9 @@ class MessageLookup extends MessageLookupByLibrary { "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), "copy_center_building": MessageLookupByLibrary.simpleMessage( "Piso -1 do edifício B | Edifício da AEFEUP"), + "current_state": MessageLookupByLibrary.simpleMessage("Estado atual: "), + "current_year": + MessageLookupByLibrary.simpleMessage("Ano curricular atual: "), "description": MessageLookupByLibrary.simpleMessage("Descrição"), "desired_email": MessageLookupByLibrary.simpleMessage( "Email em que desejas ser contactado"), @@ -84,6 +89,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Piso -1 do edifício B (B-142)"), + "ects": MessageLookupByLibrary.simpleMessage("ECTs realizados: "), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( @@ -94,6 +100,8 @@ class MessageLookup extends MessageLookupByLibrary { "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( "Notificar próxima data limite:"), + "first_year_registration": + MessageLookupByLibrary.simpleMessage("Ano da primeira inscrição: "), "floor": MessageLookupByLibrary.simpleMessage("Piso"), "floors": MessageLookupByLibrary.simpleMessage("Pisos"), "geral_registration": @@ -114,6 +122,10 @@ class MessageLookup extends MessageLookupByLibrary { "news": MessageLookupByLibrary.simpleMessage("Notícias"), "no_bus_stops": MessageLookupByLibrary.simpleMessage( "Não existe nenhuma paragem configurada"), + "no_classes": MessageLookupByLibrary.simpleMessage( + "Não existem aulas para apresentar"), + "no_classes_on": + MessageLookupByLibrary.simpleMessage("Não possui aulas à"), "no_course_units": MessageLookupByLibrary.simpleMessage( "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -124,6 +136,8 @@ class MessageLookup extends MessageLookupByLibrary { "Não há informação disponível sobre refeições"), "no_menus": MessageLookupByLibrary.simpleMessage( "Não há refeições disponíveis"), + "no_name_course": + MessageLookupByLibrary.simpleMessage("Curso sem nome"), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( "Não existem cadeiras para apresentar"), @@ -153,6 +167,7 @@ class MessageLookup extends MessageLookupByLibrary { "Atendimento presencial e telefónico"), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), "title": MessageLookupByLibrary.simpleMessage("Título"), + "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), "valid_email": MessageLookupByLibrary.simpleMessage( "Por favor insere um email válido"), "widget_prompt": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 0181657c7..cdfe2989d 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:uni/generated/intl/messages_all.dart'; +import 'intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -100,6 +100,16 @@ class S { ); } + /// `Average: ` + String get average { + return Intl.message( + 'Average: ', + name: 'average', + desc: '', + args: [], + ); + } + /// `Balance:` String get balance { return Intl.message( @@ -190,6 +200,16 @@ class S { ); } + /// `College: ` + String get college { + return Intl.message( + 'College: ', + name: 'college', + desc: '', + args: [], + ); + } + /// `Done` String get conclude { return Intl.message( @@ -260,6 +280,26 @@ class S { ); } + /// `Current state: ` + String get current_state { + return Intl.message( + 'Current state: ', + name: 'current_state', + desc: '', + args: [], + ); + } + + /// `Current academic year: ` + String get current_year { + return Intl.message( + 'Current academic year: ', + name: 'current_year', + desc: '', + args: [], + ); + } + /// `Description` String get description { return Intl.message( @@ -300,6 +340,16 @@ class S { ); } + /// `ECTs performed: ` + String get ects { + return Intl.message( + 'ECTs performed: ', + name: 'ects', + desc: '', + args: [], + ); + } + /// `Edit` String get edit_off { return Intl.message( @@ -360,6 +410,16 @@ class S { ); } + /// `Year of first registration: ` + String get first_year_registration { + return Intl.message( + 'Year of first registration: ', + name: 'first_year_registration', + desc: '', + args: [], + ); + } + /// `Floor` String get floor { return Intl.message( @@ -518,6 +578,26 @@ class S { ); } + /// `No classes to present` + String get no_classes { + return Intl.message( + 'No classes to present', + name: 'no_classes', + desc: '', + args: [], + ); + } + + /// `You don't have classes on` + String get no_classes_on { + return Intl.message( + 'You don\'t have classes on', + name: 'no_classes_on', + desc: '', + args: [], + ); + } + /// `No course units in the selected period` String get no_course_units { return Intl.message( @@ -568,6 +648,16 @@ class S { ); } + /// `Unnamed course` + String get no_name_course { + return Intl.message( + 'Unnamed course', + name: 'no_name_course', + desc: '', + args: [], + ); + } + /// `No match` String get no_results { return Intl.message( @@ -758,6 +848,16 @@ class S { ); } + /// `Unavailable` + String get unavailable { + return Intl.message( + 'Unavailable', + name: 'unavailable', + desc: '', + args: [], + ); + } + /// `Please enter a valid email` String get valid_email { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 5778da1f5..b27b0c251 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -10,6 +10,8 @@ "@add_widget": {}, "all_widgets_added": "All available widgets have already been added to your personal area!", "@all_widgets_added": {}, + "average": "Average: ", + "@average": {}, "balance": "Balance:", "@balance": {}, "bs_description": "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!", @@ -28,6 +30,8 @@ "@cancel": {}, "class_registration": "Class Registration", "@class_registration": {}, + "college": "College: ", + "@college": {}, "conclude": "Done", "@conclude": {}, "configured_buses": "Configured Buses", @@ -42,6 +46,10 @@ "@copy_center": {}, "copy_center_building": "Floor -1 of building B | AEFEUP building", "@copy_center_building": {}, + "current_state": "Current state: ", + "@current_state": {}, + "current_year": "Current academic year: ", + "@current_year": {}, "description": "Description", "@description": {}, "desired_email": "Email where you want to be contacted", @@ -50,6 +58,8 @@ "@dona_bia": {}, "dona_bia_building": "Floor -1 of building B (B-142)", "@dona_bia_building": {}, + "ects": "ECTs performed: ", + "@ects": {}, "edit_off": "Edit", "@edit_off": {}, "edit_on": "Finish editing", @@ -62,6 +72,8 @@ "@fee_date": {}, "fee_notification": "Notify next deadline:", "@fee_notification": {}, + "first_year_registration": "Year of first registration: ", + "@first_year_registration": {}, "floor": "Floor", "@floor": {}, "floors": "Floors", @@ -98,6 +110,10 @@ "@news": {}, "no_bus_stops": "No configured stops", "@no_bus_stops": {}, + "no_classes": "No classes to present", + "@no_classes": {}, + "no_classes_on": "You don't have classes on", + "@no_classes_on": {}, "no_course_units": "No course units in the selected period", "@no_course_units": {}, "no_data": "There is no data to show at this time", @@ -108,6 +124,8 @@ "@no_menu_info": {}, "no_menus": "There are no meals available", "@no_menus": {}, + "no_name_course": "Unnamed course", + "@no_name_course": {}, "no_results": "No match", "@no_results": {}, "no_selected_courses": "There are no course units to display", @@ -146,6 +164,8 @@ "@telephone": {}, "title": "Title", "@title": {}, + "unavailable": "Unavailable", + "@unavailable": {}, "valid_email": "Please enter a valid email", "@valid_email": {}, "widget_prompt": "Choose a widget to add to your personal area:", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 4a6c48c60..103ec3056 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -10,6 +10,8 @@ "@add_widget": {}, "all_widgets_added": "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", "@all_widgets_added": {}, + "average": "Média: ", + "@average": {}, "balance": "Saldo:", "@balance": {}, "bs_description": "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!", @@ -28,6 +30,8 @@ "@cancel": {}, "class_registration": "Inscrição de Turmas", "@class_registration": {}, + "college": "Faculdade: ", + "@college": {}, "conclude": "Concluído", "@conclude": {}, "configured_buses": "Autocarros Configurados", @@ -42,6 +46,10 @@ "@copy_center": {}, "copy_center_building": "Piso -1 do edifício B | Edifício da AEFEUP", "@copy_center_building": {}, + "current_state": "Estado atual: ", + "@current_state": {}, + "current_year": "Ano curricular atual: ", + "@current_year": {}, "description": "Descrição", "@description": {}, "desired_email": "Email em que desejas ser contactado", @@ -50,6 +58,8 @@ "@dona_bia": {}, "dona_bia_building": "Piso -1 do edifício B (B-142)", "@dona_bia_building": {}, + "ects": "ECTs realizados: ", + "@ects": {}, "edit_off": "Editar\n", "@edit_off": {}, "edit_on": "Concluir edição", @@ -62,6 +72,8 @@ "@fee_date": {}, "fee_notification": "Notificar próxima data limite:", "@fee_notification": {}, + "first_year_registration": "Ano da primeira inscrição: ", + "@first_year_registration": {}, "floor": "Piso", "@floor": {}, "floors": "Pisos", @@ -98,6 +110,10 @@ "@news": {}, "no_bus_stops": "Não existe nenhuma paragem configurada", "@no_bus_stops": {}, + "no_classes": "Não existem aulas para apresentar", + "@no_classes": {}, + "no_classes_on": "Não possui aulas à", + "@no_classes_on": {}, "no_course_units": "Sem cadeiras no período selecionado", "@no_course_units": {}, "no_data": "Não há dados a mostrar neste momento", @@ -108,6 +124,8 @@ "@no_menu_info": {}, "no_menus": "Não há refeições disponíveis", "@no_menus": {}, + "no_name_course": "Curso sem nome", + "@no_name_course": {}, "no_results": "Sem resultados", "@no_results": {}, "no_selected_courses": "Não existem cadeiras para apresentar", @@ -146,6 +164,8 @@ "@telephone": {}, "title": "Título", "@title": {}, + "unavailable": "Indisponível", + "@unavailable": {}, "valid_email": "Por favor insere um email válido", "@valid_email": {}, "widget_prompt": "Escolhe um widget para adicionares à tua área pessoal:", diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 353ac3a0c..712e9e1f9 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -74,6 +74,7 @@ Future main() async { final savedTheme = await AppSharedPreferences.getThemeMode(); + final savedLocale = await AppSharedPreferences.getLocale(); await SentryFlutter.init((options) { options.dsn = 'https://a2661645df1c4992b24161010c5e0ecb@o553498.ingest.sentry.io/5680848'; @@ -113,7 +114,7 @@ Future main() async { create: (context) => stateProviders.homePageEditingMode), ], child: ChangeNotifierProvider( - create: (_) => ThemeNotifier(savedTheme), + create: (_) => ThemeNotifier(savedTheme, savedLocale), child: const MyApp(), ))) }); @@ -143,6 +144,7 @@ class MyAppState extends State { theme: applicationLightTheme, darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), + locale: themeNotifier.getLocale(), home: const SplashScreen(), localizationsDelegates: const [ S.delegate, 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 9099973ec..8f0909836 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 @@ -4,6 +4,7 @@ import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/theme_notifier.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/main.dart'; class AppNavigationDrawer extends StatefulWidget { final BuildContext parentContext; @@ -84,6 +85,37 @@ class AppNavigationDrawerState extends State { ); } + Widget createLocaleBtn() { + String getLocaleText(String locale) { + switch (locale) { + case 'pt_PT': + return 'PT'; + default: + return 'EN'; + } + } + + return Consumer( + builder: (context, themeNotifier, _) { + return TextButton( + onPressed: () => themeNotifier.setNextLocale(), + style: TextButton.styleFrom( + elevation: 0, + padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 5.0), + ), + child: Container( + padding: const EdgeInsets.all(15.0), + child: Text(getLocaleText(themeNotifier.getLocale().toString()), + style: Theme.of(context) + .textTheme + .titleLarge! + .copyWith(color: Theme.of(context).primaryColor)), + ), + ); + }, + ); + } + Widget createThemeSwitchBtn() { Icon getThemeIcon(ThemeMode theme) { switch (theme) { @@ -146,7 +178,14 @@ class AppNavigationDrawerState extends State { ), )), Row(children: [ - Expanded(child: createLogoutBtn()), + Expanded(child: Align( + alignment: Alignment.center, + child: createLogoutBtn(), + )), + Align( + alignment: Alignment.centerRight, + child: createLocaleBtn(), + ), createThemeSwitchBtn() ]) ], diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index 1fc8280ff..c49a71485 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -32,7 +32,7 @@ class ScheduleCard extends GenericCard { content: lectureProvider.lectures, contentChecker: lectureProvider.lectures.isNotEmpty, onNullContent: Center( - child: Text('Não existem aulas para apresentar', + child: Text(S.of(context).no_classes, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center)), contentLoadingWidget: const ScheduleCardShimmer().build(context)) diff --git a/uni/lib/view/profile/widgets/course_info_card.dart b/uni/lib/view/profile/widgets/course_info_card.dart index ca6c4a9f3..435ce30a5 100644 --- a/uni/lib/view/profile/widgets/course_info_card.dart +++ b/uni/lib/view/profile/widgets/course_info_card.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:uni/generated/l10n.dart'; /// Manages the courses info (course name, atual year, state and year of /// first enrolment) on the user personal page. @@ -17,31 +18,31 @@ class CourseInfoCard extends GenericCard { TableRow(children: [ Container( margin: const EdgeInsets.only(top: 20.0, bottom: 8.0, left: 20.0), - child: Text('Ano curricular atual: ', + child: Text(S.of(context).current_year, style: Theme.of(context).textTheme.titleSmall), ), Container( margin: const EdgeInsets.only(top: 20.0, bottom: 8.0, right: 20.0), - child: getInfoText(course.currYear ?? 'Indisponível', context), + child: getInfoText(course.currYear ?? S.of(context).unavailable, context), ) ]), TableRow(children: [ Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), - child: Text('Estado atual: ', + child: Text(S.of(context).current_state, style: Theme.of(context).textTheme.titleSmall), ), Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), - child: getInfoText(course.state ?? 'Indisponível', context), + child: getInfoText(course.state ?? S.of(context).unavailable, context), ) ]), TableRow(children: [ Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), - child: Text('Ano da primeira inscrição: ', + child: Text(S.of(context).first_year_registration, style: Theme.of(context).textTheme.titleSmall), ), Container( @@ -56,33 +57,33 @@ class CourseInfoCard extends GenericCard { TableRow(children: [ Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), - child: Text('Faculdade: ', + child: Text(S.of(context).college, style: Theme.of(context).textTheme.titleSmall), ), Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText( - course.faculty?.toUpperCase() ?? 'Indisponível', context)) + course.faculty?.toUpperCase() ?? S.of(context).unavailable, context)) ]), TableRow(children: [ Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, left: 20.0), - child: Text('Média: ', + child: Text(S.of(context).average, style: Theme.of(context).textTheme.titleSmall), ), Container( margin: const EdgeInsets.only(top: 10.0, bottom: 8.0, right: 20.0), child: getInfoText( - course.currentAverage?.toString() ?? 'Indisponível', + course.currentAverage?.toString() ?? S.of(context).unavailable, context)) ]), TableRow(children: [ Container( margin: const EdgeInsets.only(top: 10.0, bottom: 20.0, left: 20.0), - child: Text('ECTs realizados: ', + child: Text(S.of(context).ects, style: Theme.of(context).textTheme.titleSmall), ), Container( @@ -98,7 +99,7 @@ class CourseInfoCard extends GenericCard { @override String getTitle(context) { - return course.name ?? 'Curso sem nome'; + return course.name ?? S.of(context).no_course_units; } @override diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 3c61d3ec5..b2181b969 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -181,7 +181,7 @@ class SchedulePageViewState extends GeneralPageViewState contentChecker: aggLectures[day].isNotEmpty, onNullContent: Center( child: Text( - 'Não possui aulas à ${SchedulePageView.daysOfTheWeek[day]}.')), + '${S.of(context).no_classes_on} ${SchedulePageView.daysOfTheWeek[day]}.')), ); } } diff --git a/uni/lib/view/theme_notifier.dart b/uni/lib/view/theme_notifier.dart index 626a55ba8..ff2005c19 100644 --- a/uni/lib/view/theme_notifier.dart +++ b/uni/lib/view/theme_notifier.dart @@ -1,13 +1,17 @@ import 'package:flutter/material.dart'; +import 'dart:io'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; class ThemeNotifier with ChangeNotifier { - ThemeNotifier(this._themeMode); + ThemeNotifier(this._themeMode, this._locale); ThemeMode _themeMode; + Locale _locale; getTheme() => _themeMode; + getLocale() => _locale; + setNextTheme() { final nextThemeMode = (_themeMode.index + 1) % 3; setTheme(ThemeMode.values[nextThemeMode]); @@ -18,4 +22,22 @@ class ThemeNotifier with ChangeNotifier { AppSharedPreferences.setThemeMode(themeMode); notifyListeners(); } + + setNextLocale() { + final nextLocale; + if(_locale == Locale('pt', 'PT')) nextLocale = Locale('en', 'US'); + else nextLocale = Locale('pt', 'PT'); + setLocale(nextLocale); + } + + setLocale(Locale locale) { + _locale = locale; + AppSharedPreferences.setLocale(locale); + notifyListeners(); + } } + + + + + From f8999bb51b010e933d7a8aab40f573d04bc4325e Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 3 Jul 2023 14:28:08 +0100 Subject: [PATCH 022/199] Fix locale offline storage --- .../local_storage/app_shared_preferences.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index e9c49d2e3..b806a87ff 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -17,7 +17,8 @@ class AppSharedPreferences { 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 String locale = 'app_locale'; static const int keyLength = 32; @@ -88,15 +89,15 @@ class AppSharedPreferences { return prefs.setInt(themeMode, (themeIndex + 1) % 3); } - static setLocale(Locale app_locale) async { + static setLocale(Locale appLocale) async { final prefs = await SharedPreferences.getInstance(); - prefs.setString(locale, app_locale.toString()); + prefs.setString(locale, appLocale.languageCode); } static Future getLocale() async { final prefs = await SharedPreferences.getInstance(); - final test = prefs.getString(locale) ?? 'en_US'; - return Locale.fromSubtags(languageCode: test.substring(0,3), countryCode: test.substring(0,3)); + final appLocale = prefs.getString(locale) ?? 'en'; + return Locale(appLocale); } /// Deletes the user's student number and password. @@ -215,14 +216,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); } - } From d307477edd0ec39253af525c2ca3c09cffad597f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 5 Jul 2023 03:26:22 +0100 Subject: [PATCH 023/199] Login page translated, button error fix, new locale notifier --- .../local_storage/app_shared_preferences.dart | 4 +- uni/lib/generated/intl/messages_all.dart | 10 +- uni/lib/generated/intl/messages_en.dart | 18 +++ uni/lib/generated/intl/messages_pt-PT.dart | 19 +++ uni/lib/generated/l10n.dart | 122 +++++++++++++++++- uni/lib/l10n/intl_en.arb | 24 ++++ uni/lib/l10n/intl_pt_PT.arb | 24 ++++ uni/lib/main.dart | 16 ++- uni/lib/model/entities/time_utilities.dart | 5 +- .../general/widgets/navigation_drawer.dart | 26 ++-- .../widgets/library_occupation_card.dart | 2 +- uni/lib/view/locale_notifier.dart | 27 ++++ uni/lib/view/login/login.dart | 9 +- .../login/widgets/faculties_multiselect.dart | 7 +- .../widgets/faculties_selection_form.dart | 9 +- uni/lib/view/login/widgets/inputs.dart | 27 ++-- uni/lib/view/theme_notifier.dart | 19 +-- 17 files changed, 293 insertions(+), 75 deletions(-) create mode 100644 uni/lib/view/locale_notifier.dart diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index b806a87ff..f7fad291d 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -89,9 +89,9 @@ class AppSharedPreferences { return prefs.setInt(themeMode, (themeIndex + 1) % 3); } - static setLocale(Locale appLocale) async { + static setLocale(String appLocale) async { final prefs = await SharedPreferences.getInstance(); - prefs.setString(locale, appLocale.languageCode); + prefs.setString(locale, appLocale); } static Future getLocale() async { diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 171385879..525f677ec 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -16,8 +16,8 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'messages_en.dart' as messages_en; -import 'messages_pt-PT.dart' as messages_pt_pt; +import 'package:uni/generated/intl/messages_en.dart' as messages_en; +import 'package:uni/generated/intl/messages_pt-PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { @@ -38,13 +38,13 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) { - var availableLocale = Intl.verifiedLocale( + final availableLocale = Intl.verifiedLocale( localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { return new SynchronousFuture(false); } - var lib = _deferredLibraries[availableLocale]; + final lib = _deferredLibraries[availableLocale]; lib == null ? new SynchronousFuture(false) : lib(); initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); @@ -60,7 +60,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var actualLocale = + final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 880c8856e..e27c996c1 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -49,8 +49,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Checking account"), "add": MessageLookupByLibrary.simpleMessage("Add"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), + "agree_terms": MessageLookupByLibrary.simpleMessage( + "By entering you confirm that you agree with these Terms and Conditions"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "All available widgets have already been added to your personal area!"), + "at_least_one_college": + MessageLookupByLibrary.simpleMessage("Select at least one college"), "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( @@ -69,6 +73,8 @@ class MessageLookup extends MessageLookupByLibrary { "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), "college": MessageLookupByLibrary.simpleMessage("College: "), + "college_select": + MessageLookupByLibrary.simpleMessage("select your college(s)"), "conclude": MessageLookupByLibrary.simpleMessage("Done"), "configured_buses": MessageLookupByLibrary.simpleMessage("Configured Buses"), @@ -97,6 +103,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Please fill in this field"), "exams_filter": MessageLookupByLibrary.simpleMessage("Exam Filter Settings"), + "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), "fee_date": MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), "fee_notification": @@ -105,16 +112,20 @@ class MessageLookup extends MessageLookupByLibrary { "Year of first registration: "), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), + "forgot_password": + MessageLookupByLibrary.simpleMessage("Forgot password?"), "geral_registration": MessageLookupByLibrary.simpleMessage("General Registration"), "improvement_registration": MessageLookupByLibrary.simpleMessage("Enrollment for Improvement"), + "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), "last_refresh_time": m0, "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), "loading_terms": MessageLookupByLibrary.simpleMessage( "Loading Terms and Conditions..."), + "login": MessageLookupByLibrary.simpleMessage("Login"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), "multimedia_center": @@ -127,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("No classes to present"), "no_classes_on": MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), + "no_college": MessageLookupByLibrary.simpleMessage("no college"), "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -147,8 +159,11 @@ class MessageLookup extends MessageLookupByLibrary { "occurrence_type": MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), + "password": MessageLookupByLibrary.simpleMessage("password"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "press_again": + MessageLookupByLibrary.simpleMessage("Press again to exit"), "print": MessageLookupByLibrary.simpleMessage("Print"), "problem_id": MessageLookupByLibrary.simpleMessage( "Brief identification of the problem"), @@ -161,12 +176,15 @@ class MessageLookup extends MessageLookupByLibrary { "An error occurred in sending"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "student_number": + MessageLookupByLibrary.simpleMessage("student number"), "success": MessageLookupByLibrary.simpleMessage("Sent with success"), "tele_assistance": MessageLookupByLibrary.simpleMessage("Telephone assistance"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( "Face-to-face and telephone assistance"), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), + "terms": MessageLookupByLibrary.simpleMessage("Terms and Conditions"), "title": MessageLookupByLibrary.simpleMessage("Title"), "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), "valid_email": diff --git a/uni/lib/generated/intl/messages_pt-PT.dart b/uni/lib/generated/intl/messages_pt-PT.dart index 787b2fe25..eaa1d5c99 100644 --- a/uni/lib/generated/intl/messages_pt-PT.dart +++ b/uni/lib/generated/intl/messages_pt-PT.dart @@ -49,8 +49,12 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Conta Corrente"), "add": MessageLookupByLibrary.simpleMessage("Adicionar"), "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), + "agree_terms": MessageLookupByLibrary.simpleMessage( + "Ao entrares confirmas que concordas com estes Termos e Condições"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), + "at_least_one_college": MessageLookupByLibrary.simpleMessage( + "Seleciona pelo menos uma faculdade"), "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( @@ -69,6 +73,8 @@ class MessageLookup extends MessageLookupByLibrary { "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), + "college_select": MessageLookupByLibrary.simpleMessage( + "seleciona a(s) tua(s) faculdade(s)"), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), @@ -96,6 +102,7 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor preenche este campo"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), + "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), "fee_date": MessageLookupByLibrary.simpleMessage( "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( @@ -104,16 +111,21 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ano da primeira inscrição: "), "floor": MessageLookupByLibrary.simpleMessage("Piso"), "floors": MessageLookupByLibrary.simpleMessage("Pisos"), + "forgot_password": + MessageLookupByLibrary.simpleMessage("Esqueceu a palavra-passe?"), "geral_registration": MessageLookupByLibrary.simpleMessage("Inscrição Geral"), "improvement_registration": MessageLookupByLibrary.simpleMessage("Inscrição para Melhoria"), + "keep_login": + MessageLookupByLibrary.simpleMessage("Manter sessão iniciada"), "last_refresh_time": m0, "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "loading_terms": MessageLookupByLibrary.simpleMessage( "Carregando os Termos e Condições..."), + "login": MessageLookupByLibrary.simpleMessage("Entrar"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), "multimedia_center": @@ -126,6 +138,7 @@ class MessageLookup extends MessageLookupByLibrary { "Não existem aulas para apresentar"), "no_classes_on": MessageLookupByLibrary.simpleMessage("Não possui aulas à"), + "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), "no_course_units": MessageLookupByLibrary.simpleMessage( "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( @@ -146,8 +159,11 @@ class MessageLookup extends MessageLookupByLibrary { "occurrence_type": MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), + "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "press_again": MessageLookupByLibrary.simpleMessage( + "Pressione novamente para sair"), "print": MessageLookupByLibrary.simpleMessage("Impressão"), "problem_id": MessageLookupByLibrary.simpleMessage( "Breve identificação do problema"), @@ -160,12 +176,15 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "student_number": + MessageLookupByLibrary.simpleMessage("número de estudante"), "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), "tele_assistance": MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( "Atendimento presencial e telefónico"), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), + "terms": MessageLookupByLibrary.simpleMessage("Termos e Condições"), "title": MessageLookupByLibrary.simpleMessage("Título"), "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), "valid_email": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index cdfe2989d..347c23271 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'intl/messages_all.dart'; +import 'package:uni/generated/intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -90,6 +90,16 @@ class S { ); } + /// `By entering you confirm that you agree with these Terms and Conditions` + String get agree_terms { + return Intl.message( + 'By entering you confirm that you agree with these Terms and Conditions', + name: 'agree_terms', + desc: '', + args: [], + ); + } + /// `All available widgets have already been added to your personal area!` String get all_widgets_added { return Intl.message( @@ -100,6 +110,16 @@ class S { ); } + /// `Select at least one college` + String get at_least_one_college { + return Intl.message( + 'Select at least one college', + name: 'at_least_one_college', + desc: '', + args: [], + ); + } + /// `Average: ` String get average { return Intl.message( @@ -210,6 +230,16 @@ class S { ); } + /// `select your college(s)` + String get college_select { + return Intl.message( + 'select your college(s)', + name: 'college_select', + desc: '', + args: [], + ); + } + /// `Done` String get conclude { return Intl.message( @@ -390,6 +420,16 @@ class S { ); } + /// `Login failed` + String get failed_login { + return Intl.message( + 'Login failed', + name: 'failed_login', + desc: '', + args: [], + ); + } + /// `Deadline for next fee:` String get fee_date { return Intl.message( @@ -440,6 +480,16 @@ class S { ); } + /// `Forgot password?` + String get forgot_password { + return Intl.message( + 'Forgot password?', + name: 'forgot_password', + desc: '', + args: [], + ); + } + /// `General Registration` String get geral_registration { return Intl.message( @@ -460,6 +510,16 @@ class S { ); } + /// `Stay signed in` + String get keep_login { + return Intl.message( + 'Stay signed in', + name: 'keep_login', + desc: '', + args: [], + ); + } + /// `last refresh at {time}` String last_refresh_time(Object time) { return Intl.message( @@ -503,6 +563,16 @@ class S { ); } + /// `Login` + String get login { + return Intl.message( + 'Login', + name: 'login', + desc: '', + args: [], + ); + } + /// `Log out` String get logout { return Intl.message( @@ -598,6 +668,16 @@ class S { ); } + /// `no college` + String get no_college { + return Intl.message( + 'no college', + name: 'no_college', + desc: '', + args: [], + ); + } + /// `No course units in the selected period` String get no_course_units { return Intl.message( @@ -708,6 +788,16 @@ class S { ); } + /// `password` + String get password { + return Intl.message( + 'password', + name: 'password', + desc: '', + args: [], + ); + } + /// `Face-to-face assistance` String get personal_assistance { return Intl.message( @@ -718,6 +808,16 @@ class S { ); } + /// `Press again to exit` + String get press_again { + return Intl.message( + 'Press again to exit', + name: 'press_again', + desc: '', + args: [], + ); + } + /// `Print` String get print { return Intl.message( @@ -798,6 +898,16 @@ class S { ); } + /// `student number` + String get student_number { + return Intl.message( + 'student number', + name: 'student_number', + desc: '', + args: [], + ); + } + /// `Sent with success` String get success { return Intl.message( @@ -838,6 +948,16 @@ class S { ); } + /// `Terms and Conditions` + String get terms { + return Intl.message( + 'Terms and Conditions', + name: 'terms', + desc: '', + args: [], + ); + } + /// `Title` String get title { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index b27b0c251..04087fe44 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -8,8 +8,12 @@ "@add": {}, "add_widget": "Add widget", "@add_widget": {}, + "agree_terms": "By entering you confirm that you agree with these Terms and Conditions", + "@agree_terms": {}, "all_widgets_added": "All available widgets have already been added to your personal area!", "@all_widgets_added": {}, + "at_least_one_college": "Select at least one college", + "@at_least_one_college": {}, "average": "Average: ", "@average": {}, "balance": "Balance:", @@ -32,6 +36,8 @@ "@class_registration": {}, "college": "College: ", "@college": {}, + "college_select": "select your college(s)", + "@college_select": {}, "conclude": "Done", "@conclude": {}, "configured_buses": "Configured Buses", @@ -68,6 +74,8 @@ "@empty_text": {}, "exams_filter": "Exam Filter Settings", "@exams_filter": {}, + "failed_login": "Login failed", + "@failed_login": {}, "fee_date": "Deadline for next fee:", "@fee_date": {}, "fee_notification": "Notify next deadline:", @@ -78,10 +86,14 @@ "@floor": {}, "floors": "Floors", "@floors": {}, + "forgot_password": "Forgot password?", + "@forgot_password": {}, "geral_registration": "General Registration", "@geral_registration": {}, "improvement_registration": "Enrollment for Improvement", "@improvement_registration": {}, + "keep_login": "Stay signed in", + "@keep_login": {}, "last_refresh_time": "last refresh at {time}", "@last_refresh_time": { "placeholders": { @@ -98,6 +110,8 @@ "@library_occupation": {}, "loading_terms": "Loading Terms and Conditions...", "@loading_terms": {}, + "login": "Login", + "@login": {}, "logout": "Log out", "@logout": {}, "menus": "Menus", @@ -114,6 +128,8 @@ "@no_classes": {}, "no_classes_on": "You don't have classes on", "@no_classes_on": {}, + "no_college": "no college", + "@no_college": {}, "no_course_units": "No course units in the selected period", "@no_course_units": {}, "no_data": "There is no data to show at this time", @@ -136,8 +152,12 @@ "@occurrence_type": {}, "other_links": "Other links", "@other_links": {}, + "password": "password", + "@password": {}, "personal_assistance": "Face-to-face assistance", "@personal_assistance": {}, + "press_again": "Press again to exit", + "@press_again": {}, "print": "Print", "@print": {}, "problem_id": "Brief identification of the problem", @@ -154,6 +174,8 @@ "@sent_error": {}, "stcp_stops": "STCP - Upcoming Trips", "@stcp_stops": {}, + "student_number": "student number", + "@student_number": {}, "success": "Sent with success", "@success": {}, "tele_assistance": "Telephone assistance", @@ -162,6 +184,8 @@ "@tele_personal_assistance": {}, "telephone": "Telephone", "@telephone": {}, + "terms": "Terms and Conditions", + "@terms": {}, "title": "Title", "@title": {}, "unavailable": "Unavailable", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 103ec3056..529e103f0 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -8,8 +8,12 @@ "@add": {}, "add_widget": "Adicionar widget", "@add_widget": {}, + "agree_terms": "Ao entrares confirmas que concordas com estes Termos e Condições", + "@agree_terms": {}, "all_widgets_added": "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", "@all_widgets_added": {}, + "at_least_one_college": "Seleciona pelo menos uma faculdade", + "@at_least_one_college": {}, "average": "Média: ", "@average": {}, "balance": "Saldo:", @@ -32,6 +36,8 @@ "@class_registration": {}, "college": "Faculdade: ", "@college": {}, + "college_select": "seleciona a(s) tua(s) faculdade(s)", + "@college_select": {}, "conclude": "Concluído", "@conclude": {}, "configured_buses": "Autocarros Configurados", @@ -68,6 +74,8 @@ "@empty_text": {}, "exams_filter": "Definições Filtro de Exames", "@exams_filter": {}, + "failed_login": "O login falhou", + "@failed_login": {}, "fee_date": "Data limite próxima prestação:", "@fee_date": {}, "fee_notification": "Notificar próxima data limite:", @@ -78,10 +86,14 @@ "@floor": {}, "floors": "Pisos", "@floors": {}, + "forgot_password": "Esqueceu a palavra-passe?", + "@forgot_password": {}, "geral_registration": "Inscrição Geral", "@geral_registration": {}, "improvement_registration": "Inscrição para Melhoria", "@improvement_registration": {}, + "keep_login": "Manter sessão iniciada", + "@keep_login": {}, "last_refresh_time": "última atualização às {time}", "@last_refresh_time": { "placeholders": { @@ -98,6 +110,8 @@ "@library_occupation": {}, "loading_terms": "Carregando os Termos e Condições...", "@loading_terms": {}, + "login": "Entrar", + "@login": {}, "logout": "Terminar sessão", "@logout": {}, "menus": "Ementas", @@ -114,6 +128,8 @@ "@no_classes": {}, "no_classes_on": "Não possui aulas à", "@no_classes_on": {}, + "no_college": "sem faculdade", + "@no_college": {}, "no_course_units": "Sem cadeiras no período selecionado", "@no_course_units": {}, "no_data": "Não há dados a mostrar neste momento", @@ -136,8 +152,12 @@ "@occurrence_type": {}, "other_links": "Outros links", "@other_links": {}, + "password": "palavra-passe", + "@password": {}, "personal_assistance": "Atendimento presencial", "@personal_assistance": {}, + "press_again": "Pressione novamente para sair", + "@press_again": {}, "print": "Impressão", "@print": {}, "problem_id": "Breve identificação do problema", @@ -154,6 +174,8 @@ "@sent_error": {}, "stcp_stops": "STCP - Próximas Viagens", "@stcp_stops": {}, + "student_number": "número de estudante", + "@student_number": {}, "success": "Enviado com sucesso", "@success": {}, "tele_assistance": "Atendimento telefónico", @@ -162,6 +184,8 @@ "@tele_personal_assistance": {}, "telephone": "Telefone", "@telephone": {}, + "terms": "Termos e Condições", + "@terms": {}, "title": "Título", "@title": {}, "unavailable": "Indisponível", diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 712e9e1f9..c83bd1079 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -33,6 +33,7 @@ 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/locale_notifier.dart'; import 'package:uni/view/locations/locations.dart'; import 'package:uni/view/logout_route.dart'; import 'package:uni/view/navigation_service.dart'; @@ -113,9 +114,12 @@ Future main() async { ChangeNotifierProvider( create: (context) => stateProviders.homePageEditingMode), ], - child: ChangeNotifierProvider( - create: (_) => ThemeNotifier(savedTheme, savedLocale), - child: const MyApp(), + child: ChangeNotifierProvider( + create: (_) => LocaleNotifier(savedLocale), + child: ChangeNotifierProvider( + create: (_) => ThemeNotifier(savedTheme), + child: const MyApp(), + ), ))) }); } @@ -138,13 +142,13 @@ class MyAppState extends State { SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); - return Consumer( - builder: (context, themeNotifier, _) => MaterialApp( + return Consumer2( + builder: (context, themeNotifier, localeNotifier, _) => MaterialApp( title: 'uni', theme: applicationLightTheme, darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), - locale: themeNotifier.getLocale(), + locale: localeNotifier.getLocale(), home: const SplashScreen(), localizationsDelegates: const [ S.delegate, diff --git a/uni/lib/model/entities/time_utilities.dart b/uni/lib/model/entities/time_utilities.dart index 45072ba4e..e36599eb7 100644 --- a/uni/lib/model/entities/time_utilities.dart +++ b/uni/lib/model/entities/time_utilities.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; extension TimeString on DateTime { @@ -28,8 +27,6 @@ extension TimeString on DateTime { 'Sunday' ]; - final String locale = Platform.localeName; - if (!startMonday) { weekdaysPT.removeAt(6); weekdaysEN.removeAt(6); @@ -37,7 +34,7 @@ extension TimeString on DateTime { weekdaysEN.insert(0, 'Sunday'); } - if(locale == 'pt_PT') return includeWeekend ? weekdaysPT : weekdaysPT.sublist(0, 5); + // TODO migration i18n return includeWeekend ? weekdaysEN : weekdaysEN.sublist(0, 5); 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 8f0909836..86fc01a76 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 @@ -3,8 +3,8 @@ import 'package:provider/provider.dart'; import 'package:uni/model/providers/session_provider.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/theme_notifier.dart'; +import 'package:uni/view/locale_notifier.dart'; import 'package:uni/generated/l10n.dart'; -import 'package:uni/main.dart'; class AppNavigationDrawer extends StatefulWidget { final BuildContext parentContext; @@ -67,7 +67,7 @@ class AppNavigationDrawerState extends State { } Widget createLogoutBtn() { - final String logOutText = S.of(context).logout; + const String logOutText = "Terminar sessão"; return TextButton( onPressed: () => _onLogOut(logOutText), style: TextButton.styleFrom( @@ -76,7 +76,7 @@ class AppNavigationDrawerState extends State { ), child: Container( padding: const EdgeInsets.all(15.0), - child: Text(logOutText, + child: Text(S.of(context).logout, style: Theme.of(context) .textTheme .titleLarge! @@ -86,26 +86,24 @@ class AppNavigationDrawerState extends State { } Widget createLocaleBtn() { - String getLocaleText(String locale) { - switch (locale) { - case 'pt_PT': - return 'PT'; - default: - return 'EN'; - } + String getLocaleText(Locale locale) { + final String appLocale; + locale == const Locale('pt') ? appLocale = 'PT' : appLocale = 'EN'; + return appLocale; } - return Consumer( - builder: (context, themeNotifier, _) { + return Consumer( + builder: (context, localeNotifier, _) { + return TextButton( - onPressed: () => themeNotifier.setNextLocale(), + onPressed: () => localeNotifier.setNextLocale(), style: TextButton.styleFrom( elevation: 0, padding: const EdgeInsets.symmetric(vertical: 0.0, horizontal: 5.0), ), child: Container( padding: const EdgeInsets.all(15.0), - child: Text(getLocaleText(themeNotifier.getLocale().toString()), + child: Text(getLocaleText(localeNotifier.getLocale()), style: Theme.of(context) .textTheme .titleLarge! diff --git a/uni/lib/view/library/widgets/library_occupation_card.dart b/uni/lib/view/library/widgets/library_occupation_card.dart index 8afc4431d..e277a0cf3 100644 --- a/uni/lib/view/library/widgets/library_occupation_card.dart +++ b/uni/lib/view/library/widgets/library_occupation_card.dart @@ -40,7 +40,7 @@ class LibraryOccupationCard extends GenericCard { Widget generateOccupation(occupation, context) { if (occupation == null || occupation.capacity == 0) { return Center( - child: Text('Não existem dados para apresentar', + child: Text(S.of(context).no_data, style: Theme.of(context).textTheme.titleLarge, textAlign: TextAlign.center)); } diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart new file mode 100644 index 000000000..70b0ccd10 --- /dev/null +++ b/uni/lib/view/locale_notifier.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; + +class LocaleNotifier with ChangeNotifier { + LocaleNotifier(this._locale); + + Locale _locale; + + getLocale() => _locale; + + setNextLocale() { + final Locale nextLocale; + _locale == const Locale('pt') ? nextLocale = const Locale('en') : nextLocale = const Locale('pt'); + setLocale(nextLocale); + } + + setLocale(Locale locale) { + _locale = locale; + AppSharedPreferences.setLocale(locale.languageCode); + notifyListeners(); + } +} + + + + + diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 571e6b2a4..a59ac69dc 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -9,6 +9,7 @@ import 'package:uni/model/providers/state_providers.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:uni/generated/l10n.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:uni/view/theme.dart'; @@ -147,7 +148,7 @@ class LoginPageViewState extends State { if (_exitApp) { return Future.value(true); } - ToastMessage.info(context, 'Pressione novamente para sair'); + ToastMessage.info(context, S.of(context).press_again); exitAppWaiter(); return Future.value(false); } @@ -189,7 +190,7 @@ class LoginPageViewState extends State { _toggleObscurePasswordInput, () => _login(context)), Padding(padding: EdgeInsets.only(bottom: queryData.size.height / 35)), - createSaveDataCheckBox(_keepSignedIn, _setKeepSignedIn), + createSaveDataCheckBox(context, _keepSignedIn, _setKeepSignedIn), ]), ), ); @@ -199,7 +200,7 @@ class LoginPageViewState extends State { Widget createForgetPasswordLink(BuildContext context) { return InkWell( child: Center( - child: Text("Esqueceu a palavra-passe?", + child: Text(S.of(context).forgot_password, style: Theme.of(context).textTheme.bodyLarge!.copyWith( decoration: TextDecoration.underline, color: Colors.white))), @@ -231,7 +232,7 @@ class LoginPageViewState extends State { Navigator.pushReplacementNamed( context, '/${DrawerItem.navPersonalArea.title}'); } else if (status == RequestStatus.failed) { - ToastMessage.error(context, 'O login falhou'); + ToastMessage.error(context, S.of(context).failed_login); } } } diff --git a/uni/lib/view/login/widgets/faculties_multiselect.dart b/uni/lib/view/login/widgets/faculties_multiselect.dart index ce315d539..3f77d0dd2 100644 --- a/uni/lib/view/login/widgets/faculties_multiselect.dart +++ b/uni/lib/view/login/widgets/faculties_multiselect.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/view/login/widgets/faculties_selection_form.dart'; +import 'package:uni/generated/l10n.dart'; class FacultiesMultiselect extends StatelessWidget { final List selectedFaculties; @@ -39,7 +40,7 @@ class FacultiesMultiselect extends StatelessWidget { child: Row(children: [ Expanded( child: Text( - _facultiesListText(), + _facultiesListText(context), style: const TextStyle(color: Colors.white), ), ), @@ -50,9 +51,9 @@ class FacultiesMultiselect extends StatelessWidget { ])); } - String _facultiesListText() { + String _facultiesListText(BuildContext context) { if (selectedFaculties.isEmpty) { - return 'sem faculdade'; + return S.of(context).no_college; } String facultiesText = ''; for (String faculty in selectedFaculties) { diff --git a/uni/lib/view/login/widgets/faculties_selection_form.dart b/uni/lib/view/login/widgets/faculties_selection_form.dart index 7ce700eb8..dfa5870f2 100644 --- a/uni/lib/view/login/widgets/faculties_selection_form.dart +++ b/uni/lib/view/login/widgets/faculties_selection_form.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/utils/constants.dart' as constants; import 'package:uni/view/common_widgets/toast_message.dart'; +import 'package:uni/generated/l10n.dart'; class FacultiesSelectionForm extends StatefulWidget { final List selectedFaculties; @@ -18,7 +19,7 @@ class _FacultiesSelectionFormState extends State { Widget build(BuildContext context) { return AlertDialog( backgroundColor: const Color.fromARGB(255, 0x75, 0x17, 0x1e), - title: const Text('seleciona a(s) tua(s) faculdade(s)'), + title: Text(S.of(context).college_select), titleTextStyle: const TextStyle( color: Color.fromARGB(255, 0xfa, 0xfa, 0xfa), fontSize: 18), content: SizedBox( @@ -30,7 +31,7 @@ class _FacultiesSelectionFormState extends State { return [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('Cancelar', style: TextStyle(color: Colors.white))), + child: Text(S.of(context).cancel, style: const TextStyle(color: Colors.white))), ElevatedButton( style: ElevatedButton.styleFrom( foregroundColor: Theme.of(context).primaryColor, @@ -38,13 +39,13 @@ class _FacultiesSelectionFormState extends State { onPressed: () { if (widget.selectedFaculties.isEmpty) { ToastMessage.warning( - context, 'Seleciona pelo menos uma faculdade'); + context, S.of(context).at_least_one_college); return; } Navigator.pop(context); widget.setFaculties(widget.selectedFaculties); }, - child: const Text('Confirmar')) + child: Text(S.of(context).confirm)) ]; } diff --git a/uni/lib/view/login/widgets/inputs.dart b/uni/lib/view/login/widgets/inputs.dart index b40da8720..40da926af 100644 --- a/uni/lib/view/login/widgets/inputs.dart +++ b/uni/lib/view/login/widgets/inputs.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/view/login/widgets/faculties_multiselect.dart'; import 'package:uni/view/about/widgets/terms_and_conditions.dart'; +import 'package:uni/generated/l10n.dart'; /// Creates the widget for the user to choose their faculty Widget createFacultyInput( @@ -27,8 +28,8 @@ Widget createUsernameInput( }, textInputAction: TextInputAction.next, textAlign: TextAlign.left, - decoration: textFieldDecoration('número de estudante'), - validator: (String? value) => value!.isEmpty ? 'Preenche este campo' : null, + decoration: textFieldDecoration(S.of(context).student_number), + validator: (String? value) => value!.isEmpty ? S.of(context).empty_text : null, ); } @@ -54,20 +55,20 @@ Widget createPasswordInput( obscureText: obscurePasswordInput, textAlign: TextAlign.left, decoration: passwordFieldDecoration( - 'palavra-passe', obscurePasswordInput, toggleObscurePasswordInput), + S.of(context).password, obscurePasswordInput, toggleObscurePasswordInput), validator: (String? value) => - value != null && value.isEmpty ? 'Preenche este campo' : null); + value != null && value.isEmpty ? S.of(context).empty_text : null); } /// Creates the widget for the user to keep signed in (save his data). -Widget createSaveDataCheckBox(bool keepSignedIn, setKeepSignedIn) { +Widget createSaveDataCheckBox(BuildContext context, bool keepSignedIn, setKeepSignedIn) { return CheckboxListTile( value: keepSignedIn, onChanged: setKeepSignedIn, - title: const Text( - 'Manter sessão iniciada', + title: Text( + S.of(context).keep_login, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( color: Colors.white, fontSize: 17.0, fontWeight: FontWeight.w300), ), ); @@ -93,7 +94,7 @@ Widget createLogInButton(queryData, BuildContext context, login) { } login(context); }, - child: Text('Entrar', + child: Text(S.of(context).login, style: TextStyle( color: Theme.of(context).primaryColor, fontWeight: FontWeight.w400, @@ -149,10 +150,10 @@ createSafeLoginButton(BuildContext context) { highlightColor: Colors.transparent, child: Container( padding: const EdgeInsets.all(8), - child: const Text( - '''Ao entrares confirmas que concordas com estes Termos e Condições''', + child: Text( + S.of(context).agree_terms, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( decoration: TextDecoration.underline, color: Colors.white, fontSize: 17.0, @@ -166,7 +167,7 @@ Future _showLoginDetails(BuildContext context) async { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('Termos e Condições'), + title: Text(S.of(context).terms), content: const SingleChildScrollView(child: TermsAndConditions()), actions: [ SimpleDialogOption( diff --git a/uni/lib/view/theme_notifier.dart b/uni/lib/view/theme_notifier.dart index ff2005c19..028e9d28e 100644 --- a/uni/lib/view/theme_notifier.dart +++ b/uni/lib/view/theme_notifier.dart @@ -1,17 +1,13 @@ import 'package:flutter/material.dart'; -import 'dart:io'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; class ThemeNotifier with ChangeNotifier { - ThemeNotifier(this._themeMode, this._locale); + ThemeNotifier(this._themeMode); ThemeMode _themeMode; - Locale _locale; getTheme() => _themeMode; - getLocale() => _locale; - setNextTheme() { final nextThemeMode = (_themeMode.index + 1) % 3; setTheme(ThemeMode.values[nextThemeMode]); @@ -22,19 +18,6 @@ class ThemeNotifier with ChangeNotifier { AppSharedPreferences.setThemeMode(themeMode); notifyListeners(); } - - setNextLocale() { - final nextLocale; - if(_locale == Locale('pt', 'PT')) nextLocale = Locale('en', 'US'); - else nextLocale = Locale('pt', 'PT'); - setLocale(nextLocale); - } - - setLocale(Locale locale) { - _locale = locale; - AppSharedPreferences.setLocale(locale); - notifyListeners(); - } } From 11b865daf5b0db7deb17ed651e9c321ebddaaff1 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 5 Jul 2023 23:48:22 +0100 Subject: [PATCH 024/199] Weekdays translation --- uni/lib/generated/intl/messages_en.dart | 2 +- uni/lib/generated/l10n.dart | 4 +-- uni/lib/l10n/intl_en.arb | 2 +- uni/lib/model/entities/time_utilities.dart | 35 ------------------- .../general/widgets/navigation_drawer.dart | 7 +--- uni/lib/view/home/widgets/schedule_card.dart | 6 ++-- uni/lib/view/locale_notifier.dart | 11 ++++++ .../view/restaurant/restaurant_page_view.dart | 4 +-- uni/lib/view/schedule/schedule.dart | 19 +++++----- 9 files changed, 29 insertions(+), 61 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index e27c996c1..479bd937e 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -37,7 +37,7 @@ class MessageLookup extends MessageLookupByLibrary { 'biblioteca': 'Library', 'uteis': 'Utils', 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', + 'bugs': 'Bugs and Suggestions', 'other': 'Other', })}"; diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 347c23271..6ab20c517 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -603,7 +603,7 @@ class S { ); } - /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}` + /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}` String nav_title(Object title) { return Intl.select( title, @@ -619,7 +619,7 @@ class S { 'biblioteca': 'Library', 'uteis': 'Utils', 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', + 'bugs': 'Bugs and Suggestions', 'other': 'Other', }, name: 'nav_title', diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 04087fe44..4e2742689 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -118,7 +118,7 @@ "@menus": {}, "multimedia_center": "Multimedia center", "@multimedia_center": {}, - "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}", + "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs and Suggestions} other{Other}}", "@nav_title": {}, "news": "News", "@news": {}, diff --git a/uni/lib/model/entities/time_utilities.dart b/uni/lib/model/entities/time_utilities.dart index e36599eb7..1d4ae066a 100644 --- a/uni/lib/model/entities/time_utilities.dart +++ b/uni/lib/model/entities/time_utilities.dart @@ -4,41 +4,6 @@ extension TimeString on DateTime { String toTimeHourMinString() { return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}'; } - - static List getWeekdaysStrings({bool startMonday = true, bool includeWeekend = true}) { - - final List weekdaysPT = [ - 'Segunda-Feira', - 'Terça-Feira', - 'Quarta-Feira', - 'Quinta-Feira', - 'Sexta-Feira', - 'Sábado', - 'Domingo' - ]; - - final List weekdaysEN = [ - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday' - ]; - - if (!startMonday) { - weekdaysPT.removeAt(6); - weekdaysEN.removeAt(6); - weekdaysPT.insert(0, 'Domingo'); - weekdaysEN.insert(0, 'Sunday'); - } - - // TODO migration i18n - return includeWeekend ? weekdaysEN : weekdaysEN.sublist(0, 5); - - - } } extension ClosestMonday on DateTime{ 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 86fc01a76..579bb9028 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 @@ -86,11 +86,6 @@ class AppNavigationDrawerState extends State { } Widget createLocaleBtn() { - String getLocaleText(Locale locale) { - final String appLocale; - locale == const Locale('pt') ? appLocale = 'PT' : appLocale = 'EN'; - return appLocale; - } return Consumer( builder: (context, localeNotifier, _) { @@ -103,7 +98,7 @@ class AppNavigationDrawerState extends State { ), child: Container( padding: const EdgeInsets.all(15.0), - child: Text(getLocaleText(localeNotifier.getLocale()), + child: Text(localeNotifier.getLocale().languageCode.toUpperCase(), style: Theme.of(context) .textTheme .titleLarge! diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index c49a71485..ea9fc3f7e 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -1,12 +1,12 @@ 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/generated/l10n.dart'; import 'package:uni/model/providers/lecture_provider.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/locale_notifier.dart'; import 'package:uni/view/schedule/widgets/schedule_slot.dart'; import 'package:uni/view/home/widgets/schedule_card_shimmer.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -59,7 +59,7 @@ 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: Provider.of(context).getWeekdaysWithLocale()[(lectures[i].startTime.weekday-1) % 7])); } rows.add(createRowFromLecture(context, lectures[i])); @@ -69,7 +69,7 @@ class ScheduleCard extends GenericCard { } if (rows.isEmpty) { - rows.add(DateRectangle(date: TimeString.getWeekdaysStrings()[lectures[0].startTime.weekday % 7])); + rows.add(DateRectangle(date: Provider.of(context).getWeekdaysWithLocale()[lectures[0].startTime.weekday % 7])); rows.add(createRowFromLecture(context, lectures[0])); } return rows; diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart index 70b0ccd10..dceb20fdc 100644 --- a/uni/lib/view/locale_notifier.dart +++ b/uni/lib/view/locale_notifier.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; +import 'package:intl/intl.dart'; class LocaleNotifier with ChangeNotifier { LocaleNotifier(this._locale); @@ -19,6 +20,16 @@ class LocaleNotifier with ChangeNotifier { AppSharedPreferences.setLocale(locale.languageCode); notifyListeners(); } + + getWeekdaysWithLocale() { + final List weekdays = []; + for(String weekday in DateFormat.EEEE(_locale.languageCode).dateSymbols.WEEKDAYS){ + weekdays.add(weekday[0].toUpperCase() + weekday.substring(1)); + } + weekdays.removeAt(0); + weekdays[5] == 'Saturday' ? weekdays.add('Sunday') : weekdays.add('Domingo'); + return weekdays; + } } diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index c47129ddf..afb352a8f 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -3,7 +3,6 @@ import 'package:uni/model/entities/meal.dart'; import 'package:flutter/material.dart'; import 'package:uni/model/providers/restaurant_provider.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/model/entities/time_utilities.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'; @@ -11,6 +10,7 @@ import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; +import 'package:uni/view/locale_notifier.dart'; import 'package:uni/view/restaurant/widgets/restaurant_page_card.dart'; import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; @@ -89,7 +89,7 @@ class _CanteenPageState extends GeneralPageViewState } List createTabs(BuildContext context) { - final List daysOfTheWeek = TimeString.getWeekdaysStrings(includeWeekend: true); + final List daysOfTheWeek = Provider.of(context).getWeekdaysWithLocale(); final List tabs = []; for (var i = 0; i < DayOfWeek.values.length; i++) { diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index b2181b969..9d0b96783 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -2,7 +2,6 @@ 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/generated/l10n.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -10,6 +9,7 @@ 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/schedule/widgets/schedule_slot.dart'; +import 'package:uni/view/locale_notifier.dart'; class SchedulePage extends StatefulWidget { const SchedulePage({Key? key}) : super(key: key); @@ -43,13 +43,10 @@ class SchedulePageView extends StatefulWidget { final int weekDay = DateTime.now().weekday; - static final List daysOfTheWeek = - TimeString.getWeekdaysStrings(includeWeekend: false); - static List> groupLecturesByDay(schedule) { final aggLectures = >[]; - for (int i = 0; i < daysOfTheWeek.length; i++) { + for (int i = 0; i < 5; i++) { final Set lectures = {}; for (int j = 0; j < schedule.length; j++) { if (schedule[j].startTime.weekday-1 == i) lectures.add(schedule[j]); @@ -72,10 +69,10 @@ class SchedulePageViewState extends GeneralPageViewState void initState() { super.initState(); tabController = TabController( - vsync: this, length: SchedulePageView.daysOfTheWeek.length); + vsync: this, length: 5); final offset = (widget.weekDay > 5) ? 0 - : (widget.weekDay - 1) % SchedulePageView.daysOfTheWeek.length; + : (widget.weekDay - 1) % 5; tabController?.animateTo((tabController!.index + offset)); } @@ -115,12 +112,12 @@ class SchedulePageViewState extends GeneralPageViewState /// Returns a list of widgets empty with tabs for each day of the week. List createTabs(queryData, BuildContext context) { final List tabs = []; - for (var i = 0; i < SchedulePageView.daysOfTheWeek.length; i++) { + for (var i = 0; i < 5; i++) { tabs.add(SizedBox( width: queryData.size.width * 1 / 4, child: Tab( key: Key('schedule-page-tab-$i'), - text: SchedulePageView.daysOfTheWeek[i]), + text: Provider.of(context).getWeekdaysWithLocale()[i]), )); } return tabs; @@ -129,7 +126,7 @@ class SchedulePageViewState extends GeneralPageViewState List createSchedule( context, List? lectures, RequestStatus? scheduleStatus) { final List tabBarViewContent = []; - for (int i = 0; i < SchedulePageView.daysOfTheWeek.length; i++) { + for (int i = 0; i < 5; i++) { tabBarViewContent .add(createScheduleByDay(context, i, lectures, scheduleStatus)); } @@ -181,7 +178,7 @@ class SchedulePageViewState extends GeneralPageViewState contentChecker: aggLectures[day].isNotEmpty, onNullContent: Center( child: Text( - '${S.of(context).no_classes_on} ${SchedulePageView.daysOfTheWeek[day]}.')), + '${S.of(context).no_classes_on} ${Provider.of(context).getWeekdaysWithLocale()[day]}.')), ); } } From 651a538edb0e1eb2976fd9bc6d26f964230063ee Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 6 Jul 2023 21:31:41 +0100 Subject: [PATCH 025/199] Lint and test fixing --- uni/pubspec.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index a9d5e52e8..443e343c2 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -167,8 +167,4 @@ flutter_icons: image_path: "assets/icon/icon.png" adaptive_icon_background: "#75171E" adaptive_icon_foreground: "assets/icon/android_icon_foreground.png" -flutter_intl: - enabled: true - localizely: - project_id: 788a209d-5f55-4f7d-ad09-6033b2b65fc1 From 5766b157df4450521bd9d0f6f7e7a7459b710940 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 6 Jul 2023 23:34:19 +0100 Subject: [PATCH 026/199] Test fixing --- uni/test/test_widget.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 012869d06..d3c1ecc61 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.dart'; Widget testableWidget(Widget widget, {List providers = const []}) { @@ -11,6 +12,12 @@ Widget testableWidget(Widget widget, Widget wrapWidget(Widget widget) { return MaterialApp( home: Scaffold( - body: widget, + body: Localizations( + delegates: const [ + S.delegate, + ], + locale: const Locale('pt'), + child: widget, + ), )); } From 36ca90589bc9204ea2e6c63f9c44511b014b6dc4 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 14 Jul 2023 23:50:55 +0100 Subject: [PATCH 027/199] Restaurant card redesign --- .../view/home/widgets/restaurant_card.dart | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index a5f52cea2..6ec32af12 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -24,7 +24,7 @@ class RestaurantCard extends GenericCard { String getTitle() => 'Restaurantes'; @override - onClick(BuildContext context) => null; + onClick(BuildContext context) => Navigator.pushNamed(context, '/${DrawerItem.navRestaurants.title}'); @override Widget buildCardContent(BuildContext context) { @@ -72,11 +72,12 @@ class RestaurantCard extends GenericCard { return Column(children: [ Center( child: Container( - padding: const EdgeInsets.all(15.0), child: Text(restaurant.name)),), + padding: const EdgeInsets.all(15.0), child: Text(restaurant.name, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold))),), if(meals.isNotEmpty) Card( - elevation: 1, + elevation: 0, child: RowContainer( + borderColor: Colors.transparent, color: const Color.fromARGB(0, 0, 0, 0), child: Column( mainAxisSize: MainAxisSize.min, @@ -85,16 +86,16 @@ class RestaurantCard extends GenericCard { ) else Card( - elevation: 1, + elevation: 0, child: RowContainer( - color: const Color.fromARGB(0, 0, 0, 0), - child: Container( - padding: const EdgeInsets.all(12.0), - child: const SizedBox( - width: 400, - child: Text("Não há refeições disponíveis", textAlign: TextAlign.center), - )) + borderColor: Colors.transparent, + color: const Color.fromARGB(0, 0, 0, 0), + child: Container( + padding: const EdgeInsets.all(12.0), + width: 400, + child: const Text("Não há refeições disponíveis", textAlign: TextAlign.center), )) + ) ]); } From c2d1c1f6eedb0e7e53625d1dc486da0a85ab3027 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sat, 15 Jul 2023 21:18:37 +0100 Subject: [PATCH 028/199] Restaurants titles redesign --- uni/lib/view/home/widgets/restaurant_card.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 6ec32af12..d0f41708c 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -72,6 +72,7 @@ class RestaurantCard extends GenericCard { return Column(children: [ Center( child: Container( + alignment: Alignment.centerLeft, padding: const EdgeInsets.all(15.0), child: Text(restaurant.name, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold))),), if(meals.isNotEmpty) Card( From 003666bb544cd35dba30d7c326e423d16156ceab Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 20 Jul 2023 21:13:47 +0100 Subject: [PATCH 029/199] Card redesign --- uni/lib/view/home/widgets/restaurant_card.dart | 6 +++--- uni/lib/view/restaurant/widgets/restaurant_slot.dart | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index d0f41708c..8d8bfeea5 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -73,7 +73,7 @@ class RestaurantCard extends GenericCard { Center( child: Container( alignment: Alignment.centerLeft, - padding: const EdgeInsets.all(15.0), child: Text(restaurant.name, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold))),), + padding: const EdgeInsets.fromLTRB(12, 20, 12, 5), child: Text(restaurant.name, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold))),), if(meals.isNotEmpty) Card( elevation: 0, @@ -92,9 +92,9 @@ class RestaurantCard extends GenericCard { borderColor: Colors.transparent, color: const Color.fromARGB(0, 0, 0, 0), child: Container( - padding: const EdgeInsets.all(12.0), + padding: const EdgeInsets.fromLTRB(9, 0, 0, 0), width: 400, - child: const Text("Não há refeições disponíveis", textAlign: TextAlign.center), + child: const Text("Não há refeições disponíveis"), )) ) ]); diff --git a/uni/lib/view/restaurant/widgets/restaurant_slot.dart b/uni/lib/view/restaurant/widgets/restaurant_slot.dart index 15ecc621e..424299d36 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_slot.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_slot.dart @@ -24,7 +24,7 @@ class RestaurantSlot extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: - const EdgeInsets.only(top: 10.0, bottom: 10.0, left: 10, right: 22.0), + const EdgeInsets.fromLTRB(9, 3.5, 0, 3.5), child: Container( key: Key('cantine-slot-type-$type'), child: Row( From 98f216989404be55d6ef9e210e0dddedb3f78f22 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 24 Jul 2023 22:35:06 +0100 Subject: [PATCH 030/199] Weekday and restart bug fix --- uni/lib/model/providers/lazy/restaurant_provider.dart | 1 + uni/lib/view/home/widgets/restaurant_card.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/uni/lib/model/providers/lazy/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart index 9bdd6a383..7a22b20c2 100644 --- a/uni/lib/model/providers/lazy/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -29,6 +29,7 @@ class RestaurantProvider extends StateProviderNotifier { final RestaurantDatabase restaurantDb = RestaurantDatabase(); final List restaurants = await restaurantDb.getRestaurants(); _restaurants = restaurants; + _favoriteRestaurants = await AppSharedPreferences.getFavoriteRestaurants(); } @override diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 94f004132..2c84c7dc4 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -11,8 +11,6 @@ import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; import 'package:uni/view/lazy_consumer.dart'; -final int weekDay = DateTime.now().weekday; -final offset = (weekDay > 5) ? 0 : (weekDay - 1) % DayOfWeek.values.length; class RestaurantCard extends GenericCard { RestaurantCard({Key? key}) : super(key: key); @@ -58,6 +56,8 @@ class RestaurantCard extends GenericCard { Widget generateRestaurants(dynamic data, BuildContext context) { + final int weekDay = DateTime.now().weekday; + final offset = (weekDay - 1) % 7; final List restaurants = data; return ListView.builder( shrinkWrap: true, From 59abeb9323e929811e48403ee4eee83f3a038297 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 25 Jul 2023 00:14:02 +0100 Subject: [PATCH 031/199] Format fix --- .../local_storage/app_shared_preferences.dart | 6 +- .../providers/lazy/restaurant_provider.dart | 11 +- uni/lib/view/common_widgets/generic_card.dart | 45 ++++---- .../view/home/widgets/restaurant_card.dart | 105 ++++++++++-------- .../view/restaurant/restaurant_page_view.dart | 37 +++--- .../widgets/restaurant_page_card.dart | 24 ++-- .../restaurant/widgets/restaurant_slot.dart | 3 +- 7 files changed, 119 insertions(+), 112 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index a5bed59ae..8e9691fdf 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -174,7 +174,8 @@ class AppSharedPreferences { static Future> getFavoriteRestaurants() async { final prefs = await SharedPreferences.getInstance(); - final List storedFavoriteRestaurants = prefs.getStringList(favoriteRestaurants) ?? []; + final List storedFavoriteRestaurants = + prefs.getStringList(favoriteRestaurants) ?? []; return storedFavoriteRestaurants; } @@ -204,7 +205,7 @@ class AppSharedPreferences { static Future> getFilteredExams() async { final prefs = await SharedPreferences.getInstance(); final List? storedFilteredExamTypes = - prefs.getStringList(filteredExamsTypes); + prefs.getStringList(filteredExamsTypes); if (storedFilteredExamTypes == null) { return Map.fromIterable(defaultFilteredExamTypes, value: (type) => true); @@ -241,4 +242,3 @@ class AppSharedPreferences { prefs.setBool(tuitionNotificationsToggleKey, value); } } - diff --git a/uni/lib/model/providers/lazy/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart index 398d67efb..28d958b12 100644 --- a/uni/lib/model/providers/lazy/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -39,7 +39,7 @@ class RestaurantProvider extends StateProviderNotifier { Future fetchRestaurants(Session session) async { try { final List restaurants = - await RestaurantFetcher().getRestaurants(session); + await RestaurantFetcher().getRestaurants(session); final RestaurantDatabase db = RestaurantDatabase(); db.saveRestaurants(restaurants); @@ -51,14 +51,16 @@ class RestaurantProvider extends StateProviderNotifier { } } - setFavoriteRestaurants(List newFavoriteRestaurants, Completer action) async { + setFavoriteRestaurants( + List newFavoriteRestaurants, Completer action) async { _favoriteRestaurants = List.from(newFavoriteRestaurants); AppSharedPreferences.saveFavoriteRestaurants(favoriteRestaurants); action.complete(); notifyListeners(); } - toggleFavoriteRestaurant(String restaurantName, Completer action) async { + toggleFavoriteRestaurant( + String restaurantName, Completer action) async { _favoriteRestaurants.contains(restaurantName) ? _favoriteRestaurants.remove(restaurantName) : _favoriteRestaurants.add(restaurantName); @@ -67,11 +69,10 @@ class RestaurantProvider extends StateProviderNotifier { action.complete(); } - void updateStateBasedOnLocalRestaurants() async{ + void updateStateBasedOnLocalRestaurants() async { final RestaurantDatabase restaurantDb = RestaurantDatabase(); final List restaurants = await restaurantDb.getRestaurants(); _restaurants = restaurants; notifyListeners(); } } - diff --git a/uni/lib/view/common_widgets/generic_card.dart b/uni/lib/view/common_widgets/generic_card.dart index d10f68074..4a8be7c47 100644 --- a/uni/lib/view/common_widgets/generic_card.dart +++ b/uni/lib/view/common_widgets/generic_card.dart @@ -19,7 +19,7 @@ abstract class GenericCard extends StatefulWidget { const GenericCard.customStyle( {Key? key, required this.editingMode, - this.cardAction = const SizedBox.shrink(), + this.cardAction = const SizedBox.shrink(), required this.onDelete, this.margin = const EdgeInsets.symmetric(vertical: 10, horizontal: 20), this.hasSmallTitle = false}) @@ -104,19 +104,20 @@ class GenericCardState extends State { children: [ Flexible( child: Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.symmetric(horizontal: 15), - margin: const EdgeInsets.only(top: 15, bottom: 10), - child: Text(widget.getTitle(), - style: (widget.hasSmallTitle - ? Theme.of(context).textTheme.titleLarge! - : Theme.of(context) - .textTheme - .headlineSmall!) - .copyWith( - color: Theme.of(context).primaryColor)), - ) - ), + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 15), + margin: const EdgeInsets.only(top: 15, bottom: 10), + child: Text(widget.getTitle(), + style: (widget.hasSmallTitle + ? Theme.of(context) + .textTheme + .titleLarge! + : Theme.of(context) + .textTheme + .headlineSmall!) + .copyWith( + color: Theme.of(context).primaryColor)), + )), widget.cardAction, if (widget.editingMode) Container( @@ -142,18 +143,16 @@ class GenericCardState extends State { ))); } - - Widget getDeleteIcon(context) { return Flexible( child: Container( - alignment: Alignment.centerRight, - height: 32, - child: IconButton( - iconSize: 22, - icon: const Icon(Icons.delete), - tooltip: 'Remover', - onPressed: widget.onDelete, + alignment: Alignment.centerRight, + height: 32, + child: IconButton( + iconSize: 22, + icon: const Icon(Icons.delete), + tooltip: 'Remover', + onPressed: widget.onDelete, ), )); } diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 2c84c7dc4..3631b1f18 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -11,7 +11,6 @@ import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/restaurant/widgets/restaurant_slot.dart'; import 'package:uni/view/lazy_consumer.dart'; - class RestaurantCard extends GenericCard { RestaurantCard({Key? key}) : super(key: key); @@ -23,7 +22,8 @@ class RestaurantCard extends GenericCard { String getTitle() => 'Restaurantes'; @override - onClick(BuildContext context) => Navigator.pushNamed(context, '/${DrawerItem.navRestaurants.title}'); + onClick(BuildContext context) => + Navigator.pushNamed(context, '/${DrawerItem.navRestaurants.title}'); @override void onRefresh(BuildContext context) { @@ -35,26 +35,29 @@ class RestaurantCard extends GenericCard { Widget buildCardContent(BuildContext context) { return LazyConsumer( builder: (context, restaurantProvider) { - final List favoriteRestaurants = restaurantProvider.restaurants.where((restaurant) => restaurantProvider.favoriteRestaurants.contains(restaurant.name)).toList(); - return RequestDependentWidgetBuilder( - status: restaurantProvider.status, - builder: () => - generateRestaurants(favoriteRestaurants, context), - hasContentPredicate: favoriteRestaurants.isNotEmpty, - onNullContent: Column(children: [ - Padding( - padding: const EdgeInsets.only(top: 15, bottom: 10), - child: Center( - child: Text('Sem restaurantes favoritos', - style: Theme.of(context).textTheme.titleMedium))), - OutlinedButton( - onPressed: () => Navigator.pushNamed(context, '/${DrawerItem.navRestaurants.title}'), - child: const Text('Adicionar')) - ])); - }); + final List favoriteRestaurants = restaurantProvider + .restaurants + .where((restaurant) => + restaurantProvider.favoriteRestaurants.contains(restaurant.name)) + .toList(); + return RequestDependentWidgetBuilder( + status: restaurantProvider.status, + builder: () => generateRestaurants(favoriteRestaurants, context), + hasContentPredicate: favoriteRestaurants.isNotEmpty, + onNullContent: Column(children: [ + Padding( + padding: const EdgeInsets.only(top: 15, bottom: 10), + child: Center( + child: Text('Sem restaurantes favoritos', + style: Theme.of(context).textTheme.titleMedium))), + OutlinedButton( + onPressed: () => Navigator.pushNamed( + context, '/${DrawerItem.navRestaurants.title}'), + child: const Text('Adicionar')) + ])); + }); } - Widget generateRestaurants(dynamic data, BuildContext context) { final int weekDay = DateTime.now().weekday; final offset = (weekDay - 1) % 7; @@ -67,44 +70,49 @@ class RestaurantCard extends GenericCard { return Column( mainAxisSize: MainAxisSize.min, children: [ - createRowFromRestaurant(context, restaurants[index], DayOfWeek.values[offset]) + createRowFromRestaurant( + context, restaurants[index], DayOfWeek.values[offset]) ], ); }, ); } - - Widget createRowFromRestaurant(context, Restaurant restaurant, DayOfWeek day) { + Widget createRowFromRestaurant( + context, Restaurant restaurant, DayOfWeek day) { final List meals = restaurant.getMealsOfDay(day); return Column(children: [ Center( - child: Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.fromLTRB(12, 20, 12, 5), child: Text(restaurant.name, style: TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold))),), - if(meals.isNotEmpty) - Card( - elevation: 0, - child: RowContainer( - borderColor: Colors.transparent, - color: const Color.fromARGB(0, 0, 0, 0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: createRestaurantRows(meals, context), - )), - ) + child: Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.fromLTRB(12, 20, 12, 5), + child: Text(restaurant.name, + style: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.bold))), + ), + if (meals.isNotEmpty) + Card( + elevation: 0, + child: RowContainer( + borderColor: Colors.transparent, + color: const Color.fromARGB(0, 0, 0, 0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: createRestaurantRows(meals, context), + )), + ) else - Card( - elevation: 0, - child: RowContainer( - borderColor: Colors.transparent, - color: const Color.fromARGB(0, 0, 0, 0), - child: Container( - padding: const EdgeInsets.fromLTRB(9, 0, 0, 0), - width: 400, - child: const Text("Não há refeições disponíveis"), - )) - ) + Card( + elevation: 0, + child: RowContainer( + borderColor: Colors.transparent, + color: const Color.fromARGB(0, 0, 0, 0), + child: Container( + padding: const EdgeInsets.fromLTRB(9, 0, 0, 0), + width: 400, + child: const Text("Não há refeições disponíveis"), + ))) ]); } @@ -113,5 +121,4 @@ class RestaurantCard extends GenericCard { .map((meal) => RestaurantSlot(type: meal.type, name: meal.name)) .toList(); } - } diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 46cfef1dd..9a9e937a3 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -20,7 +20,6 @@ class RestaurantPageView extends StatefulWidget { class _RestaurantPageViewState extends GeneralPageViewState with SingleTickerProviderStateMixin { - late List aggRestaurant; late TabController tabController; late ScrollController scrollViewController; @@ -44,7 +43,8 @@ class _RestaurantPageViewState extends GeneralPageViewState Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), alignment: Alignment.center, - child: const PageTitle(name: 'Restaurantes', center: false, pad: false), + child: const PageTitle( + name: 'Restaurantes', center: false, pad: false), ), TabBar( controller: tabController, @@ -69,7 +69,8 @@ class _RestaurantPageViewState extends GeneralPageViewState List restaurantsWidgets = []; if (restaurants is List) { restaurantsWidgets = restaurants - .map((restaurant) => createRestaurant(context, restaurant, dayOfWeek)) + .map((restaurant) => + createRestaurant(context, restaurant, dayOfWeek)) .toList(); } return ListView(children: restaurantsWidgets); @@ -77,9 +78,9 @@ class _RestaurantPageViewState extends GeneralPageViewState return Expanded( child: TabBarView( - controller: tabController, - children: dayContents, - )); + controller: tabController, + children: dayContents, + )); } List createTabs(BuildContext context) { @@ -96,9 +97,9 @@ class _RestaurantPageViewState extends GeneralPageViewState } Widget createRestaurant(context, Restaurant restaurant, DayOfWeek dayOfWeek) { - return RestaurantPageCard(restaurant, createRestaurantByDay(context, restaurant, dayOfWeek)); - -} + return RestaurantPageCard( + restaurant, createRestaurantByDay(context, restaurant, dayOfWeek)); + } List createRestaurantRows(List meals, BuildContext context) { return meals @@ -111,25 +112,23 @@ class _RestaurantPageViewState extends GeneralPageViewState final List meals = restaurant.getMealsOfDay(day); if (meals.isEmpty) { return Container( - margin: - const EdgeInsets.only(top: 10, bottom: 5), + margin: const EdgeInsets.only(top: 10, bottom: 5), key: Key('cantine-page-day-column-$day'), child: Column( mainAxisSize: MainAxisSize.min, - children: - const [Center (child: Text("Não há informação disponível sobre refeições")),], - ) - ); + children: const [ + Center( + child: Text("Não há informação disponível sobre refeições")), + ], + )); } else { return Container( - margin: - const EdgeInsets.only(top: 5, bottom: 5), + margin: const EdgeInsets.only(top: 5, bottom: 5), key: Key('cantine-page-day-column-$day'), child: Column( mainAxisSize: MainAxisSize.min, children: createRestaurantRows(meals, context), - ) - ); + )); } } diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index 61fe98724..0f1307ae3 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -7,13 +7,16 @@ import 'package:uni/model/entities/restaurant.dart'; import 'package:provider/provider.dart'; import 'package:uni/model/providers/lazy/restaurant_provider.dart'; - class RestaurantPageCard extends GenericCard { final Restaurant restaurant; final Widget meals; RestaurantPageCard(this.restaurant, this.meals, {super.key}) - : super.customStyle(editingMode: false, onDelete: () => null, hasSmallTitle: true, cardAction: CardFavoriteButton(restaurant)); + : super.customStyle( + editingMode: false, + onDelete: () => null, + hasSmallTitle: true, + cardAction: CardFavoriteButton(restaurant)); @override Widget buildCardContent(BuildContext context) { @@ -40,14 +43,13 @@ class CardFavoriteButton extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer( - builder: (context, restaurantProvider, _){ - final isFavorite = restaurantProvider.favoriteRestaurants.contains(restaurant.name); - return IconButton( - icon: isFavorite ? Icon(MdiIcons.heart) : Icon(MdiIcons.heartOutline), - onPressed: () => restaurantProvider.toggleFavoriteRestaurant(restaurant.name, Completer()) - ); - } - ); + builder: (context, restaurantProvider, _) { + final isFavorite = + restaurantProvider.favoriteRestaurants.contains(restaurant.name); + return IconButton( + icon: isFavorite ? Icon(MdiIcons.heart) : Icon(MdiIcons.heartOutline), + onPressed: () => restaurantProvider.toggleFavoriteRestaurant( + restaurant.name, Completer())); + }); } } - diff --git a/uni/lib/view/restaurant/widgets/restaurant_slot.dart b/uni/lib/view/restaurant/widgets/restaurant_slot.dart index 020f48650..9408fd0e0 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_slot.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_slot.dart @@ -14,8 +14,7 @@ class RestaurantSlot extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: - const EdgeInsets.fromLTRB(9, 3.5, 0, 3.5), + padding: const EdgeInsets.fromLTRB(9, 3.5, 0, 3.5), child: Container( key: Key('cantine-slot-type-$type'), child: Row( From c8bd612739375b65d5c521101eac3e7b623f8702 Mon Sep 17 00:00:00 2001 From: thePeras Date: Fri, 28 Jul 2023 17:10:33 +0100 Subject: [PATCH 032/199] Refactor helper functions in calendar --- uni/lib/view/calendar/calendar.dart | 29 +++++-------------- .../view/calendar/widgets/calendar_tile.dart | 24 +++++++++++++++ 2 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 uni/lib/view/calendar/widgets/calendar_tile.dart diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index ffd8791b7..450942c8a 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; +import 'package:uni/view/calendar/widgets/calendar_tile.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'; @@ -20,7 +21,9 @@ class CalendarPageViewState extends GeneralPageViewState { Widget getBody(BuildContext context) { return LazyConsumer( builder: (context, calendarProvider) => ListView(children: [ - _getPageTitle(), + Container( + padding: const EdgeInsets.only(bottom: 6.0), + child: const PageTitle(name: 'Calendário Escolar')), RequestDependentWidgetBuilder( status: calendarProvider.status, builder: () => @@ -32,12 +35,6 @@ class CalendarPageViewState extends GeneralPageViewState { ])); } - Widget _getPageTitle() { - return Container( - padding: const EdgeInsets.only(bottom: 6.0), - child: const PageTitle(name: 'Calendário Escolar')); - } - Widget getTimeline(BuildContext context, List calendar) { return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( @@ -50,21 +47,9 @@ class CalendarPageViewState extends GeneralPageViewState { ), builder: TimelineTileBuilder.fromStyle( contentsAlign: ContentsAlign.alternating, - contentsBuilder: (context, index) => Padding( - padding: const EdgeInsets.all(24.0), - child: Text(calendar[index].name, - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.w500)), - ), - oppositeContentsBuilder: (context, index) => Padding( - padding: const EdgeInsets.all(24.0), - child: Text(calendar[index].date, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontStyle: FontStyle.italic, - )), - ), + contentsBuilder: (_, index) => CalendarTile(text: calendar[index].name), + oppositeContentsBuilder: (_, index) => + CalendarTile(text: calendar[index].date, isOpposite: true), itemCount: calendar.length, ), ); diff --git a/uni/lib/view/calendar/widgets/calendar_tile.dart b/uni/lib/view/calendar/widgets/calendar_tile.dart new file mode 100644 index 000000000..3f9db4cdc --- /dev/null +++ b/uni/lib/view/calendar/widgets/calendar_tile.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class CalendarTile extends StatelessWidget { + final String text; + final bool isOpposite; + const CalendarTile({Key? key, required this.text, this.isOpposite = false}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: Text(text, + style: !isOpposite + ? Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.w500) + : Theme.of(context).textTheme.titleMedium?.copyWith( + fontStyle: FontStyle.italic, + )), + ); + } +} From d873b75ed14ad8e38bc90e325e5e27dd9dc99bab Mon Sep 17 00:00:00 2001 From: thePeras Date: Fri, 28 Jul 2023 17:10:33 +0100 Subject: [PATCH 033/199] Refactor helper functions in calendar --- uni/lib/view/calendar/calendar.dart | 29 +++++-------------- .../view/calendar/widgets/calendar_tile.dart | 24 +++++++++++++++ 2 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 uni/lib/view/calendar/widgets/calendar_tile.dart diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index ffd8791b7..450942c8a 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; +import 'package:uni/view/calendar/widgets/calendar_tile.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'; @@ -20,7 +21,9 @@ class CalendarPageViewState extends GeneralPageViewState { Widget getBody(BuildContext context) { return LazyConsumer( builder: (context, calendarProvider) => ListView(children: [ - _getPageTitle(), + Container( + padding: const EdgeInsets.only(bottom: 6.0), + child: const PageTitle(name: 'Calendário Escolar')), RequestDependentWidgetBuilder( status: calendarProvider.status, builder: () => @@ -32,12 +35,6 @@ class CalendarPageViewState extends GeneralPageViewState { ])); } - Widget _getPageTitle() { - return Container( - padding: const EdgeInsets.only(bottom: 6.0), - child: const PageTitle(name: 'Calendário Escolar')); - } - Widget getTimeline(BuildContext context, List calendar) { return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( @@ -50,21 +47,9 @@ class CalendarPageViewState extends GeneralPageViewState { ), builder: TimelineTileBuilder.fromStyle( contentsAlign: ContentsAlign.alternating, - contentsBuilder: (context, index) => Padding( - padding: const EdgeInsets.all(24.0), - child: Text(calendar[index].name, - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.w500)), - ), - oppositeContentsBuilder: (context, index) => Padding( - padding: const EdgeInsets.all(24.0), - child: Text(calendar[index].date, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontStyle: FontStyle.italic, - )), - ), + contentsBuilder: (_, index) => CalendarTile(text: calendar[index].name), + oppositeContentsBuilder: (_, index) => + CalendarTile(text: calendar[index].date, isOpposite: true), itemCount: calendar.length, ), ); diff --git a/uni/lib/view/calendar/widgets/calendar_tile.dart b/uni/lib/view/calendar/widgets/calendar_tile.dart new file mode 100644 index 000000000..3f9db4cdc --- /dev/null +++ b/uni/lib/view/calendar/widgets/calendar_tile.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + +class CalendarTile extends StatelessWidget { + final String text; + final bool isOpposite; + const CalendarTile({Key? key, required this.text, this.isOpposite = false}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: Text(text, + style: !isOpposite + ? Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.w500) + : Theme.of(context).textTheme.titleMedium?.copyWith( + fontStyle: FontStyle.italic, + )), + ); + } +} From 1066db940d427c6bb76b5364392f33622dab0ffb Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 1 Aug 2023 20:28:58 +0100 Subject: [PATCH 034/199] Add code cov to test step --- .github/workflows/format_lint_test.yaml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/format_lint_test.yaml b/.github/workflows/format_lint_test.yaml index 1163a17aa..2a820260a 100644 --- a/.github/workflows/format_lint_test.yaml +++ b/.github/workflows/format_lint_test.yaml @@ -6,7 +6,7 @@ env: jobs: format: - name: 'Format' + name: "Format" runs-on: ubuntu-latest defaults: run: @@ -20,7 +20,7 @@ jobs: - run: dart format $(find . -type f -name "*.dart" -a -not -name "*.g.dart") --set-exit-if-changed lint: - name: 'Lint' + name: "Lint" runs-on: ubuntu-latest needs: format defaults: @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-java@v3 with: java-version: ${{ env.JAVA_VERSION }} - distribution: 'zulu' + distribution: "zulu" - uses: subosito/flutter-action@v2 with: flutter-version: ${{ env.FLUTTER_VERSION }} @@ -46,7 +46,7 @@ jobs: - run: flutter analyze . test: - name: 'Test' + name: "Test" runs-on: ubuntu-latest needs: lint defaults: @@ -57,9 +57,17 @@ jobs: - uses: actions/setup-java@v3 with: java-version: ${{ env.JAVA_VERSION }} - distribution: 'zulu' + distribution: "zulu" - uses: subosito/flutter-action@v2 with: flutter-version: ${{ env.FLUTTER_VERSION }} - - run: flutter test --no-sound-null-safety + - name: Test with coverage + run: flutter test --coverage --coverage=./coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + files: ./coverage/lcov.info From 5e3295d9d09d4293924c09273822c31b4dceb50f Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 1 Aug 2023 20:54:07 +0100 Subject: [PATCH 035/199] Add ignore yaml --- .github/workflows/format_lint_test.yaml | 3 +-- codecov.yml | 2 ++ uni/analysis_options.yaml | 4 +--- 3 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 codecov.yml diff --git a/.github/workflows/format_lint_test.yaml b/.github/workflows/format_lint_test.yaml index 2a820260a..d53b0f003 100644 --- a/.github/workflows/format_lint_test.yaml +++ b/.github/workflows/format_lint_test.yaml @@ -63,11 +63,10 @@ jobs: flutter-version: ${{ env.FLUTTER_VERSION }} - name: Test with coverage - run: flutter test --coverage --coverage=./coverage + run: flutter test --coverage - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true - files: ./coverage/lcov.info diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..ae5cf3b2b --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +ignore: + - "**/*.g.dart" diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index be33d4712..92d895f92 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -3,8 +3,7 @@ include: package:very_good_analysis/analysis_options.yaml analyzer: # Exclude auto-generated files from dart analysis exclude: - - '**.g.dart' - - '**.freezed.dart' + - "**.g.dart" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html @@ -13,4 +12,3 @@ linter: public_member_api_docs: false avoid_equals_and_hash_code_on_mutable_classes: false one_member_abstracts: false - From 27cd1bb6b416d8ccf32f36bddb8f8c30cfd4d700 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 1 Aug 2023 21:56:38 +0100 Subject: [PATCH 036/199] Add coverage badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 68355e652..25c1236cd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ [![Build badge](https://img.shields.io/github/actions/workflow/status/NIAEFEUP/uni/format_lint_test.yaml?style=for-the-badge)](https://github.com/NIAEFEUP/uni/actions) [![Deploy badge](https://img.shields.io/github/actions/workflow/status/NIAEFEUP/uni/deploy.yaml?label=Deploy&style=for-the-badge)](https://github.com/NIAEFEUP/uni/actions) +[![Codecov branch](https://img.shields.io/codecov/c/github/NIAEFEUP/uni/develop?style=for-the-badge)](https://app.codecov.io/gh/NIAEFEUP/uni/) [![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg?style=for-the-badge)](https://pub.dev/packages/very_good_analysis) [![License badge](https://img.shields.io/github/license/NIAEFEUP/uni?style=for-the-badge)](https://github.com/NIAEFEUP/uni/blob/develop/LICENSE) From 8f659ff4191aad9039739094e9c5465a7596d111 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 1 Aug 2023 22:43:16 +0100 Subject: [PATCH 037/199] Setup PR coverage comments --- codecov.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/codecov.yml b/codecov.yml index ae5cf3b2b..25d8f819f 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,2 +1,8 @@ ignore: - "**/*.g.dart" +comment: + layout: "diff, flags, files" + behavior: default + require_changes: false + require_base: false + require_head: true From f804bafe63c206c60cdabe4ecc8c2bd3a9c555b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 10 Aug 2023 15:29:34 +0100 Subject: [PATCH 038/199] Update flutter and dart versions and update mockito --- .../controller/local_storage/app_bus_stop_database.dart | 3 +-- uni/lib/view/bug_report/widgets/form.dart | 6 +++--- uni/lib/view/exams/widgets/exam_page_title.dart | 4 ++-- uni/lib/view/restaurant/restaurant_page_view.dart | 4 ++-- uni/lib/view/useful_info/widgets/other_links_card.dart | 6 ++---- uni/lib/view/useful_info/widgets/sigarra_links_card.dart | 4 ++-- uni/pubspec.yaml | 7 ++++--- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/uni/lib/controller/local_storage/app_bus_stop_database.dart b/uni/lib/controller/local_storage/app_bus_stop_database.dart index a62476004..fa87d324d 100644 --- a/uni/lib/controller/local_storage/app_bus_stop_database.dart +++ b/uni/lib/controller/local_storage/app_bus_stop_database.dart @@ -38,8 +38,7 @@ class AppBusStopDatabase extends AppDatabase { } final stops = {}; - groupBy(buses, (stop) => (stop! as Map)['stopCode']) - .forEach( + groupBy(buses, (stop) => stop['stopCode']).forEach( (stopCode, busCodeList) => stops[stopCode as String] = BusStopData( configuredBuses: Set.from( busCodeList.map((busEntry) => busEntry['busCode']), diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index ba6748cb6..7a7c0757a 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -117,9 +117,9 @@ class BugReportFormState extends State { Widget bugReportTitle(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(vertical: 10), - child: Row( + child: const Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: const [ + children: [ Icon(Icons.bug_report, size: 40), PageTitle(name: 'Bugs e Sugestões', center: false), Icon(Icons.bug_report, size: 40), @@ -172,7 +172,7 @@ class BugReportFormState extends State { value: _selectedBug, onChanged: (value) { setState(() { - _selectedBug = value! as int; + _selectedBug = value!; }); }, isExpanded: true, diff --git a/uni/lib/view/exams/widgets/exam_page_title.dart b/uni/lib/view/exams/widgets/exam_page_title.dart index 2e8592bc4..1ffac8819 100644 --- a/uni/lib/view/exams/widgets/exam_page_title.dart +++ b/uni/lib/view/exams/widgets/exam_page_title.dart @@ -10,9 +10,9 @@ class ExamPageTitle extends StatelessWidget { return Container( padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), alignment: Alignment.center, - child: Row( + child: const Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: const [ + children: [ PageTitle(name: 'Exames', center: false, pad: false), Material(child: ExamFilterMenu()), ], diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 55b7ad0e7..e45d20730 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -134,9 +134,9 @@ class RestaurantDay extends StatelessWidget { return Container( margin: const EdgeInsets.only(top: 10, bottom: 5), key: Key('restaurant-page-day-column-$day'), - child: Column( + child: const Column( mainAxisSize: MainAxisSize.min, - children: const [ + children: [ SizedBox(height: 10), Center( child: Text('Não há informação disponível sobre refeições'), diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 651d614db..ca2051d39 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -9,10 +9,8 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column( - children: const [ - LinkButton(title: 'Impressão', link: 'https://print.up.pt') - ], + return const Column( + children: [LinkButton(title: 'Impressão', link: 'https://print.up.pt')], ); } diff --git a/uni/lib/view/useful_info/widgets/sigarra_links_card.dart b/uni/lib/view/useful_info/widgets/sigarra_links_card.dart index 48b5fbe3a..c5e7dcd5b 100644 --- a/uni/lib/view/useful_info/widgets/sigarra_links_card.dart +++ b/uni/lib/view/useful_info/widgets/sigarra_links_card.dart @@ -9,8 +9,8 @@ class SigarraLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column( - children: const [ + return const Column( + children: [ LinkButton( title: 'Notícias', link: 'https://sigarra.up.pt/feup/pt/noticias_geral.lista_noticias', diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index fea80f960..b1a32d213 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -10,8 +10,8 @@ publish_to: 'none' # We do not publish to pub.dev version: 1.5.46+164 environment: - sdk: ">=2.17.1 <3.0.0" - flutter: 3.7.2 + sdk: '>=3.0.0 <4.0.0' + flutter: 3.10.6 # Dependencies specify other packages that the application needs in order to work. # Major versions and critical security upgrades are managed by dependabot, and @@ -59,10 +59,11 @@ dependencies: dev_dependencies: + build_runner: ^2.4.6 flutter_launcher_icons: ^0.13.1 flutter_test: sdk: flutter - mockito: ^5.2.0 + mockito: ^5.4.2 test: any very_good_analysis: ^4.0.0+1 From 1d8aae8fe984c0570f0046a076d2209e0bf141a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 10 Aug 2023 15:38:49 +0100 Subject: [PATCH 039/199] apply dart fix --- uni/lib/model/providers/lazy/bus_stop_provider.dart | 2 +- uni/lib/model/providers/lazy/lecture_provider.dart | 2 +- uni/lib/view/bug_report/widgets/form.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uni/lib/model/providers/lazy/bus_stop_provider.dart b/uni/lib/model/providers/lazy/bus_stop_provider.dart index 1c3b81a61..6df3626c1 100644 --- a/uni/lib/model/providers/lazy/bus_stop_provider.dart +++ b/uni/lib/model/providers/lazy/bus_stop_provider.dart @@ -51,7 +51,7 @@ class BusStopProvider extends StateProviderNotifier { Future addUserBusStop(String stopCode, BusStopData stopData) async { if (_configuredBusStops.containsKey(stopCode)) { - (_configuredBusStops[stopCode]!.configuredBuses).clear(); + _configuredBusStops[stopCode]!.configuredBuses.clear(); _configuredBusStops[stopCode]! .configuredBuses .addAll(stopData.configuredBuses); diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index 101e70022..a9f832a5f 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -63,7 +63,7 @@ class LectureProvider extends StateProviderNotifier { Session session, Profile profile, ) => - (fetcher?.getLectures(session, profile)) ?? getLectures(session, profile); + fetcher?.getLectures(session, profile) ?? getLectures(session, profile); Future> getLectures(Session session, Profile profile) { return ScheduleFetcherApi() diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 7a7c0757a..dfa6d8041 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -61,7 +61,7 @@ class BugReportFormState extends State { bugDescriptions.forEach( (int key, Tuple2 tup) => - {bugList.add(DropdownMenuItem(value: key, child: Text(tup.item1)))}, + bugList.add(DropdownMenuItem(value: key, child: Text(tup.item1))), ); } From 12eecacf459e30beae15054f1ba5fc190136324a Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Thu, 10 Aug 2023 20:08:45 +0000 Subject: [PATCH 040/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 8b441d358..b622faabf 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.46+164 \ No newline at end of file +1.5.47+165 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index fea80f960..58984e5ef 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.46+164 +version: 1.5.47+165 environment: sdk: ">=2.17.1 <3.0.0" From 84e12a3f55362aec3ed921ecad42377a3bfb2341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 10 Aug 2023 22:03:35 +0100 Subject: [PATCH 041/199] make build.yaml --- build.yaml | 7 + uni/test/integration/src/exams_page_test.dart | 8 +- .../src/exams_page_test.mocks.dart | 382 +++++++++++ .../integration/src/schedule_page_test.dart | 14 +- .../src/schedule_page_test.mocks.dart | 599 ++++++++++++++++++ 5 files changed, 996 insertions(+), 14 deletions(-) create mode 100644 build.yaml create mode 100644 uni/test/integration/src/exams_page_test.mocks.dart create mode 100644 uni/test/integration/src/schedule_page_test.mocks.dart diff --git a/build.yaml b/build.yaml new file mode 100644 index 000000000..3fd1459f9 --- /dev/null +++ b/build.yaml @@ -0,0 +1,7 @@ +targets: + $default: + builders: + mockito|mockBuilder: + options: + build_extensions: + '^test/{{}}.dart': 'test/mocks/{{}}.mocks.dart' \ No newline at end of file diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index c57ff9199..34d57802c 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -1,10 +1,9 @@ -// @dart=2.10 - import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; @@ -20,10 +19,7 @@ import 'package:uni/view/exams/exams.dart'; import '../../test_widget.dart'; -class MockClient extends Mock implements http.Client {} - -class MockResponse extends Mock implements http.Response {} - +@GenerateNiceMocks([MockSpec(), MockSpec()]) void main() { group('ExamsPage Integration Tests', () { final mockClient = MockClient(); diff --git a/uni/test/integration/src/exams_page_test.mocks.dart b/uni/test/integration/src/exams_page_test.mocks.dart new file mode 100644 index 000000000..71a69a4fa --- /dev/null +++ b/uni/test/integration/src/exams_page_test.mocks.dart @@ -0,0 +1,382 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in uni/test/integration/src/exams_page_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; +import 'dart:convert' as _i4; +import 'dart:typed_data' as _i5; + +import 'package:http/http.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeResponse_0 extends _i1.SmartFake implements _i2.Response { + _FakeResponse_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeStreamedResponse_1 extends _i1.SmartFake + implements _i2.StreamedResponse { + _FakeStreamedResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Client]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClient extends _i1.Mock implements _i2.Client { + @override + _i3.Future<_i2.Response> head( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> get( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> post( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> put( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> patch( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> delete( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future read( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #read, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future.value(''), + returnValueForMissingStub: _i3.Future.value(''), + ) as _i3.Future); + @override + _i3.Future<_i5.Uint8List> readBytes( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #readBytes, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i5.Uint8List>.value(_i5.Uint8List(0)), + returnValueForMissingStub: + _i3.Future<_i5.Uint8List>.value(_i5.Uint8List(0)), + ) as _i3.Future<_i5.Uint8List>); + @override + _i3.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) => + (super.noSuchMethod( + Invocation.method( + #send, + [request], + ), + returnValue: + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + ) as _i3.Future<_i2.StreamedResponse>); + @override + void close() => super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [Response]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockResponse extends _i1.Mock implements _i2.Response { + @override + _i5.Uint8List get bodyBytes => (super.noSuchMethod( + Invocation.getter(#bodyBytes), + returnValue: _i5.Uint8List(0), + returnValueForMissingStub: _i5.Uint8List(0), + ) as _i5.Uint8List); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + returnValueForMissingStub: '', + ) as String); + @override + int get statusCode => (super.noSuchMethod( + Invocation.getter(#statusCode), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + @override + Map get headers => (super.noSuchMethod( + Invocation.getter(#headers), + returnValue: {}, + returnValueForMissingStub: {}, + ) as Map); + @override + bool get isRedirect => (super.noSuchMethod( + Invocation.getter(#isRedirect), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + bool get persistentConnection => (super.noSuchMethod( + Invocation.getter(#persistentConnection), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); +} diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index c01bf08e2..35b26e166 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -1,11 +1,10 @@ -// @dart=2.10 - 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; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:tuple/tuple.dart'; @@ -20,12 +19,6 @@ import 'package:uni/view/schedule/schedule.dart'; import '../../test_widget.dart'; import '../../unit/view/Widgets/schedule_slot_test.dart'; -class MockClient extends Mock implements http.Client {} - -class MockResponse extends Mock implements http.Response {} - -class MockSessionProvider extends Mock implements SessionProvider {} - class UriMatcher extends CustomMatcher { UriMatcher(Matcher matcher) : super('Uri that has', 'string', matcher); @@ -33,6 +26,11 @@ class UriMatcher extends CustomMatcher { Object featureValueOf(dynamic actual) => (actual as Uri).toString(); } +@GenerateNiceMocks([ + MockSpec(), + MockSpec(), + MockSpec() +]) void main() { group('SchedulePage Integration Tests', () { final mockClient = MockClient(); diff --git a/uni/test/integration/src/schedule_page_test.mocks.dart b/uni/test/integration/src/schedule_page_test.mocks.dart new file mode 100644 index 000000000..4a53b12f6 --- /dev/null +++ b/uni/test/integration/src/schedule_page_test.mocks.dart @@ -0,0 +1,599 @@ +// Mocks generated by Mockito 5.4.2 from annotations +// in uni/test/integration/src/schedule_page_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:convert' as _i5; +import 'dart:typed_data' as _i6; +import 'dart:ui' as _i11; + +import 'package:flutter/material.dart' as _i10; +import 'package:http/http.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; +import 'package:uni/model/entities/profile.dart' as _i9; +import 'package:uni/model/entities/session.dart' as _i3; +import 'package:uni/model/providers/startup/session_provider.dart' as _i7; +import 'package:uni/model/request_status.dart' as _i8; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeResponse_0 extends _i1.SmartFake implements _i2.Response { + _FakeResponse_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeStreamedResponse_1 extends _i1.SmartFake + implements _i2.StreamedResponse { + _FakeStreamedResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSession_2 extends _i1.SmartFake implements _i3.Session { + _FakeSession_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Client]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClient extends _i1.Mock implements _i2.Client { + @override + _i4.Future<_i2.Response> head( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future<_i2.Response> get( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future<_i2.Response> post( + Uri? url, { + Map? headers, + Object? body, + _i5.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future<_i2.Response> put( + Uri? url, { + Map? headers, + Object? body, + _i5.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future<_i2.Response> patch( + Uri? url, { + Map? headers, + Object? body, + _i5.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future<_i2.Response> delete( + Uri? url, { + Map? headers, + Object? body, + _i5.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i2.Response>); + @override + _i4.Future read( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #read, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future.value(''), + returnValueForMissingStub: _i4.Future.value(''), + ) as _i4.Future); + @override + _i4.Future<_i6.Uint8List> readBytes( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #readBytes, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + returnValueForMissingStub: + _i4.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i4.Future<_i6.Uint8List>); + @override + _i4.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) => + (super.noSuchMethod( + Invocation.method( + #send, + [request], + ), + returnValue: + _i4.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + returnValueForMissingStub: + _i4.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + ) as _i4.Future<_i2.StreamedResponse>); + @override + void close() => super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [Response]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockResponse extends _i1.Mock implements _i2.Response { + @override + _i6.Uint8List get bodyBytes => (super.noSuchMethod( + Invocation.getter(#bodyBytes), + returnValue: _i6.Uint8List(0), + returnValueForMissingStub: _i6.Uint8List(0), + ) as _i6.Uint8List); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + returnValueForMissingStub: '', + ) as String); + @override + int get statusCode => (super.noSuchMethod( + Invocation.getter(#statusCode), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + @override + Map get headers => (super.noSuchMethod( + Invocation.getter(#headers), + returnValue: {}, + returnValueForMissingStub: {}, + ) as Map); + @override + bool get isRedirect => (super.noSuchMethod( + Invocation.getter(#isRedirect), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + bool get persistentConnection => (super.noSuchMethod( + Invocation.getter(#persistentConnection), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); +} + +/// A class which mocks [SessionProvider]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { + @override + _i3.Session get session => (super.noSuchMethod( + Invocation.getter(#session), + returnValue: _FakeSession_2( + this, + Invocation.getter(#session), + ), + returnValueForMissingStub: _FakeSession_2( + this, + Invocation.getter(#session), + ), + ) as _i3.Session); + @override + bool get dependsOnSession => (super.noSuchMethod( + Invocation.getter(#dependsOnSession), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + set dependsOnSession(bool? _dependsOnSession) => super.noSuchMethod( + Invocation.setter( + #dependsOnSession, + _dependsOnSession, + ), + returnValueForMissingStub: null, + ); + @override + set cacheDuration(Duration? _cacheDuration) => super.noSuchMethod( + Invocation.setter( + #cacheDuration, + _cacheDuration, + ), + returnValueForMissingStub: null, + ); + @override + _i8.RequestStatus get status => (super.noSuchMethod( + Invocation.getter(#status), + returnValue: _i8.RequestStatus.none, + returnValueForMissingStub: _i8.RequestStatus.none, + ) as _i8.RequestStatus); + @override + bool get hasListeners => (super.noSuchMethod( + Invocation.getter(#hasListeners), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + _i4.Future loadFromStorage() => (super.noSuchMethod( + Invocation.method( + #loadFromStorage, + [], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future loadFromRemote( + _i3.Session? session, + _i9.Profile? profile, + ) => + (super.noSuchMethod( + Invocation.method( + #loadFromRemote, + [ + session, + profile, + ], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + void restoreSession( + String? username, + String? password, + List? faculties, + ) => + super.noSuchMethod( + Invocation.method( + #restoreSession, + [ + username, + password, + faculties, + ], + ), + returnValueForMissingStub: null, + ); + @override + _i4.Future postAuthentication( + String? username, + String? password, + List? faculties, { + required bool? persistentSession, + }) => + (super.noSuchMethod( + Invocation.method( + #postAuthentication, + [ + username, + password, + faculties, + ], + {#persistentSession: persistentSession}, + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + void markAsNotInitialized() => super.noSuchMethod( + Invocation.method( + #markAsNotInitialized, + [], + ), + returnValueForMissingStub: null, + ); + @override + void updateStatus(_i8.RequestStatus? status) => super.noSuchMethod( + Invocation.method( + #updateStatus, + [status], + ), + returnValueForMissingStub: null, + ); + @override + _i4.Future forceRefresh(_i10.BuildContext? context) => + (super.noSuchMethod( + Invocation.method( + #forceRefresh, + [context], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future ensureInitialized(_i10.BuildContext? context) => + (super.noSuchMethod( + Invocation.method( + #ensureInitialized, + [context], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future ensureInitializedFromRemote(_i10.BuildContext? context) => + (super.noSuchMethod( + Invocation.method( + #ensureInitializedFromRemote, + [context], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + _i4.Future ensureInitializedFromStorage() => (super.noSuchMethod( + Invocation.method( + #ensureInitializedFromStorage, + [], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + @override + void addListener(_i11.VoidCallback? listener) => super.noSuchMethod( + Invocation.method( + #addListener, + [listener], + ), + returnValueForMissingStub: null, + ); + @override + void removeListener(_i11.VoidCallback? listener) => super.noSuchMethod( + Invocation.method( + #removeListener, + [listener], + ), + returnValueForMissingStub: null, + ); + @override + void dispose() => super.noSuchMethod( + Invocation.method( + #dispose, + [], + ), + returnValueForMissingStub: null, + ); + @override + void notifyListeners() => super.noSuchMethod( + Invocation.method( + #notifyListeners, + [], + ), + returnValueForMissingStub: null, + ); +} From bea33b7cb4c2ed912dd7b4b198742011236e547d Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Thu, 10 Aug 2023 22:32:27 +0000 Subject: [PATCH 042/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index b622faabf..2aa243ec3 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.47+165 \ No newline at end of file +1.5.48+166 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 58984e5ef..870611ff7 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.47+165 +version: 1.5.48+166 environment: sdk: ">=2.17.1 <3.0.0" From 8a0a19c3221b75f7cd2e77bc50c5d1cb226a47e3 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 11 Aug 2023 16:53:52 +0100 Subject: [PATCH 043/199] Removing useless methods and completers --- uni/lib/model/providers/lazy/restaurant_provider.dart | 11 +---------- uni/lib/view/restaurant/restaurant_page_view.dart | 6 +++--- .../view/restaurant/widgets/restaurant_page_card.dart | 10 ++++------ 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/uni/lib/model/providers/lazy/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart index 28d958b12..226c1ffc5 100644 --- a/uni/lib/model/providers/lazy/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -51,22 +51,13 @@ class RestaurantProvider extends StateProviderNotifier { } } - setFavoriteRestaurants( - List newFavoriteRestaurants, Completer action) async { - _favoriteRestaurants = List.from(newFavoriteRestaurants); - AppSharedPreferences.saveFavoriteRestaurants(favoriteRestaurants); - action.complete(); - notifyListeners(); - } - toggleFavoriteRestaurant( - String restaurantName, Completer action) async { + String restaurantName) async { _favoriteRestaurants.contains(restaurantName) ? _favoriteRestaurants.remove(restaurantName) : _favoriteRestaurants.add(restaurantName); notifyListeners(); AppSharedPreferences.saveFavoriteRestaurants(favoriteRestaurants); - action.complete(); } void updateStateBasedOnLocalRestaurants() async { diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 9a9e937a3..bb40c7209 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -89,7 +89,7 @@ class _RestaurantPageViewState extends GeneralPageViewState tabs.add(Container( color: Theme.of(context).colorScheme.background, child: Tab( - key: Key('cantine-page-tab-$i'), + key: Key('restaurant-page-tab-$i'), text: toString(DayOfWeek.values[i])), )); } @@ -113,7 +113,7 @@ class _RestaurantPageViewState extends GeneralPageViewState if (meals.isEmpty) { return Container( margin: const EdgeInsets.only(top: 10, bottom: 5), - key: Key('cantine-page-day-column-$day'), + key: Key('restaurant-page-day-column-$day'), child: Column( mainAxisSize: MainAxisSize.min, children: const [ @@ -124,7 +124,7 @@ class _RestaurantPageViewState extends GeneralPageViewState } else { return Container( margin: const EdgeInsets.only(top: 5, bottom: 5), - key: Key('cantine-page-day-column-$day'), + key: Key('restaurant-page-day-column-$day'), child: Column( mainAxisSize: MainAxisSize.min, children: createRestaurantRows(meals, context), diff --git a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart index 0f1307ae3..d2fc046da 100644 --- a/uni/lib/view/restaurant/widgets/restaurant_page_card.dart +++ b/uni/lib/view/restaurant/widgets/restaurant_page_card.dart @@ -1,11 +1,9 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:uni/view/common_widgets/generic_card.dart'; import 'package:uni/model/entities/restaurant.dart'; -import 'package:provider/provider.dart'; import 'package:uni/model/providers/lazy/restaurant_provider.dart'; +import 'package:uni/view/lazy_consumer.dart'; class RestaurantPageCard extends GenericCard { final Restaurant restaurant; @@ -42,14 +40,14 @@ class CardFavoriteButton extends StatelessWidget { @override Widget build(BuildContext context) { - return Consumer( - builder: (context, restaurantProvider, _) { + return LazyConsumer( + builder: (context, restaurantProvider) { final isFavorite = restaurantProvider.favoriteRestaurants.contains(restaurant.name); return IconButton( icon: isFavorite ? Icon(MdiIcons.heart) : Icon(MdiIcons.heartOutline), onPressed: () => restaurantProvider.toggleFavoriteRestaurant( - restaurant.name, Completer())); + restaurant.name)); }); } } From 77631b1e8b9e7f1b9904531e8785eff0a3d0d385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Mon, 14 Aug 2023 15:03:50 +0100 Subject: [PATCH 044/199] Update sentry version. This was causing `package_info_plus` to be downgrading and crashing `flutter run` on newer versions of flutter --- uni/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 870611ff7..116e727df 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -47,7 +47,7 @@ dependencies: path_provider: ^2.0.0 percent_indicator: ^4.2.2 provider: ^6.0.4 - sentry_flutter: ^7.5.2 + sentry_flutter: ^7.9.0 shared_preferences: ^2.0.3 shimmer: ^3.0.0 sqflite: ^2.0.3 From 712ff5453ab1c47b3f481354fd8959e72c257894 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Fri, 18 Aug 2023 12:58:54 +0000 Subject: [PATCH 045/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 2aa243ec3..6d5c00fb5 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.48+166 \ No newline at end of file +1.5.49+167 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 116e727df..691c94e50 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.48+166 +version: 1.5.49+167 environment: sdk: ">=2.17.1 <3.0.0" From 632c61e4c48118951da6e1b1a4bc723054c69691 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 11:50:47 +0100 Subject: [PATCH 046/199] Remove splash screen --- .../controller/{logout.dart => cleanup.dart} | 2 +- .../controller/networking/network_router.dart | 2 +- uni/lib/main.dart | 213 +++++++++++------- .../providers/startup/session_provider.dart | 16 +- uni/lib/utils/drawer_items.dart | 3 +- uni/lib/view/logout_route.dart | 16 -- uni/lib/view/navigation_service.dart | 17 +- uni/lib/view/splash/splash.dart | 159 ------------- .../terms_and_condition_dialog.dart | 8 +- 9 files changed, 173 insertions(+), 263 deletions(-) rename uni/lib/controller/{logout.dart => cleanup.dart} (96%) delete mode 100644 uni/lib/view/logout_route.dart delete mode 100644 uni/lib/view/splash/splash.dart rename uni/lib/view/{splash/widgets => }/terms_and_condition_dialog.dart (90%) diff --git a/uni/lib/controller/logout.dart b/uni/lib/controller/cleanup.dart similarity index 96% rename from uni/lib/controller/logout.dart rename to uni/lib/controller/cleanup.dart index a25735549..e2ce1e3ed 100644 --- a/uni/lib/controller/logout.dart +++ b/uni/lib/controller/cleanup.dart @@ -16,7 +16,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; -Future logout(BuildContext context) async { +Future cleanupStoredData(BuildContext context) async { StateProviders.fromContext(context).markAsNotInitialized(); final prefs = await SharedPreferences.getInstance(); diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index b2fd02ba8..47f0eb09b 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -159,7 +159,7 @@ class NetworkRouter { final newSession = await reLoginFromSession(session); if (newSession == null) { - NavigationService.logout(); + NavigationService.logoutAndPopHistory(null); return Future.error('Login failed'); } session diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 702a8d2b4..4f3d8f4c8 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -8,6 +8,7 @@ import 'package:logger/logger.dart'; 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/load_static/terms_and_conditions.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/providers/lazy/bus_stop_provider.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; @@ -33,11 +34,11 @@ 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/login/login.dart'; import 'package:uni/view/navigation_service.dart'; import 'package:uni/view/restaurant/restaurant_page_view.dart'; import 'package:uni/view/schedule/schedule.dart'; -import 'package:uni/view/splash/splash.dart'; +import 'package:uni/view/terms_and_condition_dialog.dart'; import 'package:uni/view/theme.dart'; import 'package:uni/view/theme_notifier.dart'; import 'package:uni/view/useful_info/useful_info.dart'; @@ -47,6 +48,19 @@ SentryEvent? beforeSend(SentryEvent event) { return event.level == SentryLevel.info ? event : null; } +Future firstRoute() async { + final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); + final userName = userPersistentInfo.item1; + final password = userPersistentInfo.item2; + + if (userName != '' && password != '') { + return '/${DrawerItem.navPersonalArea.title}'; + } + + await acceptTermsAndConditions(); + return '/${DrawerItem.navLogIn.title}'; +} + Future main() async { final stateProviders = StateProviders( LectureProvider(), @@ -78,12 +92,14 @@ Future main() async { }); final savedTheme = await AppSharedPreferences.getThemeMode(); + final route = await firstRoute(); + await SentryFlutter.init( (options) { options.dsn = 'https://a2661645df1c4992b24161010c5e0ecb@o553498.ingest.sentry.io/5680848'; }, - appRunner: () => { + appRunner: () { runApp( MultiProvider( providers: [ @@ -126,10 +142,10 @@ Future main() async { ], child: ChangeNotifierProvider( create: (_) => ThemeNotifier(savedTheme), - child: const MyApp(), + child: MyApp(route), ), ), - ) + ); }, ); } @@ -139,7 +155,9 @@ Future main() async { /// This class is necessary to track the app's state for /// the current execution class MyApp extends StatefulWidget { - const MyApp({super.key}); + const MyApp(this.initialRoute, {super.key}); + + final String initialRoute; @override State createState() => MyAppState(); @@ -154,78 +172,117 @@ class MyAppState extends State { ]); return Consumer( - builder: (context, themeNotifier, _) => MaterialApp( - title: 'uni', - theme: applicationLightTheme, - darkTheme: applicationDarkTheme, - themeMode: themeNotifier.getTheme(), - home: const SplashScreen(), - navigatorKey: NavigationService.navigatorKey, - onGenerateRoute: (RouteSettings settings) { - final transitions = >{ - '/${DrawerItem.navPersonalArea.title}': - PageTransition.makePageTransition( - page: const HomePageView(), - settings: settings, - ), - '/${DrawerItem.navSchedule.title}': - PageTransition.makePageTransition( - page: const SchedulePage(), - settings: settings, - ), - '/${DrawerItem.navExams.title}': PageTransition.makePageTransition( - page: const ExamsPageView(), - settings: settings, - ), - '/${DrawerItem.navStops.title}': PageTransition.makePageTransition( - page: const BusStopNextArrivalsPage(), - settings: settings, - ), - '/${DrawerItem.navCourseUnits.title}': - PageTransition.makePageTransition( - page: const CourseUnitsPageView(), - settings: settings, - ), - '/${DrawerItem.navLocations.title}': - PageTransition.makePageTransition( - page: const LocationsPage(), - settings: settings, - ), - '/${DrawerItem.navRestaurants.title}': - PageTransition.makePageTransition( - page: const RestaurantPageView(), - settings: settings, - ), - '/${DrawerItem.navCalendar.title}': - PageTransition.makePageTransition( - page: const CalendarPageView(), - settings: settings, - ), - '/${DrawerItem.navLibrary.title}': - PageTransition.makePageTransition( - page: const LibraryPageView(), - settings: settings, - ), - '/${DrawerItem.navUsefulInfo.title}': - PageTransition.makePageTransition( - page: const UsefulInfoPageView(), - settings: settings, - ), - '/${DrawerItem.navAbout.title}': PageTransition.makePageTransition( - page: const AboutPageView(), - settings: settings, - ), - '/${DrawerItem.navBugReport.title}': - PageTransition.makePageTransition( - page: const BugReportPageView(), - settings: settings, - maintainState: false, - ), - '/${DrawerItem.navLogOut.title}': LogoutRoute.buildLogoutRoute() - }; - return transitions[settings.name]; - }, - ), + builder: (context, themeNotifier, _) { + WidgetsBinding.instance.addPostFrameCallback( + (_) => requestTermsAndConditionsAcceptanceIfNeeded(), + ); + + return MaterialApp( + title: 'uni', + theme: applicationLightTheme, + darkTheme: applicationDarkTheme, + themeMode: themeNotifier.getTheme(), + initialRoute: widget.initialRoute, + navigatorKey: NavigationService.navigatorKey, + onGenerateRoute: (RouteSettings settings) { + final transitions = >{ + '/${DrawerItem.navPersonalArea.title}': + PageTransition.makePageTransition( + page: const HomePageView(), + settings: settings, + ), + '/${DrawerItem.navSchedule.title}': + PageTransition.makePageTransition( + page: const SchedulePage(), + settings: settings, + ), + '/${DrawerItem.navExams.title}': + PageTransition.makePageTransition( + page: const ExamsPageView(), + settings: settings, + ), + '/${DrawerItem.navStops.title}': + PageTransition.makePageTransition( + page: const BusStopNextArrivalsPage(), + settings: settings, + ), + '/${DrawerItem.navCourseUnits.title}': + PageTransition.makePageTransition( + page: const CourseUnitsPageView(), + settings: settings, + ), + '/${DrawerItem.navLocations.title}': + PageTransition.makePageTransition( + page: const LocationsPage(), + settings: settings, + ), + '/${DrawerItem.navRestaurants.title}': + PageTransition.makePageTransition( + page: const RestaurantPageView(), + settings: settings, + ), + '/${DrawerItem.navCalendar.title}': + PageTransition.makePageTransition( + page: const CalendarPageView(), + settings: settings, + ), + '/${DrawerItem.navLibrary.title}': + PageTransition.makePageTransition( + page: const LibraryPageView(), + settings: settings, + ), + '/${DrawerItem.navUsefulInfo.title}': + PageTransition.makePageTransition( + page: const UsefulInfoPageView(), + settings: settings, + ), + '/${DrawerItem.navAbout.title}': + PageTransition.makePageTransition( + page: const AboutPageView(), + settings: settings, + ), + '/${DrawerItem.navBugReport.title}': + PageTransition.makePageTransition( + page: const BugReportPageView(), + settings: settings, + maintainState: false, + ), + '/${DrawerItem.navLogIn.title}': + PageTransition.makePageTransition( + page: const LoginPageView(), + settings: settings, + ), + '/${DrawerItem.navLogOut.title}': + NavigationService.buildLogoutRoute(), + }; + return transitions[settings.name]; + }, + ); + }, ); } + + Future requestTermsAndConditionsAcceptanceIfNeeded() async { + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final userName = userPersistentInfo.item1; + final password = userPersistentInfo.item2; + + if (!mounted) { + return; + } + + final termsAcceptance = await TermsAndConditionDialog.buildIfTermsChanged( + context, + userName, + password, + ); + + switch (termsAcceptance) { + case TermsAndConditionsState.accepted: + return; + case TermsAndConditionsState.rejected: + NavigationService.logoutAndPopHistory(null); + } + } } diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index b56255723..27f113083 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -13,18 +13,28 @@ import 'package:uni/model/request_status.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() - : super( + : _session = Session(username: '', faculties: ['feup'], cookies: ''), + super( dependsOnSession: false, cacheDuration: null, initialStatus: RequestStatus.none, ); - late Session _session; + Session _session; Session get session => _session; @override - Future loadFromStorage() async {} + Future loadFromStorage() async { + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final userName = userPersistentInfo.item1; + final password = userPersistentInfo.item2; + + final faculties = await AppSharedPreferences.getUserFaculties(); + + restoreSession(userName, password, faculties); + } @override Future loadFromRemote(Session session, Profile profile) async { diff --git a/uni/lib/utils/drawer_items.dart b/uni/lib/utils/drawer_items.dart index bf27ca63d..bda77248b 100644 --- a/uni/lib/utils/drawer_items.dart +++ b/uni/lib/utils/drawer_items.dart @@ -11,6 +11,7 @@ enum DrawerItem { navUsefulInfo('Úteis', faculties: {'feup'}), navAbout('Sobre'), navBugReport('Bugs e Sugestões'), + navLogIn('Iniciar sessão'), navLogOut('Terminar sessão'); const DrawerItem(this.title, {this.faculties}); @@ -18,7 +19,7 @@ enum DrawerItem { final Set? faculties; bool isVisible(List userFaculties) { - if (this == DrawerItem.navLogOut) { + if (this == DrawerItem.navLogIn || this == DrawerItem.navLogOut) { return false; } diff --git a/uni/lib/view/logout_route.dart b/uni/lib/view/logout_route.dart deleted file mode 100644 index ef0e269ac..000000000 --- a/uni/lib/view/logout_route.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:uni/controller/logout.dart'; -import 'package:uni/view/login/login.dart'; - -class LogoutRoute { - LogoutRoute._(); - - static MaterialPageRoute buildLogoutRoute() { - return MaterialPageRoute( - builder: (context) { - logout(context); - return const LoginPageView(); - }, - ); - } -} diff --git a/uni/lib/view/navigation_service.dart b/uni/lib/view/navigation_service.dart index bad444ac3..9e8c336b6 100644 --- a/uni/lib/view/navigation_service.dart +++ b/uni/lib/view/navigation_service.dart @@ -1,15 +1,30 @@ import 'package:flutter/material.dart'; +import 'package:uni/controller/cleanup.dart'; import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/login/login.dart'; /// Manages the navigation logic class NavigationService { static final GlobalKey navigatorKey = GlobalKey(); - static void logout() { + static void logoutAndPopHistory(BuildContext? dataContext) { + if (dataContext != null) { + cleanupStoredData(dataContext); + } + navigatorKey.currentState?.pushNamedAndRemoveUntil( '/${DrawerItem.navLogOut.title}', (_) => false, ); } + + static MaterialPageRoute buildLogoutRoute() { + return MaterialPageRoute( + builder: (context) { + cleanupStoredData(context); + return const LoginPageView(); + }, + ); + } } diff --git a/uni/lib/view/splash/splash.dart b/uni/lib/view/splash/splash.dart deleted file mode 100644 index 20651033e..000000000 --- a/uni/lib/view/splash/splash.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:uni/controller/load_static/terms_and_conditions.dart'; -import 'package:uni/controller/local_storage/app_shared_preferences.dart'; -import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/view/home/home.dart'; -import 'package:uni/view/login/login.dart'; -import 'package:uni/view/logout_route.dart'; -import 'package:uni/view/splash/widgets/terms_and_condition_dialog.dart'; -import 'package:uni/view/theme.dart'; - -class SplashScreen extends StatefulWidget { - const SplashScreen({super.key}); - - @override - SplashScreenState createState() => SplashScreenState(); -} - -/// Manages the splash screen displayed after the app is launched. -class SplashScreenState extends State { - late MediaQueryData queryData; - late StateProviders stateProviders; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - stateProviders = StateProviders.fromContext(context); - changeRouteAccordingToLoginAndTerms(); - } - - @override - Widget build(BuildContext context) { - queryData = MediaQuery.of(context); - final systemTheme = - MediaQuery.platformBrightnessOf(context) == Brightness.dark - ? applicationDarkTheme - : applicationLightTheme; - - return Theme( - data: systemTheme, - child: Builder( - builder: (context) => Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - Container( - decoration: const BoxDecoration(), - ), - Center( - child: createTitle(context), - ), - Column( - children: [ - const Spacer(), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - Padding( - padding: EdgeInsets.only( - bottom: queryData.size.height / 16, - ), - ), - createNILogo(context), - ], - ), - Padding( - padding: EdgeInsets.only( - bottom: queryData.size.height / 15, - ), - ) - ], - ) - ], - ), - ), - ), - ); - } - - /// Creates the app Title container with the app's logo. - Widget createTitle(BuildContext context) { - return ConstrainedBox( - constraints: BoxConstraints( - minWidth: queryData.size.width / 8, - minHeight: queryData.size.height / 6, - ), - child: SizedBox( - width: 150, - child: SvgPicture.asset( - 'assets/images/logo_dark.svg', - colorFilter: ColorFilter.mode( - Theme.of(context).primaryColor, - BlendMode.srcIn, - ), - ), - ), - ); - } - - /// Creates the app main logo - Widget createNILogo(BuildContext context) { - return SvgPicture.asset( - 'assets/images/by_niaefeup.svg', - colorFilter: - ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: queryData.size.width * 0.45, - ); - } - - // Redirects the user to the proper page depending on his login input. - Future changeRouteAccordingToLoginAndTerms() async { - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final userName = userPersistentInfo.item1; - final password = userPersistentInfo.item2; - - MaterialPageRoute nextRoute; - if (userName != '' && password != '') { - nextRoute = - await termsAndConditionsRoute(userName, password, stateProviders); - } else { - await acceptTermsAndConditions(); - nextRoute = - MaterialPageRoute(builder: (context) => const LoginPageView()); - } - - if (mounted) { - unawaited(Navigator.pushReplacement(context, nextRoute)); - } - } - - Future> termsAndConditionsRoute( - String userName, - String password, - StateProviders stateProviders, - ) async { - final termsAcceptance = await TermsAndConditionDialog.buildIfTermsChanged( - context, - userName, - password, - ); - - switch (termsAcceptance) { - case TermsAndConditionsState.accepted: - if (mounted) { - final faculties = await AppSharedPreferences.getUserFaculties(); - stateProviders.sessionProvider - .restoreSession(userName, password, faculties); - } - return MaterialPageRoute(builder: (context) => const HomePageView()); - - case TermsAndConditionsState.rejected: - return LogoutRoute.buildLogoutRoute(); - } - } -} diff --git a/uni/lib/view/splash/widgets/terms_and_condition_dialog.dart b/uni/lib/view/terms_and_condition_dialog.dart similarity index 90% rename from uni/lib/view/splash/widgets/terms_and_condition_dialog.dart rename to uni/lib/view/terms_and_condition_dialog.dart index a7b36393f..a1b1e2a8e 100644 --- a/uni/lib/view/splash/widgets/terms_and_condition_dialog.dart +++ b/uni/lib/view/terms_and_condition_dialog.dart @@ -33,7 +33,7 @@ class TermsAndConditionDialog { static Future _buildShowDialog( BuildContext context, - Completer routeCompleter, + Completer userTermsDecision, String userName, String password, ) { @@ -60,7 +60,8 @@ class TermsAndConditionDialog { ElevatedButton( onPressed: () async { Navigator.of(context).pop(); - routeCompleter.complete(TermsAndConditionsState.accepted); + userTermsDecision + .complete(TermsAndConditionsState.accepted); await AppSharedPreferences .setTermsAndConditionsAcceptance(areAccepted: true); }, @@ -74,7 +75,8 @@ class TermsAndConditionDialog { ElevatedButton( onPressed: () async { Navigator.of(context).pop(); - routeCompleter.complete(TermsAndConditionsState.rejected); + userTermsDecision + .complete(TermsAndConditionsState.rejected); await AppSharedPreferences .setTermsAndConditionsAcceptance(areAccepted: false); }, From 37492513dfc7838e273978362b9648f9687f7cd9 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 12:21:49 +0100 Subject: [PATCH 047/199] Tweak eager providers initialization logic --- uni/lib/main.dart | 8 ++++++- .../providers/startup/profile_provider.dart | 2 +- .../providers/startup/session_provider.dart | 5 ++-- .../pages_layouts/general/general.dart | 23 ++++++++++++------- uni/lib/view/lazy_consumer.dart | 4 ++-- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 4f3d8f4c8..7e96e32a7 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -79,12 +79,18 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); + // These providers must be valid at startup, since + // other lazy providers rely on their values + await stateProviders.sessionProvider.loadFromStorage(); + await stateProviders.profileProvider.loadFromStorage(); + + // Initialize WorkManager for background tasks await Workmanager().initialize( workerStartCallback, isInDebugMode: !kReleaseMode, - // run workmanager in debug mode when app is in debug mode ); + // Read environment, which may include app tokens await dotenv .load(fileName: 'assets/env/.env', isOptional: true) .onError((error, stackTrace) { diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index ea99c9965..c484f1f59 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -21,7 +21,7 @@ import 'package:uni/model/request_status.dart'; class ProfileProvider extends StateProviderNotifier { ProfileProvider() : super(dependsOnSession: true, cacheDuration: const Duration(days: 1)); - Profile _profile = Profile(); + late Profile _profile; Profile get profile => _profile; diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 27f113083..182c1b1cc 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -13,14 +13,13 @@ import 'package:uni/model/request_status.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() - : _session = Session(username: '', faculties: ['feup'], cookies: ''), - super( + : super( dependsOnSession: false, cacheDuration: null, initialStatus: RequestStatus.none, ); - Session _session; + late Session _session; Session get session => _session; 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 443a8c752..8b9accdb8 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; +import 'package:shimmer/shimmer.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'; @@ -142,14 +143,20 @@ abstract class GeneralPageViewState extends State { ), ) }, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: decorationImage.data, - ), - ), + child: decorationImage.hasData + ? Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: decorationImage.data, + ), + ) + : Shimmer.fromColors( + baseColor: Theme.of(context).highlightColor, + highlightColor: Theme.of(context).colorScheme.onPrimary, + child: const CircleAvatar(), + ), ); }, ); diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index d130e70a5..24c96d9d6 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -30,11 +30,11 @@ class LazyConsumer extends StatelessWidget { if (provider.dependsOnSession) { if (context.mounted) { await Provider.of(context, listen: false) - .ensureInitialized(context); + .ensureInitializedFromRemote(context); } if (context.mounted) { await Provider.of(context, listen: false) - .ensureInitialized(context); + .ensureInitializedFromRemote(context); } } From d88a7bb7de329674e8916d58936303ad2a9b0735 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 13:01:56 +0100 Subject: [PATCH 048/199] Move terms check to page transition --- uni/lib/main.dart | 189 +++++++----------- .../view/common_widgets/page_transition.dart | 39 ++++ 2 files changed, 116 insertions(+), 112 deletions(-) diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 7e96e32a7..d386f9061 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -38,7 +38,6 @@ import 'package:uni/view/login/login.dart'; import 'package:uni/view/navigation_service.dart'; import 'package:uni/view/restaurant/restaurant_page_view.dart'; import 'package:uni/view/schedule/schedule.dart'; -import 'package:uni/view/terms_and_condition_dialog.dart'; import 'package:uni/view/theme.dart'; import 'package:uni/view/theme_notifier.dart'; import 'package:uni/view/useful_info/useful_info.dart'; @@ -178,117 +177,83 @@ class MyAppState extends State { ]); return Consumer( - builder: (context, themeNotifier, _) { - WidgetsBinding.instance.addPostFrameCallback( - (_) => requestTermsAndConditionsAcceptanceIfNeeded(), - ); - - return MaterialApp( - title: 'uni', - theme: applicationLightTheme, - darkTheme: applicationDarkTheme, - themeMode: themeNotifier.getTheme(), - initialRoute: widget.initialRoute, - navigatorKey: NavigationService.navigatorKey, - onGenerateRoute: (RouteSettings settings) { - final transitions = >{ - '/${DrawerItem.navPersonalArea.title}': - PageTransition.makePageTransition( - page: const HomePageView(), - settings: settings, - ), - '/${DrawerItem.navSchedule.title}': - PageTransition.makePageTransition( - page: const SchedulePage(), - settings: settings, - ), - '/${DrawerItem.navExams.title}': - PageTransition.makePageTransition( - page: const ExamsPageView(), - settings: settings, - ), - '/${DrawerItem.navStops.title}': - PageTransition.makePageTransition( - page: const BusStopNextArrivalsPage(), - settings: settings, - ), - '/${DrawerItem.navCourseUnits.title}': - PageTransition.makePageTransition( - page: const CourseUnitsPageView(), - settings: settings, - ), - '/${DrawerItem.navLocations.title}': - PageTransition.makePageTransition( - page: const LocationsPage(), - settings: settings, - ), - '/${DrawerItem.navRestaurants.title}': - PageTransition.makePageTransition( - page: const RestaurantPageView(), - settings: settings, - ), - '/${DrawerItem.navCalendar.title}': - PageTransition.makePageTransition( - page: const CalendarPageView(), - settings: settings, - ), - '/${DrawerItem.navLibrary.title}': - PageTransition.makePageTransition( - page: const LibraryPageView(), - settings: settings, - ), - '/${DrawerItem.navUsefulInfo.title}': - PageTransition.makePageTransition( - page: const UsefulInfoPageView(), - settings: settings, - ), - '/${DrawerItem.navAbout.title}': - PageTransition.makePageTransition( - page: const AboutPageView(), - settings: settings, - ), - '/${DrawerItem.navBugReport.title}': - PageTransition.makePageTransition( - page: const BugReportPageView(), - settings: settings, - maintainState: false, - ), - '/${DrawerItem.navLogIn.title}': - PageTransition.makePageTransition( - page: const LoginPageView(), - settings: settings, - ), - '/${DrawerItem.navLogOut.title}': - NavigationService.buildLogoutRoute(), - }; - return transitions[settings.name]; - }, - ); - }, - ); - } - - Future requestTermsAndConditionsAcceptanceIfNeeded() async { - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final userName = userPersistentInfo.item1; - final password = userPersistentInfo.item2; - - if (!mounted) { - return; - } - - final termsAcceptance = await TermsAndConditionDialog.buildIfTermsChanged( - context, - userName, - password, + builder: (context, themeNotifier, _) => MaterialApp( + title: 'uni', + theme: applicationLightTheme, + darkTheme: applicationDarkTheme, + themeMode: themeNotifier.getTheme(), + initialRoute: widget.initialRoute, + navigatorKey: NavigationService.navigatorKey, + onGenerateRoute: (RouteSettings settings) { + final transitions = >{ + '/${DrawerItem.navPersonalArea.title}': + PageTransition.makePageTransition( + page: const HomePageView(), + settings: settings, + ), + '/${DrawerItem.navSchedule.title}': + PageTransition.makePageTransition( + page: const SchedulePage(), + settings: settings, + ), + '/${DrawerItem.navExams.title}': PageTransition.makePageTransition( + page: const ExamsPageView(), + settings: settings, + ), + '/${DrawerItem.navStops.title}': PageTransition.makePageTransition( + page: const BusStopNextArrivalsPage(), + settings: settings, + ), + '/${DrawerItem.navCourseUnits.title}': + PageTransition.makePageTransition( + page: const CourseUnitsPageView(), + settings: settings, + ), + '/${DrawerItem.navLocations.title}': + PageTransition.makePageTransition( + page: const LocationsPage(), + settings: settings, + ), + '/${DrawerItem.navRestaurants.title}': + PageTransition.makePageTransition( + page: const RestaurantPageView(), + settings: settings, + ), + '/${DrawerItem.navCalendar.title}': + PageTransition.makePageTransition( + page: const CalendarPageView(), + settings: settings, + ), + '/${DrawerItem.navLibrary.title}': + PageTransition.makePageTransition( + page: const LibraryPageView(), + settings: settings, + ), + '/${DrawerItem.navUsefulInfo.title}': + PageTransition.makePageTransition( + page: const UsefulInfoPageView(), + settings: settings, + ), + '/${DrawerItem.navAbout.title}': PageTransition.makePageTransition( + page: const AboutPageView(), + settings: settings, + ), + '/${DrawerItem.navBugReport.title}': + PageTransition.makePageTransition( + page: const BugReportPageView(), + settings: settings, + maintainState: false, + ), + '/${DrawerItem.navLogIn.title}': PageTransition.makePageTransition( + page: const LoginPageView(), + settings: settings, + ), + '/${DrawerItem.navLogOut.title}': + NavigationService.buildLogoutRoute(), + }; + return transitions[settings.name]; + }, + ), ); - - switch (termsAcceptance) { - case TermsAndConditionsState.accepted: - return; - case TermsAndConditionsState.rejected: - NavigationService.logoutAndPopHistory(null); - } } } diff --git a/uni/lib/view/common_widgets/page_transition.dart b/uni/lib/view/common_widgets/page_transition.dart index 033d96f65..494f8097f 100644 --- a/uni/lib/view/common_widgets/page_transition.dart +++ b/uni/lib/view/common_widgets/page_transition.dart @@ -1,13 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:uni/controller/local_storage/app_shared_preferences.dart'; +import 'package:uni/view/navigation_service.dart'; +import 'package:uni/view/terms_and_condition_dialog.dart'; + /// Transition used between pages class PageTransition { static const int pageTransitionDuration = 200; + static bool _isFirstPageTransition = true; static Route makePageTransition({ required Widget page, required RouteSettings settings, bool maintainState = true, + bool checkTermsAndConditions = true, }) { return PageRouteBuilder( pageBuilder: ( @@ -15,6 +21,15 @@ class PageTransition { Animation animation, Animation secondaryAnimation, ) { + if (_isFirstPageTransition) { + _isFirstPageTransition = false; + if (checkTermsAndConditions) { + WidgetsBinding.instance.addPostFrameCallback( + (_) => requestTermsAndConditionsAcceptanceIfNeeded(context), + ); + } + } + return page; }, transitionDuration: const Duration(milliseconds: pageTransitionDuration), @@ -30,4 +45,28 @@ class PageTransition { }, ); } + + static Future requestTermsAndConditionsAcceptanceIfNeeded( + BuildContext context, + ) async { + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + final userName = userPersistentInfo.item1; + final password = userPersistentInfo.item2; + + if (context.mounted) { + final termsAcceptance = await TermsAndConditionDialog.buildIfTermsChanged( + context, + userName, + password, + ); + + switch (termsAcceptance) { + case TermsAndConditionsState.accepted: + return; + case TermsAndConditionsState.rejected: + NavigationService.logoutAndPopHistory(null); + } + } + } } From b051cf9949f76df9483f6174eef5fb99f850c6bf Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 14:20:20 +0100 Subject: [PATCH 049/199] Remove profile image provider --- uni/lib/controller/cleanup.dart | 3 -- .../local_storage/file_offline_storage.dart | 33 ++++++++++++--- uni/lib/main.dart | 5 --- uni/lib/model/entities/exam.dart | 20 +++++----- .../providers/startup/profile_provider.dart | 10 ++--- .../providers/startup/session_provider.dart | 9 ++++- .../providers/state_provider_notifier.dart | 2 +- .../pages_layouts/general/general.dart | 40 ++++++++----------- uni/lib/view/lazy_consumer.dart | 4 +- 9 files changed, 67 insertions(+), 59 deletions(-) diff --git a/uni/lib/controller/cleanup.dart b/uni/lib/controller/cleanup.dart index e2ce1e3ed..11bea65d2 100644 --- a/uni/lib/controller/cleanup.dart +++ b/uni/lib/controller/cleanup.dart @@ -14,7 +14,6 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/controller/local_storage/app_user_database.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; Future cleanupStoredData(BuildContext context) async { StateProviders.fromContext(context).markAsNotInitialized(); @@ -41,6 +40,4 @@ Future cleanupStoredData(BuildContext context) async { if (directory.existsSync()) { directory.deleteSync(recursive: true); } - GeneralPageViewState.profileImageProvider = null; - PaintingBinding.instance.imageCache.clear(); } diff --git a/uni/lib/controller/local_storage/file_offline_storage.dart b/uni/lib/controller/local_storage/file_offline_storage.dart index 1ae925910..9580def16 100644 --- a/uni/lib/controller/local_storage/file_offline_storage.dart +++ b/uni/lib/controller/local_storage/file_offline_storage.dart @@ -3,9 +3,12 @@ import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:http/http.dart' as http; +import 'package:logger/logger.dart'; import 'package:path_provider/path_provider.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/model/entities/session.dart'; + /// The offline image storage location on the device. Future get _localPath async { final directory = await getTemporaryDirectory(); @@ -13,11 +16,13 @@ Future get _localPath async { } /// Gets cached image named [localFileName]. -/// If not found or too old, downloads it from [url] with [headers]. +/// If not found or too old, downloads it from [url]. +/// The headers are retrieved from [session], then [headers] if provided. Future loadFileFromStorageOrRetrieveNew( String localFileName, String url, - Map headers, { + Session? session, { + Map? headers, int staleDays = 7, bool forceRetrieval = false, }) async { @@ -32,27 +37,43 @@ Future loadFileFromStorageOrRetrieveNew( .lastModifiedSync() .add(Duration(days: staleDays)) .isBefore(DateTime.now())); + if (fileExists && !fileIsStale) { return file; } + if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - final downloadedFile = await _downloadAndSaveFile(targetPath, url, headers); + final downloadedFile = + await _downloadAndSaveFile(targetPath, url, session, headers); if (downloadedFile != null) { + Logger().d('Downloaded $localFileName from remote'); return downloadedFile; } } - return fileExists ? file : null; + + if (fileExists) { + Logger().d('Loaded stale $localFileName from local storage'); + return file; + } + + Logger().w('Failed to load $localFileName'); + return null; } /// Downloads the image located at [url] and saves it in [filePath]. Future _downloadAndSaveFile( String filePath, String url, - Map headers, + Session? session, + Map? headers, ) async { - final response = await http.get(url.toUri(), headers: headers); + final response = session == null + ? await http.get(url.toUri(), headers: headers) + : await NetworkRouter.getWithCookies(url, {}, session); + if (response.statusCode == 200) { return File(filePath).writeAsBytes(response.bodyBytes); } + return null; } diff --git a/uni/lib/main.dart b/uni/lib/main.dart index d386f9061..64494226f 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -78,11 +78,6 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); - // These providers must be valid at startup, since - // other lazy providers rely on their values - await stateProviders.sessionProvider.loadFromStorage(); - await stateProviders.profileProvider.loadFromStorage(); - // Initialize WorkManager for background tasks await Workmanager().initialize( workerStartCallback, diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index b8d8ef370..85c959423 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -60,17 +60,15 @@ class Exam { String rooms, this.type, this.faculty, - ) { - this.rooms = rooms.split(','); - } - - late final DateTime begin; - late final DateTime end; - late final String id; - late final String subject; - late final List rooms; - late final String type; - late final String faculty; + ) : rooms = rooms.split(','); + + final DateTime begin; + final DateTime end; + final String id; + final String subject; + final List rooms; + final String type; + final String faculty; static Map types = { 'Mini-testes': 'MT', diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index c484f1f59..81d386fad 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -20,8 +20,9 @@ import 'package:uni/model/request_status.dart'; class ProfileProvider extends StateProviderNotifier { ProfileProvider() - : super(dependsOnSession: true, cacheDuration: const Duration(days: 1)); - late Profile _profile; + : _profile = Profile(), + super(dependsOnSession: true, cacheDuration: const Duration(days: 1)); + Profile _profile; Profile get profile => _profile; @@ -165,12 +166,11 @@ class ProfileProvider extends StateProviderNotifier { final faculty = session.faculties[0]; final url = 'https://sigarra.up.pt/$faculty/pt/fotografias_service.foto?pct_cod=$studentNumber'; - final headers = {}; - headers['cookie'] = session.cookies; + return loadFileFromStorageOrRetrieveNew( '${studentNumber}_profile_picture', url, - headers, + session, forceRetrieval: forceRetrieval, ); } diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 182c1b1cc..2126f0679 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -13,13 +13,18 @@ import 'package:uni/model/request_status.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() - : super( + : _session = Session( + faculties: ['feup'], + username: '', + cookies: '', + ), + super( dependsOnSession: false, cacheDuration: null, initialStatus: RequestStatus.none, ); - late Session _session; + Session _session; 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 e74ef2259..d192b8bf4 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -12,8 +12,8 @@ import 'package:uni/model/request_status.dart'; abstract class StateProviderNotifier extends ChangeNotifier { StateProviderNotifier({ - required this.dependsOnSession, required this.cacheDuration, + this.dependsOnSession = true, RequestStatus initialStatus = RequestStatus.busy, bool initialize = true, }) : _initialStatus = initialStatus, 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 8b9accdb8..ef5753178 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,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; -import 'package:shimmer/shimmer.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'; @@ -14,7 +13,6 @@ import 'package:uni/view/profile/profile.dart'; /// Page with a hamburger menu and the user profile picture abstract class GeneralPageViewState extends State { final double borderMargin = 18; - static ImageProvider? profileImageProvider; Future onRefresh(BuildContext context); @@ -34,10 +32,13 @@ abstract class GeneralPageViewState extends State { BuildContext context, { bool forceRetrieval = false, }) async { + final sessionProvider = + Provider.of(context, listen: false); + await sessionProvider.ensureInitializedFromStorage(); final profilePictureFile = await ProfileProvider.fetchOrGetCachedProfilePicture( - Provider.of(context, listen: false).session, - forceRetrieval: forceRetrieval || profileImageProvider == null, + sessionProvider.session, + forceRetrieval: forceRetrieval, ); return getProfileDecorationImage(profilePictureFile); } @@ -46,15 +47,12 @@ abstract class GeneralPageViewState extends State { /// /// If the image is not found / doesn't exist returns a generic placeholder. DecorationImage getProfileDecorationImage(File? profilePicture) { - final fallbackPicture = profileImageProvider ?? - const AssetImage('assets/images/profile_placeholder.png'); + const fallbackPicture = AssetImage('assets/images/profile_placeholder.png'); final image = profilePicture == null ? fallbackPicture : FileImage(profilePicture); - final result = DecorationImage(fit: BoxFit.cover, image: image); - if (profilePicture != null) { - profileImageProvider = image; - } + final result = + DecorationImage(fit: BoxFit.cover, image: image as ImageProvider); return result; } @@ -143,20 +141,14 @@ abstract class GeneralPageViewState extends State { ), ) }, - child: decorationImage.hasData - ? Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - image: decorationImage.data, - ), - ) - : Shimmer.fromColors( - baseColor: Theme.of(context).highlightColor, - highlightColor: Theme.of(context).colorScheme.onPrimary, - child: const CircleAvatar(), - ), + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: decorationImage.data, + ), + ), ); }, ); diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 24c96d9d6..d130e70a5 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -30,11 +30,11 @@ class LazyConsumer extends StatelessWidget { if (provider.dependsOnSession) { if (context.mounted) { await Provider.of(context, listen: false) - .ensureInitializedFromRemote(context); + .ensureInitialized(context); } if (context.mounted) { await Provider.of(context, listen: false) - .ensureInitializedFromRemote(context); + .ensureInitialized(context); } } From 1a44005d3fc074ad3ae84ac468943ff29bcb1964 Mon Sep 17 00:00:00 2001 From: Diogo Martins <81827192+DGoiana@users.noreply.github.com> Date: Sat, 19 Aug 2023 19:38:21 +0100 Subject: [PATCH 050/199] Delete Generated 2.xcconfig --- uni/ios/Flutter/Generated 2.xcconfig | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 uni/ios/Flutter/Generated 2.xcconfig diff --git a/uni/ios/Flutter/Generated 2.xcconfig b/uni/ios/Flutter/Generated 2.xcconfig deleted file mode 100644 index 27458b7ca..000000000 --- a/uni/ios/Flutter/Generated 2.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=/Users/goiana/Desktop/flutter -FLUTTER_APPLICATION_PATH=/Users/goiana/Desktop/project-schrodinger/uni -COCOAPODS_PARALLEL_CODE_SIGN=true -FLUTTER_TARGET=lib/main.dart -FLUTTER_BUILD_DIR=build -FLUTTER_BUILD_NAME=1.5.27 -FLUTTER_BUILD_NUMBER=145 -EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 -EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 -DART_OBFUSCATION=false -TRACK_WIDGET_CREATION=true -TREE_SHAKE_ICONS=false -PACKAGE_CONFIG=.dart_tool/package_config.json From cec375a60987ca519cdaa0eacc67b681dabc3ec7 Mon Sep 17 00:00:00 2001 From: Diogo Martins <81827192+DGoiana@users.noreply.github.com> Date: Sat, 19 Aug 2023 19:38:35 +0100 Subject: [PATCH 051/199] Delete flutter_export_environment 2.sh --- uni/ios/Flutter/flutter_export_environment 2.sh | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100755 uni/ios/Flutter/flutter_export_environment 2.sh diff --git a/uni/ios/Flutter/flutter_export_environment 2.sh b/uni/ios/Flutter/flutter_export_environment 2.sh deleted file mode 100755 index b127a469d..000000000 --- a/uni/ios/Flutter/flutter_export_environment 2.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/goiana/Desktop/flutter" -export "FLUTTER_APPLICATION_PATH=/Users/goiana/Desktop/project-schrodinger/uni" -export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=lib/main.dart" -export "FLUTTER_BUILD_DIR=build" -export "FLUTTER_BUILD_NAME=1.5.27" -export "FLUTTER_BUILD_NUMBER=145" -export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=true" -export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.dart_tool/package_config.json" From e067dc19606484ebf27ed646e5675ffcc0f0b73f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 20 Aug 2023 00:36:30 +0100 Subject: [PATCH 052/199] Fix version error --- uni/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 7dfbbb2d1..56be0e829 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -3,7 +3,7 @@ description: A UP no teu bolso. publish_to: 'none' # We do not publish to pub.dev -version: 1.5.48+166 +version: 1.5.49+167 environment: sdk: ">=2.17.1 <3.0.0" From ec4bd5404a65249d26cd47e25b5f9931bde7406e Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 20 Aug 2023 00:52:16 +0100 Subject: [PATCH 053/199] Multiprovider change --- uni/lib/main.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uni/lib/main.dart b/uni/lib/main.dart index e833c6808..d0666a51a 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -127,14 +127,14 @@ Future main() async { ChangeNotifierProvider( create: (context) => stateProviders.referenceProvider, ), - ], - child: ChangeNotifierProvider( - create: (_) => LocaleNotifier(savedLocale), - child: ChangeNotifierProvider( + ChangeNotifierProvider( + create: (_) => LocaleNotifier(savedLocale), + ), + ChangeNotifierProvider( create: (_) => ThemeNotifier(savedTheme), - child: const MyApp(), ), - ), + ], + child: const MyApp(), ), ) }, From a6e278d3c9d93c2dd86654c0c702d24cc9423376 Mon Sep 17 00:00:00 2001 From: thePeras Date: Sun, 20 Aug 2023 18:56:03 +0100 Subject: [PATCH 054/199] Remove send GitHub issue code --- uni/assets/env/.env.template | 3 --- uni/lib/view/bug_report/widgets/form.dart | 29 ++++++----------------- 2 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 uni/assets/env/.env.template diff --git a/uni/assets/env/.env.template b/uni/assets/env/.env.template deleted file mode 100644 index 48b37c563..000000000 --- a/uni/assets/env/.env.template +++ /dev/null @@ -1,3 +0,0 @@ -## GITHUB TOKEN -## For sending bugs and suggestions to github -GH_TOKEN= \ No newline at end of file diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index ba6748cb6..01238400c 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -28,8 +28,6 @@ class BugReportFormState extends State { loadBugClassList(); } - final String _gitHubPostUrl = - 'https://api.github.com/repos/NIAEFEUP/project-schrodinger/issues'; final String _sentryLink = 'https://sentry.io/organizations/niaefeup/issues/?query='; @@ -249,10 +247,6 @@ class BugReportFormState extends State { bool status; try { final sentryId = await submitSentryEvent(bugReport); - final gitHubRequestStatus = await submitGitHubIssue(sentryId, bugReport); - if (gitHubRequestStatus < 200 || gitHubRequestStatus > 400) { - throw Exception('Network error'); - } Logger().i('Successfully submitted bug report.'); toastMsg = 'Enviado com sucesso'; status = true; @@ -274,12 +268,12 @@ class BugReportFormState extends State { }); } } - +/* Future submitGitHubIssue( SentryId sentryEvent, Map bugReport, ) async { - final description = '${bugReport['bugLabel']}\nFurther information on: ' + final description = '${bugReport['bugLabel']}' '$_sentryLink$sentryEvent'; final data = { 'title': bugReport['title'], @@ -289,26 +283,17 @@ class BugReportFormState extends State { for (final faculty in bugReport['faculties'] as Iterable) { (data['labels'] as List).add(faculty); } - return http - .post( - Uri.parse(_gitHubPostUrl), - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'token ${dotenv.env["GH_TOKEN"]}}' - }, - body: json.encode(data), - ) - .then((http.Response response) { - return response.statusCode; - }); - } + }*/ Future submitSentryEvent(Map bugReport) async { + // Bug Report set tag email? + final description = bugReport['email'] == '' ? '${bugReport['text']} from ${bugReport['faculty']}' : '${bugReport['text']} from ${bugReport['faculty']}\nContact: ' '${bugReport['email']}'; - return Sentry.captureMessage( + + return HubAdapter().captureMessage( '${bugReport['bugLabel']}: ${bugReport['text']}\n$description', ); } From 8dc036b2660e87a483845d133eb5ed912a85af54 Mon Sep 17 00:00:00 2001 From: thePeras Date: Sun, 20 Aug 2023 18:09:16 +0000 Subject: [PATCH 055/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 6d5c00fb5..016ff3509 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.49+167 \ No newline at end of file +1.5.50+168 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 691c94e50..4a3d7c86e 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.49+167 +version: 1.5.50+168 environment: sdk: ">=2.17.1 <3.0.0" From 9295cdf57f6492eb265607bcc6cbf63ce47fd56d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 20 Aug 2023 21:55:24 +0100 Subject: [PATCH 056/199] Fixed hover error --- uni/lib/view/restaurant/restaurant_page_view.dart | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 55b7ad0e7..aa185e5d9 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -102,12 +102,9 @@ class _RestaurantPageState extends GeneralPageViewState for (var i = 0; i < DayOfWeek.values.length; i++) { tabs.add( - ColoredBox( - color: Theme.of(context).colorScheme.background, - child: Tab( - key: Key('cantine-page-tab-$i'), - text: toString(DayOfWeek.values[i]), - ), + Tab( + key: Key('cantine-page-tab-$i'), + text: toString(DayOfWeek.values[i]), ), ); } From 0aa828b073102b971e67088a2b7f8c395c410467 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 20 Aug 2023 23:19:14 +0100 Subject: [PATCH 057/199] Fix calendar parsing --- uni/lib/view/calendar/calendar.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 48b0ef1fa..f1c69d671 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -46,6 +46,14 @@ class CalendarPageViewState extends GeneralPageViewState { } Widget getTimeline(BuildContext context, List calendar) { + // Filter out events where name or date is a non-breaking space + final filteredCalendar = calendar + .where( + (event) => + event.name.trim() != ' ' && event.date.trim() != ' ', + ) + .toList(); + return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( connectorTheme: TimelineTheme.of(context) @@ -60,7 +68,7 @@ class CalendarPageViewState extends GeneralPageViewState { contentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - calendar[index].name, + filteredCalendar[index].name, style: Theme.of(context) .textTheme .titleLarge @@ -70,13 +78,13 @@ class CalendarPageViewState extends GeneralPageViewState { oppositeContentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - calendar[index].date, + filteredCalendar[index].date, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontStyle: FontStyle.italic, ), ), ), - itemCount: calendar.length, + itemCount: filteredCalendar.length, ), ); } From 70eecde7d3454809ddbf06f9cc221e475a03c33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Mon, 21 Aug 2023 16:36:44 +0100 Subject: [PATCH 058/199] tests running in null safe mode --- build.yaml => uni/build.yaml | 0 uni/pubspec.yaml | 7 +- uni/test/analysis_options.yaml | 5 - uni/test/integration/src/exams_page_test.dart | 1 + .../integration/src/schedule_page_test.dart | 1 + .../src/exams_page_test.mocks.dart | 4 +- .../src/schedule_page_test.mocks.dart | 4 +- .../providers/exams_provider_test.mocks.dart | 419 ++++++++++++++++ .../lecture_provider_test.mocks.dart | 452 ++++++++++++++++++ .../unit/providers/exams_provider_test.dart | 14 +- .../unit/providers/lecture_provider_test.dart | 21 +- uni/test/unit/providers/mocks.dart | 12 - 12 files changed, 909 insertions(+), 31 deletions(-) rename build.yaml => uni/build.yaml (100%) delete mode 100644 uni/test/analysis_options.yaml rename uni/test/{ => mocks}/integration/src/exams_page_test.mocks.dart (98%) rename uni/test/{ => mocks}/integration/src/schedule_page_test.mocks.dart (99%) create mode 100644 uni/test/mocks/unit/providers/exams_provider_test.mocks.dart create mode 100644 uni/test/mocks/unit/providers/lecture_provider_test.mocks.dart delete mode 100644 uni/test/unit/providers/mocks.dart diff --git a/build.yaml b/uni/build.yaml similarity index 100% rename from build.yaml rename to uni/build.yaml diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index f35c056f3..8cfffa705 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -63,7 +63,12 @@ dev_dependencies: flutter_launcher_icons: ^0.13.1 flutter_test: sdk: flutter - mockito: ^5.4.2 + # FIXME(luisd): Update mockito to a release version when 5.4.3 or above + # is launched + mockito: + git: + url: https://github.com/dart-lang/mockito.git + ref: "e54a006" test: any very_good_analysis: ^4.0.0+1 diff --git a/uni/test/analysis_options.yaml b/uni/test/analysis_options.yaml deleted file mode 100644 index 36d4692d5..000000000 --- a/uni/test/analysis_options.yaml +++ /dev/null @@ -1,5 +0,0 @@ -include: ../analysis_options.yaml - -linter: - rules: - enable_null_safety: false \ No newline at end of file diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index 34d57802c..44622790c 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -17,6 +17,7 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/exams.dart'; +import '../../mocks/integration/src/exams_page_test.mocks.dart'; import '../../test_widget.dart'; @GenerateNiceMocks([MockSpec(), MockSpec()]) diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index 35b26e166..823690a33 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -16,6 +16,7 @@ import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/schedule/schedule.dart'; +import '../../mocks/integration/src/schedule_page_test.mocks.dart'; import '../../test_widget.dart'; import '../../unit/view/Widgets/schedule_slot_test.dart'; diff --git a/uni/test/integration/src/exams_page_test.mocks.dart b/uni/test/mocks/integration/src/exams_page_test.mocks.dart similarity index 98% rename from uni/test/integration/src/exams_page_test.mocks.dart rename to uni/test/mocks/integration/src/exams_page_test.mocks.dart index 71a69a4fa..e28b49f59 100644 --- a/uni/test/integration/src/exams_page_test.mocks.dart +++ b/uni/test/mocks/integration/src/exams_page_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.2 from annotations +// Mocks generated by Mockito 5.4.3-wip from annotations // in uni/test/integration/src/exams_page_test.dart. // Do not manually edit this file. @@ -14,6 +14,8 @@ import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors diff --git a/uni/test/integration/src/schedule_page_test.mocks.dart b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart similarity index 99% rename from uni/test/integration/src/schedule_page_test.mocks.dart rename to uni/test/mocks/integration/src/schedule_page_test.mocks.dart index 4a53b12f6..c3259a73a 100644 --- a/uni/test/integration/src/schedule_page_test.mocks.dart +++ b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.2 from annotations +// Mocks generated by Mockito 5.4.3-wip from annotations // in uni/test/integration/src/schedule_page_test.dart. // Do not manually edit this file. @@ -20,6 +20,8 @@ import 'package:uni/model/request_status.dart' as _i8; // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors diff --git a/uni/test/mocks/unit/providers/exams_provider_test.mocks.dart b/uni/test/mocks/unit/providers/exams_provider_test.mocks.dart new file mode 100644 index 000000000..fd78853db --- /dev/null +++ b/uni/test/mocks/unit/providers/exams_provider_test.mocks.dart @@ -0,0 +1,419 @@ +// Mocks generated by Mockito 5.4.3-wip from annotations +// in uni/test/unit/providers/exams_provider_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; +import 'dart:convert' as _i4; +import 'dart:typed_data' as _i5; + +import 'package:http/http.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; +import 'package:uni/controller/parsers/parser_exams.dart' as _i6; +import 'package:uni/model/entities/course.dart' as _i8; +import 'package:uni/model/entities/exam.dart' as _i7; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeResponse_0 extends _i1.SmartFake implements _i2.Response { + _FakeResponse_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeStreamedResponse_1 extends _i1.SmartFake + implements _i2.StreamedResponse { + _FakeStreamedResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [Client]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClient extends _i1.Mock implements _i2.Client { + @override + _i3.Future<_i2.Response> head( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> get( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> post( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> put( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> patch( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future<_i2.Response> delete( + Uri? url, { + Map? headers, + Object? body, + _i4.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.Response>.value(_FakeResponse_0( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i3.Future<_i2.Response>); + @override + _i3.Future read( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #read, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future.value(''), + returnValueForMissingStub: _i3.Future.value(''), + ) as _i3.Future); + @override + _i3.Future<_i5.Uint8List> readBytes( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #readBytes, + [url], + {#headers: headers}, + ), + returnValue: _i3.Future<_i5.Uint8List>.value(_i5.Uint8List(0)), + returnValueForMissingStub: + _i3.Future<_i5.Uint8List>.value(_i5.Uint8List(0)), + ) as _i3.Future<_i5.Uint8List>); + @override + _i3.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) => + (super.noSuchMethod( + Invocation.method( + #send, + [request], + ), + returnValue: + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + returnValueForMissingStub: + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + this, + Invocation.method( + #send, + [request], + ), + )), + ) as _i3.Future<_i2.StreamedResponse>); + @override + void close() => super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [ParserExams]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockParserExams extends _i1.Mock implements _i6.ParserExams { + @override + String getExamSeasonAbbr(String? seasonStr) => (super.noSuchMethod( + Invocation.method( + #getExamSeasonAbbr, + [seasonStr], + ), + returnValue: '', + returnValueForMissingStub: '', + ) as String); + @override + _i3.Future> parseExams( + _i2.Response? response, + _i8.Course? course, + ) => + (super.noSuchMethod( + Invocation.method( + #parseExams, + [ + response, + course, + ], + ), + returnValue: _i3.Future>.value(<_i7.Exam>{}), + returnValueForMissingStub: + _i3.Future>.value(<_i7.Exam>{}), + ) as _i3.Future>); +} + +/// A class which mocks [Response]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockResponse extends _i1.Mock implements _i2.Response { + @override + _i5.Uint8List get bodyBytes => (super.noSuchMethod( + Invocation.getter(#bodyBytes), + returnValue: _i5.Uint8List(0), + returnValueForMissingStub: _i5.Uint8List(0), + ) as _i5.Uint8List); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + returnValueForMissingStub: '', + ) as String); + @override + int get statusCode => (super.noSuchMethod( + Invocation.getter(#statusCode), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + @override + Map get headers => (super.noSuchMethod( + Invocation.getter(#headers), + returnValue: {}, + returnValueForMissingStub: {}, + ) as Map); + @override + bool get isRedirect => (super.noSuchMethod( + Invocation.getter(#isRedirect), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + bool get persistentConnection => (super.noSuchMethod( + Invocation.getter(#persistentConnection), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); +} diff --git a/uni/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/uni/test/mocks/unit/providers/lecture_provider_test.mocks.dart new file mode 100644 index 000000000..3fd2208a6 --- /dev/null +++ b/uni/test/mocks/unit/providers/lecture_provider_test.mocks.dart @@ -0,0 +1,452 @@ +// Mocks generated by Mockito 5.4.3-wip from annotations +// in uni/test/unit/providers/lecture_provider_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:convert' as _i8; +import 'dart:typed_data' as _i9; + +import 'package:http/http.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart' + as _i2; +import 'package:uni/model/entities/lecture.dart' as _i5; +import 'package:uni/model/entities/profile.dart' as _i7; +import 'package:uni/model/entities/session.dart' as _i6; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeDates_0 extends _i1.SmartFake implements _i2.Dates { + _FakeDates_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeResponse_1 extends _i1.SmartFake implements _i3.Response { + _FakeResponse_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeStreamedResponse_2 extends _i1.SmartFake + implements _i3.StreamedResponse { + _FakeStreamedResponse_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [ScheduleFetcher]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockScheduleFetcher extends _i1.Mock implements _i2.ScheduleFetcher { + @override + _i4.Future> getLectures( + _i6.Session? session, + _i7.Profile? profile, + ) => + (super.noSuchMethod( + Invocation.method( + #getLectures, + [ + session, + profile, + ], + ), + returnValue: _i4.Future>.value(<_i5.Lecture>[]), + returnValueForMissingStub: + _i4.Future>.value(<_i5.Lecture>[]), + ) as _i4.Future>); + @override + _i2.Dates getDates() => (super.noSuchMethod( + Invocation.method( + #getDates, + [], + ), + returnValue: _FakeDates_0( + this, + Invocation.method( + #getDates, + [], + ), + ), + returnValueForMissingStub: _FakeDates_0( + this, + Invocation.method( + #getDates, + [], + ), + ), + ) as _i2.Dates); + @override + List getEndpoints(_i6.Session? session) => (super.noSuchMethod( + Invocation.method( + #getEndpoints, + [session], + ), + returnValue: [], + returnValueForMissingStub: [], + ) as List); +} + +/// A class which mocks [Client]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockClient extends _i1.Mock implements _i3.Client { + @override + _i4.Future<_i3.Response> head( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #head, + [url], + {#headers: headers}, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future<_i3.Response> get( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #get, + [url], + {#headers: headers}, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future<_i3.Response> post( + Uri? url, { + Map? headers, + Object? body, + _i8.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #post, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future<_i3.Response> put( + Uri? url, { + Map? headers, + Object? body, + _i8.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #put, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future<_i3.Response> patch( + Uri? url, { + Map? headers, + Object? body, + _i8.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #patch, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future<_i3.Response> delete( + Uri? url, { + Map? headers, + Object? body, + _i8.Encoding? encoding, + }) => + (super.noSuchMethod( + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + returnValue: _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.Response>.value(_FakeResponse_1( + this, + Invocation.method( + #delete, + [url], + { + #headers: headers, + #body: body, + #encoding: encoding, + }, + ), + )), + ) as _i4.Future<_i3.Response>); + @override + _i4.Future read( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #read, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future.value(''), + returnValueForMissingStub: _i4.Future.value(''), + ) as _i4.Future); + @override + _i4.Future<_i9.Uint8List> readBytes( + Uri? url, { + Map? headers, + }) => + (super.noSuchMethod( + Invocation.method( + #readBytes, + [url], + {#headers: headers}, + ), + returnValue: _i4.Future<_i9.Uint8List>.value(_i9.Uint8List(0)), + returnValueForMissingStub: + _i4.Future<_i9.Uint8List>.value(_i9.Uint8List(0)), + ) as _i4.Future<_i9.Uint8List>); + @override + _i4.Future<_i3.StreamedResponse> send(_i3.BaseRequest? request) => + (super.noSuchMethod( + Invocation.method( + #send, + [request], + ), + returnValue: + _i4.Future<_i3.StreamedResponse>.value(_FakeStreamedResponse_2( + this, + Invocation.method( + #send, + [request], + ), + )), + returnValueForMissingStub: + _i4.Future<_i3.StreamedResponse>.value(_FakeStreamedResponse_2( + this, + Invocation.method( + #send, + [request], + ), + )), + ) as _i4.Future<_i3.StreamedResponse>); + @override + void close() => super.noSuchMethod( + Invocation.method( + #close, + [], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [Response]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockResponse extends _i1.Mock implements _i3.Response { + @override + _i9.Uint8List get bodyBytes => (super.noSuchMethod( + Invocation.getter(#bodyBytes), + returnValue: _i9.Uint8List(0), + returnValueForMissingStub: _i9.Uint8List(0), + ) as _i9.Uint8List); + @override + String get body => (super.noSuchMethod( + Invocation.getter(#body), + returnValue: '', + returnValueForMissingStub: '', + ) as String); + @override + int get statusCode => (super.noSuchMethod( + Invocation.getter(#statusCode), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + @override + Map get headers => (super.noSuchMethod( + Invocation.getter(#headers), + returnValue: {}, + returnValueForMissingStub: {}, + ) as Map); + @override + bool get isRedirect => (super.noSuchMethod( + Invocation.getter(#isRedirect), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + @override + bool get persistentConnection => (super.noSuchMethod( + Invocation.getter(#persistentConnection), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); +} diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index 2ac9bf387..2f4c33ddd 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -1,9 +1,10 @@ -// @dart=2.10 - import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/parsers/parser_exams.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; @@ -12,12 +13,15 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/request_status.dart'; -import 'mocks.dart'; +import '../../mocks/unit/providers/exams_provider_test.mocks.dart'; +@GenerateNiceMocks( + [MockSpec(), MockSpec(), MockSpec()], +) void main() { group('ExamProvider', () { final mockClient = MockClient(); - final parserExams = ParserExamsMock(); + final parserExams = MockParserExams(); final mockResponse = MockResponse(); final sopeCourseUnit = CourseUnit( @@ -68,7 +72,7 @@ void main() { .thenAnswer((_) async => mockResponse); when(mockResponse.statusCode).thenReturn(200); - ExamProvider provider; + late ExamProvider provider; setUp(() { provider = ExamProvider(); diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index 2f77e9acf..8498f01c2 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -1,8 +1,9 @@ -// @dart=2.10 - import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:tuple/tuple.dart'; +import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; @@ -11,11 +12,14 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; -import 'mocks.dart'; +import '../../mocks/unit/providers/lecture_provider_test.mocks.dart'; +@GenerateNiceMocks( + [MockSpec(), MockSpec(), MockSpec()], +) void main() { group('Schedule Action Creator', () { - final fetcherMock = ScheduleFetcherMock(); + final fetcherMock = MockScheduleFetcher(); final mockClient = MockClient(); final mockResponse = MockResponse(); const userPersistentInfo = Tuple2('', ''); @@ -51,7 +55,7 @@ void main() { .thenAnswer((_) async => mockResponse); when(mockResponse.statusCode).thenReturn(200); - LectureProvider provider; + late LectureProvider provider; setUp(() { provider = LectureProvider(); expect(provider.status, RequestStatus.busy); @@ -76,7 +80,12 @@ void main() { when(fetcherMock.getLectures(any, any)) .thenAnswer((_) async => throw Exception('💥')); - await provider.fetchUserLectures(userPersistentInfo, session, profile); + await provider.fetchUserLectures( + userPersistentInfo, + session, + profile, + fetcher: fetcherMock, + ); expect(provider.status, RequestStatus.failed); }); diff --git a/uni/test/unit/providers/mocks.dart b/uni/test/unit/providers/mocks.dart deleted file mode 100644 index edbe8cc80..000000000 --- a/uni/test/unit/providers/mocks.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:http/http.dart' as http; -import 'package:mockito/mockito.dart'; -import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; -import 'package:uni/controller/parsers/parser_exams.dart'; - -class MockClient extends Mock implements http.Client {} - -class MockResponse extends Mock implements http.Response {} - -class ParserExamsMock extends Mock implements ParserExams {} - -class ScheduleFetcherMock extends Mock implements ScheduleFetcher {} From 574cc12d00e32fcffe2db4b94bce8bfc13625f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Mon, 21 Aug 2023 16:40:15 +0100 Subject: [PATCH 059/199] Update flutter CI version --- .github/workflows/format_lint_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format_lint_test.yaml b/.github/workflows/format_lint_test.yaml index 34f752778..9b4b9055b 100644 --- a/.github/workflows/format_lint_test.yaml +++ b/.github/workflows/format_lint_test.yaml @@ -4,7 +4,7 @@ on: branches: [master, develop] env: - FLUTTER_VERSION: 3.7.2 + FLUTTER_VERSION: 3.10.6 JAVA_VERSION: 11.x jobs: From 2a38386f91606545c28d905c6275ffc48319a08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Mon, 21 Aug 2023 17:03:36 +0100 Subject: [PATCH 060/199] Fix linting --- uni/lib/view/login/login.dart | 2 +- uni/lib/view/login/widgets/inputs.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 06d56819b..f1cae2116 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -87,7 +87,7 @@ class LoginPageViewState extends State { /// Tracks if the user wants to keep signed in (has a /// checkmark on the button). - void _setKeepSignedIn(bool? value) { + void _setKeepSignedIn({bool? value}) { if (value == null) return; setState(() { _keepSignedIn = value; diff --git a/uni/lib/view/login/widgets/inputs.dart b/uni/lib/view/login/widgets/inputs.dart index d42b805b2..a123af1c3 100644 --- a/uni/lib/view/login/widgets/inputs.dart +++ b/uni/lib/view/login/widgets/inputs.dart @@ -68,12 +68,12 @@ Widget createPasswordInput( /// Creates the widget for the user to keep signed in (save his data). Widget createSaveDataCheckBox( - void Function(bool?)? setKeepSignedIn, { + void Function({bool? value})? setKeepSignedIn, { required bool keepSignedIn, }) { return CheckboxListTile( value: keepSignedIn, - onChanged: setKeepSignedIn, + onChanged: (value) => setKeepSignedIn?.call(value: value), title: const Text( 'Manter sessão iniciada', textAlign: TextAlign.center, From 39f86c27f56ce83b3ff25a936c8484e005e29eb8 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Mon, 21 Aug 2023 16:16:33 +0000 Subject: [PATCH 061/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 016ff3509..2f698c62d 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.50+168 \ No newline at end of file +1.5.51+169 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 4a3d7c86e..fdb657b73 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.50+168 +version: 1.5.51+169 environment: sdk: ">=2.17.1 <3.0.0" From f362f6e8480ebbf8a687707073643a0833fb85a0 Mon Sep 17 00:00:00 2001 From: thePeras Date: Mon, 21 Aug 2023 18:38:03 +0100 Subject: [PATCH 062/199] Send sentry user feedback from report --- uni/lib/view/bug_report/widgets/form.dart | 42 +++++++++-------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 01238400c..de53e0954 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -246,7 +246,7 @@ class BugReportFormState extends State { String toastMsg; bool status; try { - final sentryId = await submitSentryEvent(bugReport); + await submitSentryEvent(bugReport); Logger().i('Successfully submitted bug report.'); toastMsg = 'Enviado com sucesso'; status = true; @@ -268,34 +268,24 @@ class BugReportFormState extends State { }); } } -/* - Future submitGitHubIssue( - SentryId sentryEvent, - Map bugReport, - ) async { - final description = '${bugReport['bugLabel']}' - '$_sentryLink$sentryEvent'; - final data = { - 'title': bugReport['title'], - 'body': description, - 'labels': ['In-app bug report', bugReport['bugLabel']], - }; - for (final faculty in bugReport['faculties'] as Iterable) { - (data['labels'] as List).add(faculty); - } - }*/ - - Future submitSentryEvent(Map bugReport) async { - // Bug Report set tag email? - final description = bugReport['email'] == '' - ? '${bugReport['text']} from ${bugReport['faculty']}' - : '${bugReport['text']} from ${bugReport['faculty']}\nContact: ' - '${bugReport['email']}'; + Future submitSentryEvent(Map bugReport) async { + final sentryId = await Sentry.captureMessage( + 'User Feedback', + withScope: (scope) { + scope + ..setTag('report', 'true') + ..setTag('report.type', bugReport['bugLabel'] as String); + }, + ); - return HubAdapter().captureMessage( - '${bugReport['bugLabel']}: ${bugReport['text']}\n$description', + final userFeedback = SentryUserFeedback( + eventId: sentryId, + comments: '${bugReport['title']}\n ${bugReport['text']}', + email: bugReport['email'] as String, ); + + await Sentry.captureUserFeedback(userFeedback); } void clearForm() { From af9d64f62b7ce8f5e2a006c6049e2a5bbb084319 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 15:30:48 +0100 Subject: [PATCH 063/199] Fix theme issues on login page --- uni/lib/view/login/login.dart | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 06d56819b..7d45a6ab9 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -26,12 +26,6 @@ class LoginPageViewState extends State { 'feup' ]; // May choose more than one faculty in the dropdown. - @override - void didChangeDependencies() { - super.didChangeDependencies(); - setState(() {}); - } - static final FocusNode usernameFocus = FocusNode(); static final FocusNode passwordFocus = FocusNode(); @@ -107,15 +101,13 @@ class LoginPageViewState extends State { return Theme( data: applicationLightTheme.copyWith( - // The handle color is not applying due to a Flutter bug: - // https://github.com/flutter/flutter/issues/74890 textSelectionTheme: const TextSelectionThemeData( cursorColor: Colors.white, selectionHandleColor: Colors.white, ), ), child: Builder( - builder: (themeContext) => Scaffold( + builder: (context) => Scaffold( backgroundColor: darkRed, body: WillPopScope( child: Padding( @@ -164,7 +156,7 @@ class LoginPageViewState extends State { ], ), ), - onWillPop: () => onWillPop(themeContext), + onWillPop: () => onWillPop(context), ), ), ), From 8518f37598e3375ff1ab1052a2056e307f1f1546 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Tue, 22 Aug 2023 09:08:14 +0000 Subject: [PATCH 064/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 2f698c62d..dfe37f912 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.51+169 \ No newline at end of file +1.5.52+170 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index fdb657b73..b69a86488 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.51+169 +version: 1.5.52+170 environment: sdk: ">=2.17.1 <3.0.0" From 8c1a759618986652ab05d775d610752818a8bf6e Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 15:24:12 +0100 Subject: [PATCH 065/199] Relax codecov config --- codecov.yml | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/codecov.yml b/codecov.yml index 25d8f819f..08d0732c5 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,8 +1,37 @@ +# see https://docs.codecov.io/docs/codecov-yaml +# Validation check: +# $ curl --data-binary @codecov.yml https://codecov.io/validate + ignore: - "**/*.g.dart" + - "!**/lib/**" # ignore all files outside of lib + +codecov: + require_ci_to_pass: yes + notify: + wait_for_ci: yes + +coverage: + precision: 0 # 2 = xx.xx%, 0 = xx% + round: up # how coverage is rounded: down/up/nearest + range: 40...100 # custom range of coverage colors from red -> yellow -> green + status: + project: + default: + informational: true + target: 70% # specify the target coverage for each commit status + threshold: 10% # allow this decrease on project + if_ci_failed: error + patch: + default: + informational: true + threshold: 50% # allow this decrease on patch + changes: false + +github_checks: + annotations: false + comment: - layout: "diff, flags, files" - behavior: default + layout: header, diff require_changes: false - require_base: false - require_head: true + behavior: default \ No newline at end of file From 14a7eb6194ee4c716872451154a19681e3c424b4 Mon Sep 17 00:00:00 2001 From: Processing Date: Thu, 17 Aug 2023 19:33:47 +0100 Subject: [PATCH 066/199] =?UTF-8?q?Hide=20"Impress=C3=A3o"=20link=20from?= =?UTF-8?q?=20"Outros=20links"=20card.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../view/useful_info/widgets/other_links_card.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 651d614db..71730af58 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; -import 'package:uni/view/useful_info/widgets/link_button.dart'; +// import 'package:uni/view/useful_info/widgets/link_button.dart'; /// Manages the 'Current account' section inside the user's page (accessible /// through the top-right widget with the user picture) @@ -10,10 +10,11 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { return Column( - children: const [ - LinkButton(title: 'Impressão', link: 'https://print.up.pt') - ], - ); + /*children: const [ + // LinkButton(title: 'Impressão', link: 'https://print.up.pt') + // TODO(Process-ing): Get fixed link + ],*/ + ); } @override From 7dc87c8d1deb9ffeba7366f53a4c1edac3e1cdd6 Mon Sep 17 00:00:00 2001 From: Processing Date: Thu, 17 Aug 2023 19:38:14 +0100 Subject: [PATCH 067/199] Add "Consultas SASUP" link to "Outros links" card. --- .../view/useful_info/widgets/other_links_card.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 71730af58..6ed1bf9fb 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:uni/view/common_widgets/generic_expansion_card.dart'; -// import 'package:uni/view/useful_info/widgets/link_button.dart'; +import 'package:uni/view/useful_info/widgets/link_button.dart'; /// Manages the 'Current account' section inside the user's page (accessible /// through the top-right widget with the user picture) @@ -10,11 +10,15 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { return Column( - /*children: const [ - // LinkButton(title: 'Impressão', link: 'https://print.up.pt') + children: const [ + // LinkButton(title: 'Impressão', link: 'https://print.up.pt'), // TODO(Process-ing): Get fixed link - ],*/ - ); + LinkButton( + title: 'Consultas SASUP', + link: 'https://www.up.pt/portal/pt/sasup/saude/marcar-consulta/', + ), + ], + ); } @override From b03270d4ec6ad275f78b8fccf181e16e75dcf16b Mon Sep 17 00:00:00 2001 From: Process-ing Date: Tue, 22 Aug 2023 13:57:27 +0000 Subject: [PATCH 068/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index dfe37f912..9f75d9101 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.52+170 \ No newline at end of file +1.5.53+171 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index b69a86488..018900be3 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.52+170 +version: 1.5.53+171 environment: sdk: ">=2.17.1 <3.0.0" From 0c848c7e28b2a5527038587aa271b79e3ae90a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Tue, 22 Aug 2023 16:51:19 +0100 Subject: [PATCH 069/199] Update deploy.yaml --- .github/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 94a4a6309..2017cb745 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -40,7 +40,7 @@ jobs: env: PROPERTIES_PATH: "android/key.properties" JAVA_VERSION: "11.x" - FLUTTER_VERSION: "3.7.2" + FLUTTER_VERSION: "3.10.6" defaults: run: working-directory: ./uni From fa2a3edc33667f8a03d6df68d17dbf7d879e9aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Tue, 22 Aug 2023 19:56:21 +0100 Subject: [PATCH 070/199] fix linting --- uni/lib/view/useful_info/widgets/other_links_card.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 6ed1bf9fb..a1a43bf48 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -9,8 +9,8 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column( - children: const [ + return const Column( + children: [ // LinkButton(title: 'Impressão', link: 'https://print.up.pt'), // TODO(Process-ing): Get fixed link LinkButton( From 3943c0203030044463572a8a293ba769e7c7c528 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Thu, 24 Aug 2023 11:59:40 +0000 Subject: [PATCH 071/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 9f75d9101..ce5241713 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.53+171 \ No newline at end of file +1.5.54+172 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 018900be3..b2e4e3b63 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.53+171 +version: 1.5.54+172 environment: sdk: ">=2.17.1 <3.0.0" From 2fec68084a8fc2b7bd4e92dd8171caedeeced1fa Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 24 Aug 2023 19:47:58 +0100 Subject: [PATCH 072/199] Widget testing changes --- uni/test/test_widget.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index fc8798227..66f48f95d 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; @@ -13,14 +14,13 @@ Widget testableWidget( Widget wrapWidget(Widget widget) { return MaterialApp( - home: Scaffold( - body: Localizations( - delegates: const [ - S.delegate, - ], - locale: const Locale('pt'), - child: widget, - ), - ), + localizationsDelegates: const [ + S.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: S.delegate.supportedLocales, + home: widget, ); } From d96185f6acc687e633186720b22a9770ee3bbc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 24 Aug 2023 21:19:11 +0100 Subject: [PATCH 073/199] update readme to accomodate generated files --- uni/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/uni/README.md b/uni/README.md index f9d2ee3c1..e718bd0fe 100644 --- a/uni/README.md +++ b/uni/README.md @@ -30,6 +30,34 @@ In order to remove it, is it as simple as running the following command, from th rm .git/hooks/pre-commit ``` +### Generated files + +Flutter doesn't support runtime reflection, in order to circumvent these limitations, we use **automatic code generation** or **static metaprogramming** for things like **mocks** and other possible usecases. By convention, you should **always commit** the generated `.dart` files into the repository. + +Dart leverages annotations to signal the `build_runner` that it should generate some code. They look something like this: +```dart + import 'package:mockito/annotations.dart' + + class Cat{ + } + + @GenerateNiceMocks([MockSpec()]) + void main(){ + + } +``` +In this case, `build_runner` will dectect that `GenerateNiceMocks` is a generator function from `mockito` and will generate code to a different file. + +In order to run the `build_runner` once: +```sh +dart run build_runner build +``` + +But you can also watch for changes in `.dart` files and automatically run the `build_runner` on those file changes (useful if you find yourself need to generate code very frequently): +```sh +dart run build_runner watch +``` + ## Project structure ### Overview From 46c06b024b8764b3231f3563b1cd5406646aac48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 24 Aug 2023 21:20:11 +0100 Subject: [PATCH 074/199] Exclude mock files from being formatted or linted --- .github/workflows/format_lint_test.yaml | 2 +- uni/analysis_options.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/format_lint_test.yaml b/.github/workflows/format_lint_test.yaml index 9b4b9055b..0fb4e2d6d 100644 --- a/.github/workflows/format_lint_test.yaml +++ b/.github/workflows/format_lint_test.yaml @@ -20,7 +20,7 @@ jobs: with: flutter-version: ${{ env.FLUTTER_VERSION }} - - run: dart format $(find . -type f -name "*.dart" -a -not -name "*.g.dart") --set-exit-if-changed + - run: dart format $(find . -type f -name "*.dart" -a -not -name "*.g.dart" -a -not -name "*.mocks.dart") --set-exit-if-changed lint: name: "Lint" diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index 92d895f92..6acf469de 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -4,6 +4,7 @@ analyzer: # Exclude auto-generated files from dart analysis exclude: - "**.g.dart" + - "**.mocks.dart" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html From 7a44a0041a00862178b06d8451043b0f1a3c213e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 24 Aug 2023 21:30:14 +0100 Subject: [PATCH 075/199] make pre-commit hook not format mock files --- pre-commit-hook.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pre-commit-hook.sh b/pre-commit-hook.sh index 838253711..c8f93c62b 100755 --- a/pre-commit-hook.sh +++ b/pre-commit-hook.sh @@ -3,7 +3,7 @@ mkdir -p .git/hooks #it seems that are some cases where git will not create a ho tee .git/hooks/pre-commit << EOF #!/bin/sh -FILES="\$(git diff --name-only --cached | grep .*\.dart | grep -v .*\.g\.dart)" +FILES="\$(git diff --name-only --cached | grep .*\.dart | grep -v .*\.g\.dart | grep -v .*\.mocks\.dart)" [ -z "\$FILES" ] && exit 0 From 437f379ef804280a95680e55a2f02311385da376 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 24 Aug 2023 22:52:55 +0100 Subject: [PATCH 076/199] Filter at parse lever --- uni/lib/controller/parsers/parser_calendar.dart | 11 ++++++++++- uni/lib/view/calendar/calendar.dart | 14 +++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/uni/lib/controller/parsers/parser_calendar.dart b/uni/lib/controller/parsers/parser_calendar.dart index 77af03e39..e98d5467d 100644 --- a/uni/lib/controller/parsers/parser_calendar.dart +++ b/uni/lib/controller/parsers/parser_calendar.dart @@ -7,7 +7,7 @@ Future> getCalendarFromHtml(Response response) async { final calendarHtml = document.querySelectorAll('tr'); - return calendarHtml + final eventList = calendarHtml .map( (event) => CalendarEvent( event.children[0].innerHtml, @@ -15,4 +15,13 @@ Future> getCalendarFromHtml(Response response) async { ), ) .toList(); + + final filteredCalendar = eventList + .where( + (event) => + event.name.trim() != ' ' && event.date.trim() != ' ', + ) + .toList(); + + return filteredCalendar; } diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index f1c69d671..48b0ef1fa 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -46,14 +46,6 @@ class CalendarPageViewState extends GeneralPageViewState { } Widget getTimeline(BuildContext context, List calendar) { - // Filter out events where name or date is a non-breaking space - final filteredCalendar = calendar - .where( - (event) => - event.name.trim() != ' ' && event.date.trim() != ' ', - ) - .toList(); - return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( connectorTheme: TimelineTheme.of(context) @@ -68,7 +60,7 @@ class CalendarPageViewState extends GeneralPageViewState { contentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - filteredCalendar[index].name, + calendar[index].name, style: Theme.of(context) .textTheme .titleLarge @@ -78,13 +70,13 @@ class CalendarPageViewState extends GeneralPageViewState { oppositeContentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - filteredCalendar[index].date, + calendar[index].date, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontStyle: FontStyle.italic, ), ), ), - itemCount: filteredCalendar.length, + itemCount: calendar.length, ), ); } From 8b8f5ab996ca4d98895e2fc160013b7af0e4d5ac Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 25 Aug 2023 14:32:10 +0100 Subject: [PATCH 077/199] Testable widget changes --- uni/test/test_widget.dart | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 66f48f95d..67a4b27eb 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -2,14 +2,21 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/view/locale_notifier.dart'; Widget testableWidget( Widget widget, { List providers = const [], }) { - if (providers.isEmpty) return wrapWidget(widget); - - return MultiProvider(providers: providers, child: wrapWidget(widget)); + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (_) => LocaleNotifier(const Locale('pt')), + ), + ...providers + ], + child: wrapWidget(widget), + ); } Widget wrapWidget(Widget widget) { @@ -21,6 +28,8 @@ Widget wrapWidget(Widget widget) { GlobalCupertinoLocalizations.delegate, ], supportedLocales: S.delegate.supportedLocales, - home: widget, + home: Scaffold( + body: widget, + ), ); } From d7769fbd0f6ac9df6aceba5a1cc2bbdb4b18ece9 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 25 Aug 2023 14:33:44 +0100 Subject: [PATCH 078/199] Restaurant widget moved to the bottom --- uni/lib/utils/favorite_widget_type.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/lib/utils/favorite_widget_type.dart b/uni/lib/utils/favorite_widget_type.dart index bc74e102d..9e27fe865 100644 --- a/uni/lib/utils/favorite_widget_type.dart +++ b/uni/lib/utils/favorite_widget_type.dart @@ -3,9 +3,9 @@ enum FavoriteWidgetType { schedule, printBalance, account, - restaurant, libraryOccupation(faculties: {'feup'}), - busStops; + busStops, + restaurant; const FavoriteWidgetType({this.faculties}); From 1142b57f12731d82552874452d3c3ae44c9a61de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Fri, 25 Aug 2023 16:21:29 +0100 Subject: [PATCH 079/199] Update README.md grammer --- uni/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uni/README.md b/uni/README.md index e718bd0fe..b6c91e4eb 100644 --- a/uni/README.md +++ b/uni/README.md @@ -32,7 +32,7 @@ In order to remove it, is it as simple as running the following command, from th ### Generated files -Flutter doesn't support runtime reflection, in order to circumvent these limitations, we use **automatic code generation** or **static metaprogramming** for things like **mocks** and other possible usecases. By convention, you should **always commit** the generated `.dart` files into the repository. +Flutter doesn't support runtime reflection. In order to circumvent these limitations, we use **automatic code generation** or **static metaprogramming** for things like **mocks** and other possible usecases. By convention, you should **always commit** the generated `.dart` files into the repository. Dart leverages annotations to signal the `build_runner` that it should generate some code. They look something like this: ```dart @@ -46,14 +46,14 @@ Dart leverages annotations to signal the `build_runner` that it should generate } ``` -In this case, `build_runner` will dectect that `GenerateNiceMocks` is a generator function from `mockito` and will generate code to a different file. +In this case, `build_runner` will detect that `GenerateNiceMocks` is a generator function from `mockito` and will generate code to a different file. In order to run the `build_runner` once: ```sh dart run build_runner build ``` -But you can also watch for changes in `.dart` files and automatically run the `build_runner` on those file changes (useful if you find yourself need to generate code very frequently): +But you can also watch for changes in `.dart` files and automatically run the `build_runner` on those file changes (useful if you find yourself in need to generate code very frequently): ```sh dart run build_runner watch ``` From db339bf6479f50dbc8d20c38ffe6cecbc66799a3 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Fri, 25 Aug 2023 15:26:04 +0000 Subject: [PATCH 080/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index ce5241713..8d22ede0a 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.54+172 \ No newline at end of file +1.5.55+173 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index b2e4e3b63..304dbac25 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.54+172 +version: 1.5.55+173 environment: sdk: ">=2.17.1 <3.0.0" From 4418be70774d6f9fdf16c32e5c1cab1a8538708b Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 25 Aug 2023 20:17:24 +0100 Subject: [PATCH 081/199] Fixed tests errors --- uni/test/integration/src/schedule_page_test.dart | 1 + uni/test/unit/view/Pages/exams_page_view_test.dart | 6 ++++++ uni/test/unit/view/Widgets/exam_row_test.dart | 4 ++++ uni/test/unit/view/Widgets/schedule_slot_test.dart | 3 +++ 4 files changed, 14 insertions(+) diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index c01bf08e2..6787a98bc 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -63,6 +63,7 @@ void main() { ]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); const scheduleSlotTimeKey1 = 'schedule-slot-time-11:00-13:00'; const scheduleSlotTimeKey2 = 'schedule-slot-time-14:00-16:00'; 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 119e408c2..d4e3a227f 100644 --- a/uni/test/unit/view/Pages/exams_page_view_test.dart +++ b/uni/test/unit/view/Pages/exams_page_view_test.dart @@ -48,6 +48,7 @@ void main() { final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); expect(find.byKey(Key(firstExam.toString())), findsOneWidget); expect(find.byKey(Key('$firstExam-exam')), findsOneWidget); @@ -90,6 +91,7 @@ void main() { final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); expect( find.byKey(Key(examList.map((ex) => ex.toString()).join())), @@ -135,6 +137,8 @@ void main() { final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); + expect(find.byKey(Key(firstExam.toString())), findsOneWidget); expect(find.byKey(Key(secondExam.toString())), findsOneWidget); expect(find.byKey(Key('$firstExam-exam')), findsOneWidget); @@ -202,6 +206,8 @@ void main() { final providers = [ChangeNotifierProvider(create: (_) => examProvider)]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); + expect(find.byKey(Key(firstDayKey)), findsOneWidget); expect(find.byKey(Key(secondDayKey)), findsOneWidget); expect(find.byKey(Key('$firstExam-exam')), findsOneWidget); diff --git a/uni/test/unit/view/Widgets/exam_row_test.dart b/uni/test/unit/view/Widgets/exam_row_test.dart index 47ea0bac1..02b547631 100644 --- a/uni/test/unit/view/Widgets/exam_row_test.dart +++ b/uni/test/unit/view/Widgets/exam_row_test.dart @@ -35,6 +35,8 @@ void main() { ChangeNotifierProvider(create: (_) => ExamProvider()) ]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); + final roomsKey = '$subject-$rooms-$beginTime-$endTime'; expect( @@ -56,6 +58,8 @@ void main() { ]; await tester.pumpWidget(testableWidget(widget, providers: providers)); + await tester.pump(); + final roomsKey = '$subject-$rooms-$beginTime-$endTime'; expect( diff --git a/uni/test/unit/view/Widgets/schedule_slot_test.dart b/uni/test/unit/view/Widgets/schedule_slot_test.dart index 2a85c7c3a..ab664da90 100644 --- a/uni/test/unit/view/Widgets/schedule_slot_test.dart +++ b/uni/test/unit/view/Widgets/schedule_slot_test.dart @@ -29,6 +29,7 @@ void main() { ); await tester.pumpWidget(testableWidget(widget)); + await tester.pump(); testScheduleSlot(subject, beginText, endText, rooms, typeClass, teacher); }); @@ -50,6 +51,8 @@ void testScheduleSlot( matching: find.text(begin), ), findsOneWidget, + reason: + 'Expected to find widget with text $begin and key $scheduleSlotTimeKey', ); expect( find.descendant( From fe7c7def9735270c7a6ba8cff980d45e70496b17 Mon Sep 17 00:00:00 2001 From: thePeras Date: Fri, 25 Aug 2023 23:03:14 +0100 Subject: [PATCH 082/199] Gitignore Podfile generated by CocoaPods --- uni/.gitignore | 2 ++ uni/ios/Podfile | 41 ----------------------------------------- uni/macos/Podfile | 40 ---------------------------------------- 3 files changed, 2 insertions(+), 81 deletions(-) delete mode 100644 uni/ios/Podfile delete mode 100644 uni/macos/Podfile diff --git a/uni/.gitignore b/uni/.gitignore index 9d9b2a895..69fd250d8 100644 --- a/uni/.gitignore +++ b/uni/.gitignore @@ -101,12 +101,14 @@ unlinked_spec.ds **/ios/Flutter/flutter_export_environment.sh **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* +**/ios/Podfile # macOS **/Flutter/ephemeral/ **/Pods/ **/macos/Flutter/GeneratedPluginRegistrant.swift **/macos/Flutter/ephemeral +**/macos/Podfile **/xcuserdata/ # Windows diff --git a/uni/ios/Podfile b/uni/ios/Podfile deleted file mode 100644 index 88359b225..000000000 --- a/uni/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '11.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/uni/macos/Podfile b/uni/macos/Podfile deleted file mode 100644 index 049abe295..000000000 --- a/uni/macos/Podfile +++ /dev/null @@ -1,40 +0,0 @@ -platform :osx, '10.14' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end From bfb18c6002d8f1a5f3adee2178ad2a82a8a5fd27 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 20 Aug 2023 23:19:14 +0100 Subject: [PATCH 083/199] Fix calendar parsing --- uni/lib/view/calendar/calendar.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 48b0ef1fa..f1c69d671 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -46,6 +46,14 @@ class CalendarPageViewState extends GeneralPageViewState { } Widget getTimeline(BuildContext context, List calendar) { + // Filter out events where name or date is a non-breaking space + final filteredCalendar = calendar + .where( + (event) => + event.name.trim() != ' ' && event.date.trim() != ' ', + ) + .toList(); + return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( connectorTheme: TimelineTheme.of(context) @@ -60,7 +68,7 @@ class CalendarPageViewState extends GeneralPageViewState { contentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - calendar[index].name, + filteredCalendar[index].name, style: Theme.of(context) .textTheme .titleLarge @@ -70,13 +78,13 @@ class CalendarPageViewState extends GeneralPageViewState { oppositeContentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - calendar[index].date, + filteredCalendar[index].date, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontStyle: FontStyle.italic, ), ), ), - itemCount: calendar.length, + itemCount: filteredCalendar.length, ), ); } From d514742882d93b6a5b145280c6dec2edf4f557d2 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 24 Aug 2023 22:52:55 +0100 Subject: [PATCH 084/199] Filter at parse lever --- uni/lib/controller/parsers/parser_calendar.dart | 11 ++++++++++- uni/lib/view/calendar/calendar.dart | 14 +++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/uni/lib/controller/parsers/parser_calendar.dart b/uni/lib/controller/parsers/parser_calendar.dart index 77af03e39..e98d5467d 100644 --- a/uni/lib/controller/parsers/parser_calendar.dart +++ b/uni/lib/controller/parsers/parser_calendar.dart @@ -7,7 +7,7 @@ Future> getCalendarFromHtml(Response response) async { final calendarHtml = document.querySelectorAll('tr'); - return calendarHtml + final eventList = calendarHtml .map( (event) => CalendarEvent( event.children[0].innerHtml, @@ -15,4 +15,13 @@ Future> getCalendarFromHtml(Response response) async { ), ) .toList(); + + final filteredCalendar = eventList + .where( + (event) => + event.name.trim() != ' ' && event.date.trim() != ' ', + ) + .toList(); + + return filteredCalendar; } diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index f1c69d671..48b0ef1fa 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -46,14 +46,6 @@ class CalendarPageViewState extends GeneralPageViewState { } Widget getTimeline(BuildContext context, List calendar) { - // Filter out events where name or date is a non-breaking space - final filteredCalendar = calendar - .where( - (event) => - event.name.trim() != ' ' && event.date.trim() != ' ', - ) - .toList(); - return FixedTimeline.tileBuilder( theme: TimelineTheme.of(context).copyWith( connectorTheme: TimelineTheme.of(context) @@ -68,7 +60,7 @@ class CalendarPageViewState extends GeneralPageViewState { contentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - filteredCalendar[index].name, + calendar[index].name, style: Theme.of(context) .textTheme .titleLarge @@ -78,13 +70,13 @@ class CalendarPageViewState extends GeneralPageViewState { oppositeContentsBuilder: (context, index) => Padding( padding: const EdgeInsets.all(24), child: Text( - filteredCalendar[index].date, + calendar[index].date, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontStyle: FontStyle.italic, ), ), ), - itemCount: filteredCalendar.length, + itemCount: calendar.length, ), ); } From 543a3637ca366c83e6b6aa5c9f0d57fe6d5a0656 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Sat, 26 Aug 2023 12:47:08 +0000 Subject: [PATCH 085/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 8d22ede0a..ba05a7c9f 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.55+173 \ No newline at end of file +1.5.56+174 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 304dbac25..12fc59ac6 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.55+173 +version: 1.5.56+174 environment: sdk: ">=2.17.1 <3.0.0" From d1a358036412acf7dcc12037c5beebd03b36ed7b Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sun, 13 Aug 2023 15:31:23 +0100 Subject: [PATCH 086/199] Fix home page loading on card number regression --- .../local_storage/app_shared_preferences.dart | 16 ++++++++++++++-- uni/lib/view/home/widgets/main_cards_list.dart | 4 ++-- uni/lib/view/lazy_consumer.dart | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index 627518e82..be8be85e9 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -177,8 +177,20 @@ class AppSharedPreferences { /// Returns a list containing the user's favorite widgets. static Future> getFavoriteCards() async { final prefs = await SharedPreferences.getInstance(); - final storedFavorites = prefs.getStringList(favoriteCards); - if (storedFavorites == null) return defaultFavoriteCards; + var storedFavorites = prefs.getStringList(favoriteCards); + + if (storedFavorites == null) { + return defaultFavoriteCards; + } else if (storedFavorites.length < FavoriteWidgetType.values.length) { + // A new card is not available in this version, so skip it + storedFavorites = storedFavorites + .where( + (element) => int.parse(element) < FavoriteWidgetType.values.length, + ) + .toList(); + await prefs.setStringList(favoriteCards, storedFavorites); + } + return storedFavorites .map((i) => FavoriteWidgetType.values[int.parse(i)]) .toList(); diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index 16ebe80ed..acac8a12e 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -181,7 +181,7 @@ class MainCardsList extends StatelessWidget { List favoriteCardsFromTypes( List cardTypes, BuildContext context, - HomePageProvider editingModeProvider, + HomePageProvider homePageProvider, ) { final userSession = Provider.of(context, listen: false).session; @@ -192,7 +192,7 @@ class MainCardsList extends StatelessWidget { final i = cardTypes.indexOf(type); return cardCreators[type]!( Key(i.toString()), - editingMode: editingModeProvider.isEditing, + editingMode: homePageProvider.isEditing, onDelete: () => removeCardIndexFromFavorites(i, context), ); }).toList(); diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index d130e70a5..d5b14438e 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -43,7 +43,7 @@ class LazyConsumer extends StatelessWidget { await provider.ensureInitializedFromRemote(context); } } catch (e) { - Logger().e('Failed to initialize provider: ', e); + Logger().e('Failed to initialize $T: $e'); } }); From d2fe20597175dc28dec2a8a41b70e0f479c47a0d Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sun, 13 Aug 2023 16:05:11 +0100 Subject: [PATCH 087/199] Fix concurrent login requests --- .../local_storage/app_shared_preferences.dart | 15 ++++------ .../controller/networking/network_router.dart | 28 ++++++++++++++++-- .../providers/state_provider_notifier.dart | 2 +- uni/lib/view/lazy_consumer.dart | 29 ++++++++++--------- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index be8be85e9..d27fcabbd 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -177,18 +177,15 @@ class AppSharedPreferences { /// Returns a list containing the user's favorite widgets. static Future> getFavoriteCards() async { final prefs = await SharedPreferences.getInstance(); - var storedFavorites = prefs.getStringList(favoriteCards); + final storedFavorites = prefs + .getStringList(favoriteCards) + ?.where( + (element) => int.parse(element) < FavoriteWidgetType.values.length, + ) + .toList(); if (storedFavorites == null) { return defaultFavoriteCards; - } else if (storedFavorites.length < FavoriteWidgetType.values.length) { - // A new card is not available in this version, so skip it - storedFavorites = storedFavorites - .where( - (element) => int.parse(element) < FavoriteWidgetType.values.length, - ) - .toList(); - await prefs.setStringList(favoriteCards, storedFavorites); } return storedFavorites diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index 47f0eb09b..5d64c5ecc 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -27,6 +27,14 @@ class NetworkRouter { /// The mutual exclusion primitive for login requests. static final Lock _loginLock = Lock(); + /// The last time the user was logged in. + /// Used to avoid repeated concurrent login requests. + static DateTime? _lastLoginTime; + + /// Cached session for the current user. + /// Returned on repeated concurrent login requests. + static Session? _cachedSession; + /// Performs a login using the Sigarra API, /// returning an authenticated [Session] on the given [faculties] with the /// given username [username] and password [password] if successful. @@ -37,6 +45,14 @@ class NetworkRouter { required bool persistentSession, }) async { return _loginLock.synchronized(() async { + if (_lastLoginTime != null && + DateTime.now().difference(_lastLoginTime!) < + const Duration(minutes: 1) && + _cachedSession != null) { + Logger().d('Login request ignored due to recent login'); + return _cachedSession; + } + final url = '${NetworkRouter.getBaseUrls(faculties)[0]}mob_val_geral.autentica'; @@ -61,6 +77,9 @@ class NetworkRouter { } Logger().i('Login successful'); + _lastLoginTime = DateTime.now(); + _cachedSession = session; + return session; }); } @@ -74,7 +93,7 @@ class NetworkRouter { final faculties = session.faculties; final persistentSession = session.persistentSession; - Logger().i('Re-logging in user $username'); + Logger().d('Re-login from session: $username, $faculties'); return login( username, @@ -154,7 +173,8 @@ class NetworkRouter { final forbidden = response.statusCode == 403; if (forbidden) { - final userIsLoggedIn = await userLoggedIn(session); + final userIsLoggedIn = + _cachedSession != null && await userLoggedIn(session); if (!userIsLoggedIn) { final newSession = await reLoginFromSession(session); @@ -189,13 +209,17 @@ class NetworkRouter { /// performing a health check on the user's personal page. static Future userLoggedIn(Session session) async { return _loginLock.synchronized(() async { + Logger().i('Checking if user is still logged in'); + final url = '${getBaseUrl(session.faculties[0])}' 'fest_geral.cursos_list?pv_num_unico=${session.username}'; final headers = {}; headers['cookie'] = session.cookies; + final response = await (httpClient != null ? httpClient!.get(url.toUri(), headers: headers) : http.get(url.toUri(), headers: headers)); + return response.statusCode == 200; }); } diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index d192b8bf4..de3e71696 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -62,7 +62,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { DateTime.now().difference(_lastUpdateTime!) > cacheDuration!; if (!shouldReload) { - Logger().i('Last info for $runtimeType is within cache period ' + Logger().d('Last info for $runtimeType is within cache period ' '(last updated on $_lastUpdateTime); skipping remote load'); updateStatus(RequestStatus.successful); return; diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index d5b14438e..60318807b 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; @@ -21,26 +23,27 @@ class LazyConsumer extends StatelessWidget { Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) async { try { - // Load data stored in the database immediately final provider = Provider.of(context, listen: false); - await provider.ensureInitializedFromStorage(); // If the provider fetchers depend on the session, make sure that // SessionProvider and ProfileProvider are initialized - if (provider.dependsOnSession) { - if (context.mounted) { - await Provider.of(context, listen: false) - .ensureInitialized(context); - } - if (context.mounted) { - await Provider.of(context, listen: false) - .ensureInitialized(context); - } - } + final sessionFuture = provider.dependsOnSession + ? Provider.of(context, listen: false) + .ensureInitialized(context) + .then((_) { + Provider.of(context, listen: false) + .ensureInitialized(context); + }) + : Future(() {}); + + // Load data stored in the database immediately + await provider.ensureInitializedFromStorage(); // Finally, complete provider initialization if (context.mounted) { - await provider.ensureInitializedFromRemote(context); + await sessionFuture.then((_) async { + await provider.ensureInitializedFromRemote(context); + }); } } catch (e) { Logger().e('Failed to initialize $T: $e'); From 3959c835b1ad314ec156bd67e76fb79d03b49bb0 Mon Sep 17 00:00:00 2001 From: Bruno Mendes <61701401+bdmendes@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:59:45 +0100 Subject: [PATCH 088/199] Wait for profile provider initialization --- uni/lib/view/lazy_consumer.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 60318807b..7364306b4 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -17,6 +17,7 @@ class LazyConsumer extends StatelessWidget { required this.builder, super.key, }); + final Widget Function(BuildContext, T) builder; @override @@ -30,8 +31,8 @@ class LazyConsumer extends StatelessWidget { final sessionFuture = provider.dependsOnSession ? Provider.of(context, listen: false) .ensureInitialized(context) - .then((_) { - Provider.of(context, listen: false) + .then((_) async { + await Provider.of(context, listen: false) .ensureInitialized(context); }) : Future(() {}); From 0e857089b0dbed78acca07afb88b379fe7bc6d0b Mon Sep 17 00:00:00 2001 From: bdmendes Date: Thu, 31 Aug 2023 18:26:40 +0000 Subject: [PATCH 089/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index ba05a7c9f..1fafb60be 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.56+174 \ No newline at end of file +1.5.57+175 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 12fc59ac6..7d3d601da 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.56+174 +version: 1.5.57+175 environment: sdk: ">=2.17.1 <3.0.0" From 800ce699528f85947e01efdd35fd89de09ce9154 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 15:14:05 +0100 Subject: [PATCH 090/199] Update target sdk version --- uni/android/app/build.gradle | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/uni/android/app/build.gradle b/uni/android/app/build.gradle index 1e13ce5bc..8fe00a408 100644 --- a/uni/android/app/build.gradle +++ b/uni/android/app/build.gradle @@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 33 + compileSdkVersion 33 // default is flutter.compileSdkVersion ndkVersion flutter.ndkVersion compileOptions { @@ -50,10 +50,8 @@ android { defaultConfig { applicationId "pt.up.fe.ni.uni" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. minSdkVersion 21 // default is flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + targetSdkVersion 33 // default is flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } From 43e6780013cf534f0f0d0135955a9570661156fd Mon Sep 17 00:00:00 2001 From: bdmendes Date: Thu, 31 Aug 2023 18:30:03 +0000 Subject: [PATCH 091/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 1fafb60be..1e7f5c2d4 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.57+175 \ No newline at end of file +1.5.58+176 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 7d3d601da..7eb18e425 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.57+175 +version: 1.5.58+176 environment: sdk: ">=2.17.1 <3.0.0" From 006e281e7efb0bee529327f2f438edd5b13212ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 31 Aug 2023 23:06:19 +0100 Subject: [PATCH 092/199] fix tests --- uni/test/test_widget.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index c8430b967..3171ad692 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -1,13 +1,20 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; Widget testableWidget( Widget widget, { List providers = const [], }) { - if (providers.isEmpty) return wrapWidget(widget); - - return MultiProvider(providers: providers, child: wrapWidget(widget)); + return MultiProvider( + providers: [ + ChangeNotifierProvider(create: (context) => SessionProvider()), + ChangeNotifierProvider(create: (context) => ProfileProvider()), + ...providers + ], + child: wrapWidget(widget), + ); } Widget wrapWidget(Widget widget) { From 161bb92cd78b904ba87d57a3961006e0ca9eabe3 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 31 Aug 2023 23:11:56 +0100 Subject: [PATCH 093/199] Missed translations, inefficient enums removal --- uni/analysis_options.yaml | 1 + .../local_storage/app_shared_preferences.dart | 3 +- uni/lib/generated/intl/messages_all.dart | 7 +- uni/lib/generated/intl/messages_en.dart | 61 ++++-- uni/lib/generated/intl/messages_pt_PT.dart | 168 +++++++------- uni/lib/generated/l10n.dart | 205 ++++++++++++++++-- uni/lib/l10n/intl_en.arb | 34 +++ uni/lib/l10n/intl_pt_PT.arb | 34 +++ uni/lib/model/entities/exam.dart | 45 +--- uni/lib/view/bug_report/widgets/form.dart | 25 +-- .../course_unit_info/course_unit_info.dart | 16 +- .../view/home/widgets/restaurant_card.dart | 8 +- uni/lib/view/login/login.dart | 13 +- .../widgets/create_print_mb_dialog.dart | 21 +- 14 files changed, 430 insertions(+), 211 deletions(-) diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index 92d895f92..6df16fd8f 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -4,6 +4,7 @@ analyzer: # Exclude auto-generated files from dart analysis exclude: - "**.g.dart" + - "/lib/generated/**.dart" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index e3a6478da..bd8206faf 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:encrypt/encrypt.dart' as encrypt; import 'package:flutter/material.dart'; @@ -125,7 +126,7 @@ class AppSharedPreferences { static Future getLocale() async { final prefs = await SharedPreferences.getInstance(); - final appLocale = prefs.getString(locale) ?? 'en'; + final appLocale = prefs.getString(locale) ?? Platform.localeName; return Locale(appLocale); } diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index de96ef7c8..5c2bef3d1 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -61,8 +61,11 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = - Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + final actualLocale = Intl.verifiedLocale( + locale, + _messagesExistFor, + onFailure: (_) => null, + ); if (actualLocale == null) return null; return _findExact(actualLocale); } diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 58c300a64..6cb2f58f8 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -51,19 +51,20 @@ class MessageLookup extends MessageLookupByLibrary { "account_card_title": MessageLookupByLibrary.simpleMessage("Checking account"), "add": MessageLookupByLibrary.simpleMessage("Add"), + "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), - "agree_terms": - MessageLookupByLibrary.simpleMessage("By entering you confirm that " - "you agree with these Terms and Conditions"), - "all_widgets_added": - MessageLookupByLibrary.simpleMessage("All available widgets have " - "already been added to your personal area!"), + "agree_terms": MessageLookupByLibrary.simpleMessage( + "By entering you confirm that you agree with these Terms and Conditions", + ), + "all_widgets_added": MessageLookupByLibrary.simpleMessage( + "All available widgets have already been added to your personal area!", + ), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( - r"Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!", + "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!", ), "bug_description": MessageLookupByLibrary.simpleMessage( "Bug found, how to reproduce it, etc.", @@ -76,9 +77,13 @@ class MessageLookup extends MessageLookupByLibrary { "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites 'Bus' widget. " - "The remaining ones will only be displayed on the page."), + "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.", + ), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), + "change": MessageLookupByLibrary.simpleMessage("Change"), + "change_prompt": MessageLookupByLibrary.simpleMessage( + "Do you want to change the password?", + ), "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), "college": MessageLookupByLibrary.simpleMessage("College: "), @@ -89,23 +94,26 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by " - "NIAEFEUP and may be deleted at my request."), + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", + ), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B | AEFEUP building", ), + "course_class": MessageLookupByLibrary.simpleMessage("Classes"), + "course_info": MessageLookupByLibrary.simpleMessage("Info"), "current_state": MessageLookupByLibrary.simpleMessage("Current state: "), "current_year": MessageLookupByLibrary.simpleMessage("Current academic year: "), + "decrement": MessageLookupByLibrary.simpleMessage("Decrement 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Description"), "desired_email": MessageLookupByLibrary.simpleMessage( "Email where you want to be contacted", ), "dona_bia": MessageLookupByLibrary.simpleMessage( - "D. Beatriz's stationery store", + "D. Beatriz\'s stationery store", ), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B (B-142)", @@ -117,6 +125,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Please fill in this field"), "exams_filter": MessageLookupByLibrary.simpleMessage("Exam Filter Settings"), + "expired_password": + MessageLookupByLibrary.simpleMessage("Your password has expired"), "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), "fee_date": MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), @@ -129,10 +139,13 @@ class MessageLookup extends MessageLookupByLibrary { "floors": MessageLookupByLibrary.simpleMessage("Floors"), "forgot_password": MessageLookupByLibrary.simpleMessage("Forgot password?"), + "generate_reference": + MessageLookupByLibrary.simpleMessage("Generate reference"), "geral_registration": MessageLookupByLibrary.simpleMessage("General Registration"), "improvement_registration": MessageLookupByLibrary.simpleMessage("Enrollment for Improvement"), + "increment": MessageLookupByLibrary.simpleMessage("Increment 1,00€"), "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), "last_refresh_time": m0, "last_timestamp": m1, @@ -144,17 +157,22 @@ class MessageLookup extends MessageLookupByLibrary { "login": MessageLookupByLibrary.simpleMessage("Login"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), + "min_value_reference": + MessageLookupByLibrary.simpleMessage("Minimum value: 1,00 €"), "multimedia_center": MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("News"), - "no_bus": MessageLookupByLibrary.simpleMessage("Don't miss any bus!"), + "no_bus": MessageLookupByLibrary.simpleMessage("Don\'t miss any bus!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), + "no_class": MessageLookupByLibrary.simpleMessage( + "There are no classes to display", + ), "no_classes": MessageLookupByLibrary.simpleMessage("No classes to present"), "no_classes_on": - MessageLookupByLibrary.simpleMessage("You don't have classes on"), + MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), "no_college": MessageLookupByLibrary.simpleMessage("no college"), "no_course_units": MessageLookupByLibrary.simpleMessage( "No course units in the selected period", @@ -169,6 +187,11 @@ class MessageLookup extends MessageLookupByLibrary { "no_exams_label": MessageLookupByLibrary.simpleMessage( "Looks like you are on vacation!", ), + "no_favorite_restaurants": + MessageLookupByLibrary.simpleMessage("No favorite restaurants"), + "no_info": MessageLookupByLibrary.simpleMessage( + "There is no information to display", + ), "no_menu_info": MessageLookupByLibrary.simpleMessage( "There is no information available about meals", ), @@ -190,6 +213,9 @@ class MessageLookup extends MessageLookupByLibrary { "occurrence_type": MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), + "pass_change_request": MessageLookupByLibrary.simpleMessage( + "For security reasons, passwords must be changed periodically.", + ), "password": MessageLookupByLibrary.simpleMessage("password"), "pendent_references": MessageLookupByLibrary.simpleMessage("Pending references"), @@ -201,6 +227,12 @@ class MessageLookup extends MessageLookupByLibrary { "problem_id": MessageLookupByLibrary.simpleMessage( "Brief identification of the problem", ), + "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( + "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account", + ), + "reference_success": MessageLookupByLibrary.simpleMessage( + "Reference created successfully!", + ), "remove": MessageLookupByLibrary.simpleMessage("Delete"), "room": MessageLookupByLibrary.simpleMessage("Room"), "school_calendar": @@ -210,6 +242,7 @@ class MessageLookup extends MessageLookupByLibrary { "sent_error": MessageLookupByLibrary.simpleMessage( "An error occurred in sending", ), + "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), "student_number": diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 4b09319f9..297fff62c 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -19,30 +19,26 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt_PT'; - static String m0(dynamic time) => "última atualização às ${time}"; + static m0(time) => "última atualização às ${time}"; - static String m1(dynamic time) => Intl.plural( - time as num, - zero: 'Atualizado há ${time} minutos', - one: 'Atualizado há ${time} minuto', - other: 'Atualizado há ${time} minutos', - ); + static m1(time) => + "${Intl.plural(time as num, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static String m2(String title) => Intl.select(title, { - 'horario': 'Horário', - 'exames': 'Exames', - 'area': 'Área Pessoal', - 'cadeiras': 'Cadeiras', - 'autocarros': 'Autocarros', - 'locais': 'Locais', - 'restaurantes': 'Restaurantes', - 'calendario': 'Calendário', - 'biblioteca': 'Biblioteca', - 'uteis': 'Úteis', - 'sobre': 'Sobre', - 'bugs': 'Bugs e Sugestões', - 'other': 'Outros', - }); + static m2(String title) => "${Intl.select(title, { + 'horario': 'Horário', + 'exames': 'Exames', + 'area': 'Área Pessoal', + 'cadeiras': 'Cadeiras', + 'autocarros': 'Autocarros', + 'locais': 'Locais', + 'restaurantes': 'Restaurantes', + 'calendario': 'Calendário', + 'biblioteca': 'Biblioteca', + 'uteis': 'Úteis', + 'sobre': 'Sobre', + 'bugs': 'Bugs e Sugestões', + 'other': 'Outros', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -51,94 +47,87 @@ class MessageLookup extends MessageLookupByLibrary { "account_card_title": MessageLookupByLibrary.simpleMessage("Conta Corrente"), "add": MessageLookupByLibrary.simpleMessage("Adicionar"), + "add_quota": MessageLookupByLibrary.simpleMessage("Adicionar quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "Ao entrares confirmas que concordas " - "com estes Termos e Condições", - ), + "Ao entrares confirmas que concordas com estes Termos e Condições"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "Todos os widgets disponíveis já foram adicionados à tua " - "área pessoal!"), + "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), "at_least_one_college": MessageLookupByLibrary.simpleMessage( - "Seleciona pelo menos uma faculdade", - ), + "Seleciona pelo menos uma faculdade"), "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( - r"Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!", - ), + "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!"), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug encontrado, como o reproduzir, etc", - ), + "Bug encontrado, como o reproduzir, etc"), "bus_error": MessageLookupByLibrary.simpleMessage( - "Não foi possível obter informação", - ), + "Não foi possível obter informação"), "bus_information": MessageLookupByLibrary.simpleMessage( - "Seleciona os autocarros dos quais queres informação:", - ), + "Seleciona os autocarros dos quais queres informação:"), "buses_personalize": MessageLookupByLibrary.simpleMessage( - "Configura aqui os teus autocarros", - ), + "Configura aqui os teus autocarros"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Os autocarros favoritos serão apresentados no widget " - "'Autocarros' dos favoritos. " - "Os restantes serão apresentados apenas na página."), + "Os autocarros favoritos serão apresentados no widget \'Autocarros\' dos favoritos. Os restantes serão apresentados apenas na página."), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), + "change": MessageLookupByLibrary.simpleMessage("Alterar"), + "change_prompt": MessageLookupByLibrary.simpleMessage( + "Deseja alterar a palavra-passe?"), "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), "college_select": MessageLookupByLibrary.simpleMessage( - "seleciona a(s) tua(s) faculdade(s)", - ), + "seleciona a(s) tua(s) faculdade(s)"), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "consent": MessageLookupByLibrary.simpleMessage( - "Consinto que esta informação seja revista pelo NIAEFEUP, " - "podendo ser eliminada a meu pedido."), + "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido."), "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B | Edifício da AEFEUP", - ), + "Piso -1 do edifício B | Edifício da AEFEUP"), + "course_class": MessageLookupByLibrary.simpleMessage("Turmas"), + "course_info": MessageLookupByLibrary.simpleMessage("Ficha"), "current_state": MessageLookupByLibrary.simpleMessage("Estado atual: "), "current_year": MessageLookupByLibrary.simpleMessage("Ano curricular atual: "), + "decrement": MessageLookupByLibrary.simpleMessage("Decrementar 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Descrição"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email em que desejas ser contactado", - ), + "Email em que desejas ser contactado"), "dona_bia": MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B (B-142)", - ), + "Piso -1 do edifício B (B-142)"), "ects": MessageLookupByLibrary.simpleMessage("ECTs realizados: "), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( - "Por favor preenche este campo", - ), + "Por favor preenche este campo"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), + "expired_password": + MessageLookupByLibrary.simpleMessage("A tua palavra-passe expirou"), "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), "fee_date": MessageLookupByLibrary.simpleMessage( - "Data limite próxima prestação:", - ), + "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( - "Notificar próxima data limite:", - ), + "Notificar próxima data limite:"), "first_year_registration": MessageLookupByLibrary.simpleMessage("Ano da primeira inscrição: "), "floor": MessageLookupByLibrary.simpleMessage("Piso"), "floors": MessageLookupByLibrary.simpleMessage("Pisos"), "forgot_password": MessageLookupByLibrary.simpleMessage("Esqueceu a palavra-passe?"), + "generate_reference": + MessageLookupByLibrary.simpleMessage("Gerar referência"), "geral_registration": MessageLookupByLibrary.simpleMessage("Inscrição Geral"), "improvement_registration": MessageLookupByLibrary.simpleMessage("Inscrição para Melhoria"), + "increment": MessageLookupByLibrary.simpleMessage("Incrementar 1,00€"), "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão iniciada"), "last_refresh_time": m0, @@ -146,71 +135,72 @@ class MessageLookup extends MessageLookupByLibrary { "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Carregando os Termos e Condições...", - ), + "Carregando os Termos e Condições..."), "login": MessageLookupByLibrary.simpleMessage("Entrar"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), + "min_value_reference": + MessageLookupByLibrary.simpleMessage("Valor mínimo: 1,00 €"), "multimedia_center": MessageLookupByLibrary.simpleMessage("Centro de multimédia"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("Notícias"), "no_bus": MessageLookupByLibrary.simpleMessage( - "Não percas nenhum autocarro!", - ), + "Não percas nenhum autocarro!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage( - "Não existe nenhuma paragem configurada", - ), + "Não existe nenhuma paragem configurada"), + "no_class": MessageLookupByLibrary.simpleMessage( + "Não existem turmas para apresentar"), "no_classes": MessageLookupByLibrary.simpleMessage( - "Não existem aulas para apresentar", - ), + "Não existem aulas para apresentar"), "no_classes_on": MessageLookupByLibrary.simpleMessage("Não possui aulas à"), "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "Sem cadeiras no período selecionado", - ), + "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( - "Não há dados a mostrar neste momento", - ), + "Não há dados a mostrar neste momento"), "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), "no_exams_label": MessageLookupByLibrary.simpleMessage("Parece que estás de férias!"), + "no_favorite_restaurants": + MessageLookupByLibrary.simpleMessage("Sem restaurantes favoritos"), + "no_info": MessageLookupByLibrary.simpleMessage( + "Não existem informações para apresentar"), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "Não há informação disponível sobre refeições", - ), + "Não há informação disponível sobre refeições"), "no_menus": MessageLookupByLibrary.simpleMessage( - "Não há refeições disponíveis", - ), + "Não há refeições disponíveis"), "no_name_course": MessageLookupByLibrary.simpleMessage("Curso sem nome"), "no_references": MessageLookupByLibrary.simpleMessage( - "Não existem referências a pagar", - ), + "Não existem referências a pagar"), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "Não existem cadeiras para apresentar", - ), + "Não existem cadeiras para apresentar"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "Não existem exames para apresentar", - ), + "Não existem exames para apresentar"), "occurrence_type": MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), + "pass_change_request": MessageLookupByLibrary.simpleMessage( + "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente."), "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "pendent_references": MessageLookupByLibrary.simpleMessage("Referências pendentes"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Atendimento presencial"), "press_again": MessageLookupByLibrary.simpleMessage( - "Pressione novamente para sair", - ), + "Pressione novamente para sair"), "print": MessageLookupByLibrary.simpleMessage("Impressão"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Breve identificação do problema", - ), + "Breve identificação do problema"), + "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( + "Os dados da referência gerada aparecerão no Sigarra, conta corrente.\\nPerfil > Conta Corrente"), + "reference_success": MessageLookupByLibrary.simpleMessage( + "Referência criada com sucesso!"), "remove": MessageLookupByLibrary.simpleMessage("Remover"), "room": MessageLookupByLibrary.simpleMessage("Sala"), "school_calendar": @@ -219,6 +209,7 @@ class MessageLookup extends MessageLookupByLibrary { "send": MessageLookupByLibrary.simpleMessage("Enviar"), "sent_error": MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), + "some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), "student_number": @@ -227,18 +218,15 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Atendimento presencial e telefónico", - ), + "Atendimento presencial e telefónico"), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), "terms": MessageLookupByLibrary.simpleMessage("Termos e Condições"), "title": MessageLookupByLibrary.simpleMessage("Título"), "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), "valid_email": MessageLookupByLibrary.simpleMessage( - "Por favor insere um email válido", - ), + "Por favor insere um email válido"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:", - ), + "Escolhe um widget para adicionares à tua área pessoal:"), "year": MessageLookupByLibrary.simpleMessage("Ano") }; } diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 50d0fbcdf..a0ac95cfd 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:uni/generated/intl/messages_all.dart'; +import 'intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -18,35 +18,28 @@ class S { static S? _current; static S get current { - assert( - _current != null, - 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.', - ); + assert(_current != null, 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); return _current!; } - static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); + static const AppLocalizationDelegate delegate = + AppLocalizationDelegate(); static Future load(Locale locale) { - final name = (locale.countryCode?.isEmpty ?? false) - ? locale.languageCode - : locale.toString(); - final localeName = Intl.canonicalizedLocale(name); + final name = (locale.countryCode?.isEmpty ?? false) ? locale.languageCode : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); return initializeMessages(localeName).then((_) { Intl.defaultLocale = localeName; final instance = S(); S._current = instance; - + return instance; }); - } + } static S of(BuildContext context) { final instance = S.maybeOf(context); - assert( - instance != null, - 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?', - ); + assert(instance != null, 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); return instance!; } @@ -84,6 +77,16 @@ class S { ); } + /// `Add quota` + String get add_quota { + return Intl.message( + 'Add quota', + name: 'add_quota', + desc: '', + args: [], + ); + } + /// `Add widget` String get add_widget { return Intl.message( @@ -187,7 +190,7 @@ class S { /// `Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.` String get buses_text { return Intl.message( - "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", + 'Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.', name: 'buses_text', desc: '', args: [], @@ -214,6 +217,36 @@ class S { ); } + /// `Change` + String get change { + return Intl.message( + 'Change', + name: 'change', + desc: '', + args: [], + ); + } + + /// `Do you want to change the password?` + String get change_prompt { + return Intl.message( + 'Do you want to change the password?', + name: 'change_prompt', + desc: '', + args: [], + ); + } + + /// `Classes` + String get course_class { + return Intl.message( + 'Classes', + name: 'course_class', + desc: '', + args: [], + ); + } + /// `Class Registration` String get class_registration { return Intl.message( @@ -314,6 +347,16 @@ class S { ); } + /// `Info` + String get course_info { + return Intl.message( + 'Info', + name: 'course_info', + desc: '', + args: [], + ); + } + /// `Current state: ` String get current_state { return Intl.message( @@ -334,6 +377,16 @@ class S { ); } + /// `Decrement 1,00€` + String get decrement { + return Intl.message( + 'Decrement 1,00€', + name: 'decrement', + desc: '', + args: [], + ); + } + /// `Description` String get description { return Intl.message( @@ -357,7 +410,7 @@ class S { /// `D. Beatriz's stationery store` String get dona_bia { return Intl.message( - "D. Beatriz's stationery store", + 'D. Beatriz\'s stationery store', name: 'dona_bia', desc: '', args: [], @@ -424,6 +477,16 @@ class S { ); } + /// `Your password has expired` + String get expired_password { + return Intl.message( + 'Your password has expired', + name: 'expired_password', + desc: '', + args: [], + ); + } + /// `Login failed` String get failed_login { return Intl.message( @@ -494,6 +557,16 @@ class S { ); } + /// `Generate reference` + String get generate_reference { + return Intl.message( + 'Generate reference', + name: 'generate_reference', + desc: '', + args: [], + ); + } + /// `General Registration` String get geral_registration { return Intl.message( @@ -514,6 +587,16 @@ class S { ); } + /// `Increment 1,00€` + String get increment { + return Intl.message( + 'Increment 1,00€', + name: 'increment', + desc: '', + args: [], + ); + } + /// `Stay signed in` String get keep_login { return Intl.message( @@ -597,6 +680,16 @@ class S { ); } + /// `Minimum value: 1,00 €` + String get min_value_reference { + return Intl.message( + 'Minimum value: 1,00 €', + name: 'min_value_reference', + desc: '', + args: [], + ); + } + /// `Multimedia center` String get multimedia_center { return Intl.message( @@ -645,7 +738,7 @@ class S { /// `Don't miss any bus!` String get no_bus { return Intl.message( - "Don't miss any bus!", + 'Don\'t miss any bus!', name: 'no_bus', desc: '', args: [], @@ -662,6 +755,16 @@ class S { ); } + /// `There are no classes to display` + String get no_class { + return Intl.message( + 'There are no classes to display', + name: 'no_class', + desc: '', + args: [], + ); + } + /// `No classes to present` String get no_classes { return Intl.message( @@ -675,7 +778,7 @@ class S { /// `You don't have classes on` String get no_classes_on { return Intl.message( - "You don't have classes on", + 'You don\'t have classes on', name: 'no_classes_on', desc: '', args: [], @@ -742,6 +845,26 @@ class S { ); } + /// `No favorite restaurants` + String get no_favorite_restaurants { + return Intl.message( + 'No favorite restaurants', + name: 'no_favorite_restaurants', + desc: '', + args: [], + ); + } + + /// `There is no information to display` + String get no_info { + return Intl.message( + 'There is no information to display', + name: 'no_info', + desc: '', + args: [], + ); + } + /// `There is no information available about meals` String get no_menu_info { return Intl.message( @@ -832,6 +955,16 @@ class S { ); } + /// `For security reasons, passwords must be changed periodically.` + String get pass_change_request { + return Intl.message( + 'For security reasons, passwords must be changed periodically.', + name: 'pass_change_request', + desc: '', + args: [], + ); + } + /// `password` String get password { return Intl.message( @@ -892,6 +1025,26 @@ class S { ); } + /// `The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account` + String get reference_sigarra_help { + return Intl.message( + 'The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account', + name: 'reference_sigarra_help', + desc: '', + args: [], + ); + } + + /// `Reference created successfully!` + String get reference_success { + return Intl.message( + 'Reference created successfully!', + name: 'reference_success', + desc: '', + args: [], + ); + } + /// `Delete` String get remove { return Intl.message( @@ -952,6 +1105,16 @@ class S { ); } + /// `Some error!` + String get some_error { + return Intl.message( + 'Some error!', + name: 'some_error', + desc: '', + args: [], + ); + } + /// `STCP - Upcoming Trips` String get stcp_stops { return Intl.message( @@ -1098,4 +1261,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} +} \ No newline at end of file diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 5dc250b90..d96cf6deb 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -6,6 +6,8 @@ "@account_card_title": {}, "add": "Add", "@add": {}, + "add_quota": "Add quota", + "@add_quota": {}, "add_widget": "Add widget", "@add_widget": {}, "agree_terms": "By entering you confirm that you agree with these Terms and Conditions", @@ -32,6 +34,12 @@ "@bus_information": {}, "cancel": "Cancel", "@cancel": {}, + "change": "Change", + "@change": {}, + "change_prompt": "Do you want to change the password?", + "@change_prompt": {}, + "course_class": "Classes", + "@course_class": {}, "class_registration": "Class Registration", "@class_registration": {}, "college": "College: ", @@ -52,10 +60,14 @@ "@copy_center": {}, "copy_center_building": "Floor -1 of building B | AEFEUP building", "@copy_center_building": {}, + "course_info": "Info", + "@course_info": {}, "current_state": "Current state: ", "@current_state": {}, "current_year": "Current academic year: ", "@current_year": {}, + "decrement": "Decrement 1,00€", + "@decrement": {}, "description": "Description", "@description": {}, "desired_email": "Email where you want to be contacted", @@ -74,6 +86,8 @@ "@empty_text": {}, "exams_filter": "Exam Filter Settings", "@exams_filter": {}, + "expired_password": "Your password has expired", + "@expired_password": {}, "failed_login": "Login failed", "@failed_login": {}, "fee_date": "Deadline for next fee:", @@ -88,10 +102,14 @@ "@floors": {}, "forgot_password": "Forgot password?", "@forgot_password": {}, + "generate_reference": "Generate reference", + "@generate_reference": {}, "geral_registration": "General Registration", "@geral_registration": {}, "improvement_registration": "Enrollment for Improvement", "@improvement_registration": {}, + "increment": "Increment 1,00€", + "@increment": {}, "keep_login": "Stay signed in", "@keep_login": {}, "last_refresh_time": "last refresh at {time}", @@ -116,6 +134,8 @@ "@logout": {}, "menus": "Menus", "@menus": {}, + "min_value_reference": "Minimum value: 1,00 €", + "@min_value_reference": {}, "multimedia_center": "Multimedia center", "@multimedia_center": {}, "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}", @@ -126,6 +146,8 @@ "@no_bus": {}, "no_bus_stops": "No configured stops", "@no_bus_stops": {}, + "no_class": "There are no classes to display", + "@no_class": {}, "no_classes": "No classes to present", "@no_classes": {}, "no_classes_on": "You don't have classes on", @@ -142,6 +164,10 @@ "@no_exams": {}, "no_exams_label": "Looks like you are on vacation!", "@no_exams_label": {}, + "no_favorite_restaurants": "No favorite restaurants", + "@no_favorite_restaurants": {}, + "no_info": "There is no information to display", + "@no_info": {}, "no_menu_info": "There is no information available about meals", "@no_menu_info": {}, "no_menus": "There are no meals available", @@ -160,6 +186,8 @@ "@occurrence_type": {}, "other_links": "Other links", "@other_links": {}, + "pass_change_request": "For security reasons, passwords must be changed periodically.", + "@pass_change_request": {}, "password": "password", "@password": {}, "pendent_references": "Pending references", @@ -172,6 +200,10 @@ "@print": {}, "problem_id": "Brief identification of the problem", "@problem_id": {}, + "reference_sigarra_help": "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account", + "@reference_sigarra_help": {}, + "reference_success": "Reference created successfully!", + "@reference_success": {}, "remove": "Delete", "@remove": {}, "room": "Room", @@ -184,6 +216,8 @@ "@send": {}, "sent_error": "An error occurred in sending", "@sent_error": {}, + "some_error": "Some error!", + "@some_error": {}, "stcp_stops": "STCP - Upcoming Trips", "@stcp_stops": {}, "student_number": "student number", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index fcb473fc8..e25bfbea9 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -6,6 +6,8 @@ "@account_card_title": {}, "add": "Adicionar", "@add": {}, + "add_quota": "Adicionar quota", + "@add_quota": {}, "add_widget": "Adicionar widget", "@add_widget": {}, "agree_terms": "Ao entrares confirmas que concordas com estes Termos e Condições", @@ -32,6 +34,12 @@ "@bus_information": {}, "cancel": "Cancelar\n", "@cancel": {}, + "change": "Alterar", + "@change": {}, + "change_prompt": "Deseja alterar a palavra-passe?", + "@change_prompt": {}, + "course_class": "Turmas", + "@course_class": {}, "class_registration": "Inscrição de Turmas", "@class_registration": {}, "college": "Faculdade: ", @@ -52,10 +60,14 @@ "@copy_center": {}, "copy_center_building": "Piso -1 do edifício B | Edifício da AEFEUP", "@copy_center_building": {}, + "course_info": "Ficha", + "@course_info": {}, "current_state": "Estado atual: ", "@current_state": {}, "current_year": "Ano curricular atual: ", "@current_year": {}, + "decrement": "Decrementar 1,00€", + "@decrement": {}, "description": "Descrição", "@description": {}, "desired_email": "Email em que desejas ser contactado", @@ -74,6 +86,8 @@ "@empty_text": {}, "exams_filter": "Definições Filtro de Exames", "@exams_filter": {}, + "expired_password": "A tua palavra-passe expirou", + "@expired_password": {}, "failed_login": "O login falhou", "@failed_login": {}, "fee_date": "Data limite próxima prestação:", @@ -88,10 +102,14 @@ "@floors": {}, "forgot_password": "Esqueceu a palavra-passe?", "@forgot_password": {}, + "generate_reference": "Gerar referência", + "@generate_reference": {}, "geral_registration": "Inscrição Geral", "@geral_registration": {}, "improvement_registration": "Inscrição para Melhoria", "@improvement_registration": {}, + "increment": "Incrementar 1,00€", + "@increment": {}, "keep_login": "Manter sessão iniciada", "@keep_login": {}, "last_refresh_time": "última atualização às {time}", @@ -116,6 +134,8 @@ "@logout": {}, "menus": "Ementas", "@menus": {}, + "min_value_reference": "Valor mínimo: 1,00 €", + "@min_value_reference": {}, "multimedia_center": "Centro de multimédia", "@multimedia_center": {}, "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} sobre{Sobre} bugs{Bugs e Sugestões} other{Outros}}", @@ -126,6 +146,8 @@ "@no_bus": {}, "no_bus_stops": "Não existe nenhuma paragem configurada", "@no_bus_stops": {}, + "no_class": "Não existem turmas para apresentar", + "@no_class": {}, "no_classes": "Não existem aulas para apresentar", "@no_classes": {}, "no_classes_on": "Não possui aulas à", @@ -142,6 +164,10 @@ "@no_exams": {}, "no_exams_label": "Parece que estás de férias!", "@no_exams_label": {}, + "no_favorite_restaurants": "Sem restaurantes favoritos", + "@no_favorite_restaurants": {}, + "no_info": "Não existem informações para apresentar", + "@no_info": {}, "no_menu_info": "Não há informação disponível sobre refeições", "@no_menu_info": {}, "no_menus": "Não há refeições disponíveis", @@ -160,6 +186,8 @@ "@occurrence_type": {}, "other_links": "Outros links", "@other_links": {}, + "pass_change_request": "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", + "@pass_change_request": {}, "password": "palavra-passe", "@password": {}, "pendent_references": "Referências pendentes", @@ -172,6 +200,10 @@ "@print": {}, "problem_id": "Breve identificação do problema", "@problem_id": {}, + "reference_sigarra_help": "Os dados da referência gerada aparecerão no Sigarra, conta corrente.\\nPerfil > Conta Corrente", + "@reference_sigarra_help": {}, + "reference_success": "Referência criada com sucesso!", + "@reference_success": {}, "remove": "Remover", "@remove": {}, "room": "Sala", @@ -184,6 +216,8 @@ "@send": {}, "sent_error": "Ocorreu um erro no envio", "@sent_error": {}, + "some_error": "Algum erro!", + "@some_error": {}, "stcp_stops": "STCP - Próximas Viagens", "@stcp_stops": {}, "student_number": "número de estudante", diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index 67ac88576..0d4c61b8b 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -1,39 +1,6 @@ import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; -enum WeekDays { - monday('Segunda', 'Monday'), - tuesday('Terça', 'Tuesday'), - wednesday('Quarta', 'Wednesday'), - thursday('Quinta', 'Thursday'), - friday('Sexta', 'Friday'), - saturday('Sábado', 'Saturday'), - sunday('Domingo', 'Sunday'); - - const WeekDays(this.dayPT, this.dayEN); - final String dayPT; - final String dayEN; -} - -enum Months { - january('janeiro', 'January'), - february('fevereiro', 'February'), - march('março', 'March'), - april('abril', 'April'), - may('maio', 'May'), - june('junho', 'June'), - july('julho', 'July'), - august('agosto', 'August'), - september('setembro', 'September'), - october('outubro', 'October'), - november('novembro', 'November'), - december('dezembro', 'December'); - - const Months(this.monthPT, this.monthEN); - final String monthPT; - final String monthEN; -} - /// Manages a generic Exam. /// /// The information stored is: @@ -99,19 +66,11 @@ class Exam { String locale = Intl.getCurrentLocale(); String get weekDay { - if (locale == 'pt_PT') { - return WeekDays.values[begin.weekday - 1].dayPT; - } else { - return WeekDays.values[begin.weekday - 1].dayEN; - } + return DateFormat.EEEE(locale).dateSymbols.WEEKDAYS[begin.weekday - 1]; } String get month { - if (locale == 'pt_PT') { - return Months.values[begin.month - 1].monthPT; - } else { - return Months.values[begin.weekday - 1].monthEN; - } + return DateFormat.EEEE(locale).dateSymbols.MONTHS[begin.month - 1]; } String get beginTime => formatTime(begin); diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index c4186d98c..96eccb6c1 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -60,16 +60,17 @@ class BugReportFormState extends State { bool _isConsentGiven = false; void loadBugClassList() { - bugList = []; final locale = Intl.getCurrentLocale(); - bugDescriptions.forEach((int key, Tuple2 tup) { - if (locale == 'pt_PT') { - bugList.add(DropdownMenuItem(value: key, child: Text(tup.item1))); - } else { - bugList.add(DropdownMenuItem(value: key, child: Text(tup.item2))); - } - }); + bugList = bugDescriptions.entries + .map( + (entry) => DropdownMenuItem( + value: entry.key, + child: + Text(locale == 'pt_PT' ? entry.value.item1 : entry.value.item2), + ), + ) + .toList(); } @override @@ -264,7 +265,7 @@ class BugReportFormState extends State { bugDescriptions[_selectedBug], faculties, ).toMap(); - String toastMsg; + var toastMsg = ''; bool status; try { final sentryId = await submitSentryEvent(bugReport); @@ -273,13 +274,11 @@ class BugReportFormState extends State { throw Exception('Network error'); } Logger().i('Successfully submitted bug report.'); - // ignore: use_build_context_synchronously - toastMsg = S.of(context).success; + if (context.mounted) toastMsg = S.of(context).success; status = true; } catch (e) { Logger().e('Error while posting bug report:$e'); - // ignore: use_build_context_synchronously - toastMsg = S.of(context).sent_error; + if (context.mounted) toastMsg = S.of(context).sent_error; status = false; } 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 7c0d61596..ade00b29d 100644 --- a/uni/lib/view/course_unit_info/course_unit_info.dart +++ b/uni/lib/view/course_unit_info/course_unit_info.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/providers/lazy/course_units_info_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; @@ -67,8 +68,11 @@ class CourseUnitDetailPageViewState center: false, name: widget.courseUnit.name, ), - const TabBar( - tabs: [Tab(text: 'Ficha'), Tab(text: 'Turmas')], + TabBar( + tabs: [ + Tab(text: S.of(context).course_info), + Tab(text: S.of(context).course_class) + ], ), Expanded( child: Padding( @@ -90,9 +94,9 @@ class CourseUnitDetailPageViewState return LazyConsumer( builder: (context, courseUnitsInfoProvider) { return RequestDependentWidgetBuilder( - onNullContent: const Center( + onNullContent: Center( child: Text( - 'Não existem informações para apresentar', + S.of(context).no_info, textAlign: TextAlign.center, ), ), @@ -114,9 +118,9 @@ class CourseUnitDetailPageViewState return LazyConsumer( builder: (context, courseUnitsInfoProvider) { return RequestDependentWidgetBuilder( - onNullContent: const Center( + onNullContent: Center( child: Text( - 'Não existem turmas para apresentar', + S.of(context).no_class, textAlign: TextAlign.center, ), ), diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 67d8e583e..77eacada5 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/providers/lazy/restaurant_provider.dart'; @@ -21,7 +22,8 @@ class RestaurantCard extends GenericCard { }) : super.fromEditingInformation(); @override - String getTitle(BuildContext context) => 'Restaurantes'; + String getTitle(BuildContext context) => + S.of(context).nav_title(DrawerItem.navRestaurants.title); @override Future onClick(BuildContext context) => @@ -53,7 +55,7 @@ class RestaurantCard extends GenericCard { padding: const EdgeInsets.only(top: 15, bottom: 10), child: Center( child: Text( - 'Sem restaurantes favoritos', + S.of(context).no_favorite_restaurants, style: Theme.of(context).textTheme.titleMedium, ), ), @@ -63,7 +65,7 @@ class RestaurantCard extends GenericCard { context, '/${DrawerItem.navRestaurants.title}', ), - child: const Text('Adicionar'), + child: Text(S.of(context).add), ) ], ), diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 0663b9d90..600c9498c 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -294,21 +294,20 @@ class LoginPageViewState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('A tua palavra-passe expirou'), + title: Text(S.of(context).expired_password), content: Column( mainAxisSize: MainAxisSize.min, children: [ Text( - 'Por razões de segurança, as palavras-passe têm de ser ' - 'alteradas periodicamente.', + S.of(context).pass_change_request, textAlign: TextAlign.start, style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 20), - const Align( + Align( alignment: Alignment.centerLeft, child: Text( - 'Deseja alterar a palavra-passe?', + S.of(context).change_prompt, textAlign: TextAlign.start, ), ), @@ -316,13 +315,13 @@ class LoginPageViewState extends State { ), actions: [ TextButton( - child: const Text('Cancelar'), + child: Text(S.of(context).cancel), onPressed: () { Navigator.of(context).pop(); }, ), ElevatedButton( - child: const Text('Alterar'), + child: Text(S.of(context).change), onPressed: () async { const url = 'https://self-id.up.pt/password'; if (await canLaunchUrl(Uri.parse(url))) { 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 f2fb513e5..51ddddd4a 100644 --- a/uni/lib/view/profile/widgets/create_print_mb_dialog.dart +++ b/uni/lib/view/profile/widgets/create_print_mb_dialog.dart @@ -2,6 +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/generated/l10n.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; @@ -32,9 +33,7 @@ Future addMoneyDialog(BuildContext context) async { Padding( padding: const EdgeInsets.only(top: 5, bottom: 10), child: Text( - 'Os dados da referência gerada aparecerão no Sigarra, ' - 'conta corrente. \n' - 'Perfil > Conta Corrente', + S.of(context).reference_sigarra_help, textAlign: TextAlign.start, style: Theme.of(context).textTheme.titleSmall, ), @@ -43,7 +42,7 @@ Future addMoneyDialog(BuildContext context) async { children: [ IconButton( icon: const Icon(Icons.indeterminate_check_box), - tooltip: 'Decrementar 1,00€', + tooltip: S.of(context).decrement, onPressed: () { final decreasedValue = valueTextToNumber(controller.text) - 1; @@ -83,7 +82,7 @@ Future addMoneyDialog(BuildContext context) async { ), IconButton( icon: const Icon(Icons.add_box), - tooltip: 'Incrementar 1,00€', + tooltip: S.of(context).increment, onPressed: () { controller.value = TextEditingValue( text: numberToValueText( @@ -98,20 +97,20 @@ Future addMoneyDialog(BuildContext context) async { ), ), title: Text( - 'Adicionar quota', + S.of(context).add_quota, style: Theme.of(context).textTheme.headlineSmall, ), actions: [ TextButton( child: Text( - 'Cancelar', + S.of(context).cancel, style: Theme.of(context).textTheme.bodyMedium, ), onPressed: () => Navigator.pop(context), ), ElevatedButton( onPressed: () => generateReference(context, value), - child: const Text('Gerar referência'), + child: Text(S.of(context).generate_reference), ) ], ); @@ -132,7 +131,7 @@ String numberToValueText(double number) => Future generateReference(BuildContext context, double amount) async { if (amount < 1) { - await ToastMessage.warning(context, 'Valor mínimo: 1,00 €'); + await ToastMessage.warning(context, S.of(context).min_value_reference); return; } @@ -142,8 +141,8 @@ Future generateReference(BuildContext context, double amount) async { if (response.statusCode == 200 && context.mounted) { Navigator.of(context).pop(false); - await ToastMessage.success(context, 'Referência criada com sucesso!'); + await ToastMessage.success(context, S.of(context).reference_success); } else { - await ToastMessage.error(context, 'Algum erro!'); + await ToastMessage.error(context, S.of(context).some_error); } } From 707f75a1676a32600a93173bc044ef5495788e37 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 31 Aug 2023 23:22:12 +0100 Subject: [PATCH 094/199] Login exceptions translation --- uni/ios/Flutter/AppFrameworkInfo.plist | 26 ---- uni/ios/Flutter/Debug.xcconfig | 2 - uni/ios/Flutter/Release.xcconfig | 2 - uni/lib/generated/intl/messages_all.dart | 27 ++-- uni/lib/generated/intl/messages_en.dart | 142 +++++++------------ uni/lib/generated/intl/messages_pt_PT.dart | 8 +- uni/lib/generated/l10n.dart | 41 ++++-- uni/lib/l10n/intl_en.arb | 4 + uni/lib/l10n/intl_pt_PT.arb | 4 + uni/lib/main.dart | 4 +- uni/lib/model/entities/login_exceptions.dart | 7 +- 11 files changed, 120 insertions(+), 147 deletions(-) delete mode 100644 uni/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 uni/ios/Flutter/Debug.xcconfig delete mode 100644 uni/ios/Flutter/Release.xcconfig diff --git a/uni/ios/Flutter/AppFrameworkInfo.plist b/uni/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9625e105d..000000000 --- a/uni/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 11.0 - - diff --git a/uni/ios/Flutter/Debug.xcconfig b/uni/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f3..000000000 --- a/uni/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/uni/ios/Flutter/Release.xcconfig b/uni/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe2..000000000 --- a/uni/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 5c2bef3d1..6b3ebeae5 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -15,13 +15,13 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'package:uni/generated/intl/messages_en.dart' as messages_en; -import 'package:uni/generated/intl/messages_pt_PT.dart' as messages_pt_pt; +import 'messages_en.dart' as messages_en; +import 'messages_pt_PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { - 'en': Future.value, - 'pt_PT': Future.value, + 'en': () => new Future.value(null), + 'pt_PT': () => new Future.value(null), }; MessageLookupByLibrary? _findExact(String localeName) { @@ -37,17 +37,15 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) async { - final availableLocale = Intl.verifiedLocale( - localeName, - (locale) => _deferredLibraries[locale] != null, - onFailure: (_) => null, - ); + var availableLocale = Intl.verifiedLocale( + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { return new Future.value(false); } - final lib = _deferredLibraries[availableLocale]; + var lib = _deferredLibraries[availableLocale]; await (lib == null ? new Future.value(false) : lib()); - initializeInternalMessageLookup(CompositeMessageLookup.new); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); return new Future.value(true); } @@ -61,11 +59,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = Intl.verifiedLocale( - locale, - _messagesExistFor, - onFailure: (_) => null, - ); + var actualLocale = + Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); } diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 6cb2f58f8..9d5c4f6d3 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -19,33 +19,29 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; - static String m0(dynamic time) => "last refresh at ${time}"; + static m0(time) => "last refresh at ${time}"; - static String m1(dynamic time) => Intl.plural( - time as num, - zero: 'Refreshed ${time} minutes ago', - one: 'Refreshed ${time} minute ago', - other: 'Refreshed ${time} minutes ago', - ); + static m1(time) => + "${Intl.plural(time as num, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - static String m2(String title) => Intl.select(title, { - 'horario': 'Schedule', - 'exames': 'Exams', - 'area': 'Personal Area', - 'cadeiras': 'Course Units', - 'autocarros': 'Buses', - 'locais': 'Places', - 'restaurantes': 'Restaurants', - 'calendario': 'Calendar', - 'biblioteca': 'Library', - 'uteis': 'Utils', - 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', - 'other': 'Other', - }); + static m2(title) => "${Intl.select(title, { + 'horario': 'Schedule', + 'exames': 'Exams', + 'area': 'Personal Area', + 'cadeiras': 'Course Units', + 'autocarros': 'Buses', + 'locais': 'Places', + 'restaurantes': 'Restaurants', + 'calendario': 'Calendar', + 'biblioteca': 'Library', + 'uteis': 'Utils', + 'sobre': 'About', + 'bugs': 'Bugs/ Suggestions', + 'other': 'Other', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { + static _notInlinedMessages(_) => { "academic_services": MessageLookupByLibrary.simpleMessage("Academic services"), "account_card_title": @@ -54,36 +50,31 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "By entering you confirm that you agree with these Terms and Conditions", - ), + "By entering you confirm that you agree with these Terms and Conditions"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "All available widgets have already been added to your personal area!", - ), + "All available widgets have already been added to your personal area!"), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( - "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!", - ), + "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!"), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug found, how to reproduce it, etc.", - ), + "Bug found, how to reproduce it, etc."), "bus_error": MessageLookupByLibrary.simpleMessage("Unable to get information"), "bus_information": MessageLookupByLibrary.simpleMessage( - "Select the buses you want information about:", - ), + "Select the buses you want information about:"), "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.", - ), + "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page."), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "change": MessageLookupByLibrary.simpleMessage("Change"), "change_prompt": MessageLookupByLibrary.simpleMessage( - "Do you want to change the password?", - ), + "Do you want to change the password?"), + "check_internet": MessageLookupByLibrary.simpleMessage( + "Check your internet connection"), "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), "college": MessageLookupByLibrary.simpleMessage("College: "), @@ -94,13 +85,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", - ), + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request."), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B | AEFEUP building", - ), + "Floor -1 of building B | AEFEUP building"), "course_class": MessageLookupByLibrary.simpleMessage("Classes"), "course_info": MessageLookupByLibrary.simpleMessage("Info"), "current_state": @@ -110,14 +99,11 @@ class MessageLookup extends MessageLookupByLibrary { "decrement": MessageLookupByLibrary.simpleMessage("Decrement 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Description"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email where you want to be contacted", - ), + "Email where you want to be contacted"), "dona_bia": MessageLookupByLibrary.simpleMessage( - "D. Beatriz\'s stationery store", - ), + "D. Beatriz\'s stationery store"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B (B-142)", - ), + "Floor -1 of building B (B-142)"), "ects": MessageLookupByLibrary.simpleMessage("ECTs performed: "), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), @@ -133,8 +119,7 @@ class MessageLookup extends MessageLookupByLibrary { "fee_notification": MessageLookupByLibrary.simpleMessage("Notify next deadline:"), "first_year_registration": MessageLookupByLibrary.simpleMessage( - "Year of first registration: ", - ), + "Year of first registration: "), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), "forgot_password": @@ -146,14 +131,15 @@ class MessageLookup extends MessageLookupByLibrary { "improvement_registration": MessageLookupByLibrary.simpleMessage("Enrollment for Improvement"), "increment": MessageLookupByLibrary.simpleMessage("Increment 1,00€"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Invalid credentials"), "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), "last_refresh_time": m0, "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Loading Terms and Conditions...", - ), + "Loading Terms and Conditions..."), "login": MessageLookupByLibrary.simpleMessage("Login"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), @@ -167,55 +153,43 @@ class MessageLookup extends MessageLookupByLibrary { "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), "no_class": MessageLookupByLibrary.simpleMessage( - "There are no classes to display", - ), + "There are no classes to display"), "no_classes": MessageLookupByLibrary.simpleMessage("No classes to present"), "no_classes_on": MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), "no_college": MessageLookupByLibrary.simpleMessage("no college"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "No course units in the selected period", - ), + "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( - "There is no data to show at this time", - ), + "There is no data to show at this time"), "no_date": MessageLookupByLibrary.simpleMessage("No date"), "no_exams": MessageLookupByLibrary.simpleMessage( - "You have no exams scheduled\n", - ), + "You have no exams scheduled\n"), "no_exams_label": MessageLookupByLibrary.simpleMessage( - "Looks like you are on vacation!", - ), + "Looks like you are on vacation!"), "no_favorite_restaurants": MessageLookupByLibrary.simpleMessage("No favorite restaurants"), "no_info": MessageLookupByLibrary.simpleMessage( - "There is no information to display", - ), + "There is no information to display"), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "There is no information available about meals", - ), + "There is no information available about meals"), "no_menus": MessageLookupByLibrary.simpleMessage( - "There are no meals available", - ), + "There are no meals available"), "no_name_course": MessageLookupByLibrary.simpleMessage("Unnamed course"), "no_references": MessageLookupByLibrary.simpleMessage( - "There are no references to pay", - ), + "There are no references to pay"), "no_results": MessageLookupByLibrary.simpleMessage("No match"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "There are no course units to display", - ), + "There are no course units to display"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "There are no exams to present", - ), + "There are no exams to present"), "occurrence_type": MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "For security reasons, passwords must be changed periodically.", - ), + "For security reasons, passwords must be changed periodically."), "password": MessageLookupByLibrary.simpleMessage("password"), "pendent_references": MessageLookupByLibrary.simpleMessage("Pending references"), @@ -225,14 +199,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Press again to exit"), "print": MessageLookupByLibrary.simpleMessage("Print"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Brief identification of the problem", - ), + "Brief identification of the problem"), "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account", - ), + "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account"), "reference_success": MessageLookupByLibrary.simpleMessage( - "Reference created successfully!", - ), + "Reference created successfully!"), "remove": MessageLookupByLibrary.simpleMessage("Delete"), "room": MessageLookupByLibrary.simpleMessage("Room"), "school_calendar": @@ -240,8 +211,7 @@ class MessageLookup extends MessageLookupByLibrary { "semester": MessageLookupByLibrary.simpleMessage("Semester"), "send": MessageLookupByLibrary.simpleMessage("Send"), "sent_error": MessageLookupByLibrary.simpleMessage( - "An error occurred in sending", - ), + "An error occurred in sending"), "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), @@ -251,8 +221,7 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Telephone assistance"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Face-to-face and telephone assistance", - ), + "Face-to-face and telephone assistance"), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), "terms": MessageLookupByLibrary.simpleMessage("Terms and Conditions"), "title": MessageLookupByLibrary.simpleMessage("Title"), @@ -260,8 +229,7 @@ class MessageLookup extends MessageLookupByLibrary { "valid_email": MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:", - ), + "Choose a widget to add to your personal area:"), "year": MessageLookupByLibrary.simpleMessage("Year") }; } diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 297fff62c..d47d3f4d9 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -24,7 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static m1(time) => "${Intl.plural(time as num, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static m2(String title) => "${Intl.select(title, { + static m2(title) => "${Intl.select(title, { 'horario': 'Horário', 'exames': 'Exames', 'area': 'Área Pessoal', @@ -41,7 +41,7 @@ class MessageLookup extends MessageLookupByLibrary { })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static Map _notInlinedMessages(_) => { + static _notInlinedMessages(_) => { "academic_services": MessageLookupByLibrary.simpleMessage("Serviços académicos"), "account_card_title": @@ -73,6 +73,8 @@ class MessageLookup extends MessageLookupByLibrary { "change": MessageLookupByLibrary.simpleMessage("Alterar"), "change_prompt": MessageLookupByLibrary.simpleMessage( "Deseja alterar a palavra-passe?"), + "check_internet": MessageLookupByLibrary.simpleMessage( + "Verifica a tua ligação à internet"), "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), @@ -128,6 +130,8 @@ class MessageLookup extends MessageLookupByLibrary { "improvement_registration": MessageLookupByLibrary.simpleMessage("Inscrição para Melhoria"), "increment": MessageLookupByLibrary.simpleMessage("Incrementar 1,00€"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão iniciada"), "last_refresh_time": m0, diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index a0ac95cfd..7b45c0e86 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -18,28 +18,31 @@ class S { static S? _current; static S get current { - assert(_current != null, 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); + assert(_current != null, + 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); return _current!; } - static const AppLocalizationDelegate delegate = - AppLocalizationDelegate(); + static const AppLocalizationDelegate delegate = AppLocalizationDelegate(); static Future load(Locale locale) { - final name = (locale.countryCode?.isEmpty ?? false) ? locale.languageCode : locale.toString(); - final localeName = Intl.canonicalizedLocale(name); + final name = (locale.countryCode?.isEmpty ?? false) + ? locale.languageCode + : locale.toString(); + final localeName = Intl.canonicalizedLocale(name); return initializeMessages(localeName).then((_) { Intl.defaultLocale = localeName; final instance = S(); S._current = instance; - + return instance; }); - } + } static S of(BuildContext context) { final instance = S.maybeOf(context); - assert(instance != null, 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); + assert(instance != null, + 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); return instance!; } @@ -237,6 +240,16 @@ class S { ); } + /// `Check your internet connection` + String get check_internet { + return Intl.message( + 'Check your internet connection', + name: 'check_internet', + desc: '', + args: [], + ); + } + /// `Classes` String get course_class { return Intl.message( @@ -597,6 +610,16 @@ class S { ); } + /// `Invalid credentials` + String get invalid_credentials { + return Intl.message( + 'Invalid credentials', + name: 'invalid_credentials', + desc: '', + args: [], + ); + } + /// `Stay signed in` String get keep_login { return Intl.message( @@ -1261,4 +1284,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} \ No newline at end of file +} diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index d96cf6deb..d63ce3056 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -38,6 +38,8 @@ "@change": {}, "change_prompt": "Do you want to change the password?", "@change_prompt": {}, + "check_internet": "Check your internet connection", + "@check_internet": {}, "course_class": "Classes", "@course_class": {}, "class_registration": "Class Registration", @@ -110,6 +112,8 @@ "@improvement_registration": {}, "increment": "Increment 1,00€", "@increment": {}, + "invalid_credentials": "Invalid credentials", + "@invalid_credentials": {}, "keep_login": "Stay signed in", "@keep_login": {}, "last_refresh_time": "last refresh at {time}", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index e25bfbea9..eaf6e2829 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -38,6 +38,8 @@ "@change": {}, "change_prompt": "Deseja alterar a palavra-passe?", "@change_prompt": {}, + "check_internet": "Verifica a tua ligação à internet", + "@check_internet": {}, "course_class": "Turmas", "@course_class": {}, "class_registration": "Inscrição de Turmas", @@ -110,6 +112,8 @@ "@improvement_registration": {}, "increment": "Incrementar 1,00€", "@increment": {}, + "invalid_credentials": "Credenciais inválidas", + "@invalid_credentials": {}, "keep_login": "Manter sessão iniciada", "@keep_login": {}, "last_refresh_time": "última atualização às {time}", diff --git a/uni/lib/main.dart b/uni/lib/main.dart index c576d4b55..66d95888c 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -170,6 +170,8 @@ class MyApp extends StatefulWidget { State createState() => MyAppState(); } +final GlobalKey navigatorKey = GlobalKey(); + /// Manages the app depending on its current state class MyAppState extends State { @override @@ -192,7 +194,7 @@ class MyAppState extends State { ], supportedLocales: S.delegate.supportedLocales, initialRoute: widget.initialRoute, - navigatorKey: NavigationService.navigatorKey, + navigatorKey: navigatorKey, onGenerateRoute: (RouteSettings settings) { final transitions = { '/${DrawerItem.navPersonalArea.title}': diff --git a/uni/lib/model/entities/login_exceptions.dart b/uni/lib/model/entities/login_exceptions.dart index c170f6405..74ab67a01 100644 --- a/uni/lib/model/entities/login_exceptions.dart +++ b/uni/lib/model/entities/login_exceptions.dart @@ -1,13 +1,16 @@ +import 'package:uni/generated/l10n.dart'; +import 'package:uni/main.dart'; + class ExpiredCredentialsException implements Exception { ExpiredCredentialsException(); } class InternetStatusException implements Exception { InternetStatusException(); - String message = 'Verifica a tua ligação à internet'; + String message = S.of(navigatorKey.currentContext!).check_internet; } class WrongCredentialsException implements Exception { WrongCredentialsException(); - String message = 'Credenciais inválidas'; + String message = S.of(navigatorKey.currentContext!).invalid_credentials; } From 5b16bd0c9b596e0d5abf05df64d3a3db2135a735 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 31 Aug 2023 23:25:16 +0100 Subject: [PATCH 095/199] Commit error fix --- uni/ios/Flutter/AppFrameworkInfo.plist | 26 ++++++++++++++++++++++++++ uni/ios/Flutter/Debug.xcconfig | 2 ++ uni/ios/Flutter/Release.xcconfig | 2 ++ 3 files changed, 30 insertions(+) create mode 100644 uni/ios/Flutter/AppFrameworkInfo.plist create mode 100644 uni/ios/Flutter/Debug.xcconfig create mode 100644 uni/ios/Flutter/Release.xcconfig diff --git a/uni/ios/Flutter/AppFrameworkInfo.plist b/uni/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..9625e105d --- /dev/null +++ b/uni/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/uni/ios/Flutter/Debug.xcconfig b/uni/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..ec97fc6f3 --- /dev/null +++ b/uni/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/uni/ios/Flutter/Release.xcconfig b/uni/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..c4855bfe2 --- /dev/null +++ b/uni/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" From adb8b65829f28b43176ca78910cb9ca50fbb3ce0 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 19 Aug 2023 15:14:05 +0100 Subject: [PATCH 096/199] Update target sdk version --- uni/android/app/build.gradle | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/uni/android/app/build.gradle b/uni/android/app/build.gradle index e1abc5e1c..8fe00a408 100644 --- a/uni/android/app/build.gradle +++ b/uni/android/app/build.gradle @@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion 33 // default is flutter.compileSdkVersion ndkVersion flutter.ndkVersion compileOptions { @@ -50,10 +50,8 @@ android { defaultConfig { applicationId "pt.up.fe.ni.uni" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion 21 // default is flutter.minSdkVersion + targetSdkVersion 33 // default is flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } From d2ed63a706f8f265db2fe96f68c1cf06825b92d3 Mon Sep 17 00:00:00 2001 From: niaefeup-admin Date: Fri, 1 Sep 2023 11:34:56 +0000 Subject: [PATCH 097/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 862505918..7ffae3959 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.0+118 \ No newline at end of file +1.6.0+119 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index b4e98accf..fe92515d3 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.0+118 +version: 1.6.0+119 environment: sdk: ">=2.17.1 <3.0.0" From 9172bc69eee534ae6b2e0a4e7986c97eabc32e2c Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 3 Sep 2023 21:31:12 +0100 Subject: [PATCH 098/199] Code cleaning --- uni/analysis_options.yaml | 2 +- uni/lib/generated/intl/messages_en.dart | 4 ++-- uni/lib/generated/intl/messages_pt_PT.dart | 4 ++-- uni/lib/view/locale_notifier.dart | 16 +++++++--------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index 6df16fd8f..f66e9c4bf 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -4,7 +4,7 @@ analyzer: # Exclude auto-generated files from dart analysis exclude: - "**.g.dart" - - "/lib/generated/**.dart" + - "uni/lib/generated/**.dart" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 9d5c4f6d3..7ca67d707 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -24,7 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static m1(time) => "${Intl.plural(time as num, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - static m2(title) => "${Intl.select(title, { + static m2(String title) => "${Intl.select(title, { 'horario': 'Schedule', 'exames': 'Exams', 'area': 'Personal Area', @@ -41,7 +41,7 @@ class MessageLookup extends MessageLookupByLibrary { })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { + static Map _notInlinedMessages(_) => { "academic_services": MessageLookupByLibrary.simpleMessage("Academic services"), "account_card_title": diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index d47d3f4d9..38e5b71e0 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -24,7 +24,7 @@ class MessageLookup extends MessageLookupByLibrary { static m1(time) => "${Intl.plural(time as num, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static m2(title) => "${Intl.select(title, { + static m2(String title) => "${Intl.select(title, { 'horario': 'Horário', 'exames': 'Exames', 'area': 'Área Pessoal', @@ -41,7 +41,7 @@ class MessageLookup extends MessageLookupByLibrary { })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { + static Map _notInlinedMessages(_) => { "academic_services": MessageLookupByLibrary.simpleMessage("Serviços académicos"), "account_card_title": diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart index 109c9c4d2..6e8df082e 100644 --- a/uni/lib/view/locale_notifier.dart +++ b/uni/lib/view/locale_notifier.dart @@ -24,15 +24,13 @@ class LocaleNotifier with ChangeNotifier { } List getWeekdaysWithLocale() { - final weekdays = []; - for (final weekday - in DateFormat.EEEE(_locale.languageCode).dateSymbols.WEEKDAYS) { - weekdays.add(weekday[0].toUpperCase() + weekday.substring(1)); - } - weekdays.removeAt(0); - weekdays[5] == 'Saturday' - ? weekdays.add('Sunday') - : weekdays.add('Domingo'); + final weekdays = DateFormat.EEEE(_locale.languageCode) + .dateSymbols + .WEEKDAYS + .skip(1) + .map((weekday) => weekday[0].toUpperCase() + weekday.substring(1)) + .toList() + ..add(_locale.languageCode == 'en' ? 'Sunday' : 'Domingo'); return weekdays; } } From 38b958efbd3fc2ac863154d3fc3df0f21341960f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 3 Sep 2023 21:40:05 +0100 Subject: [PATCH 099/199] Lint fixing --- uni/analysis_options.yaml | 1 - uni/lib/generated/intl/messages_all.dart | 22 +-- uni/lib/generated/intl/messages_en.dart | 145 +++++++++++------- uni/lib/generated/intl/messages_pt_PT.dart | 162 +++++++++++++-------- uni/lib/generated/l10n.dart | 22 +-- 5 files changed, 219 insertions(+), 133 deletions(-) diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index f66e9c4bf..92d895f92 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -4,7 +4,6 @@ analyzer: # Exclude auto-generated files from dart analysis exclude: - "**.g.dart" - - "uni/lib/generated/**.dart" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 6b3ebeae5..de96ef7c8 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -15,13 +15,13 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'messages_en.dart' as messages_en; -import 'messages_pt_PT.dart' as messages_pt_pt; +import 'package:uni/generated/intl/messages_en.dart' as messages_en; +import 'package:uni/generated/intl/messages_pt_PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { - 'en': () => new Future.value(null), - 'pt_PT': () => new Future.value(null), + 'en': Future.value, + 'pt_PT': Future.value, }; MessageLookupByLibrary? _findExact(String localeName) { @@ -37,15 +37,17 @@ MessageLookupByLibrary? _findExact(String localeName) { /// User programs should call this before using [localeName] for messages. Future initializeMessages(String localeName) async { - var availableLocale = Intl.verifiedLocale( - localeName, (locale) => _deferredLibraries[locale] != null, - onFailure: (_) => null); + final availableLocale = Intl.verifiedLocale( + localeName, + (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null, + ); if (availableLocale == null) { return new Future.value(false); } - var lib = _deferredLibraries[availableLocale]; + final lib = _deferredLibraries[availableLocale]; await (lib == null ? new Future.value(false) : lib()); - initializeInternalMessageLookup(() => new CompositeMessageLookup()); + initializeInternalMessageLookup(CompositeMessageLookup.new); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); return new Future.value(true); } @@ -59,7 +61,7 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var actualLocale = + final actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 7ca67d707..908784164 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -19,26 +19,30 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; - static m0(time) => "last refresh at ${time}"; + static String m0(dynamic time) => "last refresh at ${time}"; - static m1(time) => - "${Intl.plural(time as num, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + static String m1(dynamic time) => Intl.plural( + time as num, + zero: 'Refreshed ${time} minutes ago', + one: 'Refreshed ${time} minute ago', + other: 'Refreshed ${time} minutes ago', + ); - static m2(String title) => "${Intl.select(title, { - 'horario': 'Schedule', - 'exames': 'Exams', - 'area': 'Personal Area', - 'cadeiras': 'Course Units', - 'autocarros': 'Buses', - 'locais': 'Places', - 'restaurantes': 'Restaurants', - 'calendario': 'Calendar', - 'biblioteca': 'Library', - 'uteis': 'Utils', - 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', - 'other': 'Other', - })}"; + static String m2(String title) => Intl.select(title, { + 'horario': 'Schedule', + 'exames': 'Exams', + 'area': 'Personal Area', + 'cadeiras': 'Course Units', + 'autocarros': 'Buses', + 'locais': 'Places', + 'restaurantes': 'Restaurants', + 'calendario': 'Calendar', + 'biblioteca': 'Library', + 'uteis': 'Utils', + 'sobre': 'About', + 'bugs': 'Bugs/ Suggestions', + 'other': 'Other', + }); final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -50,31 +54,39 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "By entering you confirm that you agree with these Terms and Conditions"), + "By entering you confirm that you agree with these Terms and Conditions", + ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "All available widgets have already been added to your personal area!"), + "All available widgets have already been added to your personal area!", + ), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( - "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!"), + r"Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!", + ), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug found, how to reproduce it, etc."), + "Bug found, how to reproduce it, etc.", + ), "bus_error": MessageLookupByLibrary.simpleMessage("Unable to get information"), "bus_information": MessageLookupByLibrary.simpleMessage( - "Select the buses you want information about:"), + "Select the buses you want information about:", + ), "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page."), + "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", + ), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "change": MessageLookupByLibrary.simpleMessage("Change"), "change_prompt": MessageLookupByLibrary.simpleMessage( - "Do you want to change the password?"), + "Do you want to change the password?", + ), "check_internet": MessageLookupByLibrary.simpleMessage( - "Check your internet connection"), + "Check your internet connection", + ), "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), "college": MessageLookupByLibrary.simpleMessage("College: "), @@ -85,11 +97,13 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request."), + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", + ), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B | AEFEUP building"), + "Floor -1 of building B | AEFEUP building", + ), "course_class": MessageLookupByLibrary.simpleMessage("Classes"), "course_info": MessageLookupByLibrary.simpleMessage("Info"), "current_state": @@ -99,11 +113,14 @@ class MessageLookup extends MessageLookupByLibrary { "decrement": MessageLookupByLibrary.simpleMessage("Decrement 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Description"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email where you want to be contacted"), + "Email where you want to be contacted", + ), "dona_bia": MessageLookupByLibrary.simpleMessage( - "D. Beatriz\'s stationery store"), + "D. Beatriz's stationery store", + ), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B (B-142)"), + "Floor -1 of building B (B-142)", + ), "ects": MessageLookupByLibrary.simpleMessage("ECTs performed: "), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), @@ -119,7 +136,8 @@ class MessageLookup extends MessageLookupByLibrary { "fee_notification": MessageLookupByLibrary.simpleMessage("Notify next deadline:"), "first_year_registration": MessageLookupByLibrary.simpleMessage( - "Year of first registration: "), + "Year of first registration: ", + ), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), "forgot_password": @@ -139,7 +157,8 @@ class MessageLookup extends MessageLookupByLibrary { "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Loading Terms and Conditions..."), + "Loading Terms and Conditions...", + ), "login": MessageLookupByLibrary.simpleMessage("Login"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), @@ -149,47 +168,59 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("News"), - "no_bus": MessageLookupByLibrary.simpleMessage("Don\'t miss any bus!"), + "no_bus": MessageLookupByLibrary.simpleMessage("Don't miss any bus!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), "no_class": MessageLookupByLibrary.simpleMessage( - "There are no classes to display"), + "There are no classes to display", + ), "no_classes": MessageLookupByLibrary.simpleMessage("No classes to present"), "no_classes_on": - MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), + MessageLookupByLibrary.simpleMessage("You don't have classes on"), "no_college": MessageLookupByLibrary.simpleMessage("no college"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "No course units in the selected period"), + "No course units in the selected period", + ), "no_data": MessageLookupByLibrary.simpleMessage( - "There is no data to show at this time"), + "There is no data to show at this time", + ), "no_date": MessageLookupByLibrary.simpleMessage("No date"), "no_exams": MessageLookupByLibrary.simpleMessage( - "You have no exams scheduled\n"), + "You have no exams scheduled\n", + ), "no_exams_label": MessageLookupByLibrary.simpleMessage( - "Looks like you are on vacation!"), + "Looks like you are on vacation!", + ), "no_favorite_restaurants": MessageLookupByLibrary.simpleMessage("No favorite restaurants"), "no_info": MessageLookupByLibrary.simpleMessage( - "There is no information to display"), + "There is no information to display", + ), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "There is no information available about meals"), + "There is no information available about meals", + ), "no_menus": MessageLookupByLibrary.simpleMessage( - "There are no meals available"), + "There are no meals available", + ), "no_name_course": MessageLookupByLibrary.simpleMessage("Unnamed course"), "no_references": MessageLookupByLibrary.simpleMessage( - "There are no references to pay"), + "There are no references to pay", + ), "no_results": MessageLookupByLibrary.simpleMessage("No match"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "There are no course units to display"), + "There are no course units to display", + ), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "There are no exams to present"), + "There are no exams to present", + ), "occurrence_type": MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "For security reasons, passwords must be changed periodically."), + "For security reasons, passwords must be changed periodically.", + ), "password": MessageLookupByLibrary.simpleMessage("password"), "pendent_references": MessageLookupByLibrary.simpleMessage("Pending references"), @@ -199,11 +230,14 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Press again to exit"), "print": MessageLookupByLibrary.simpleMessage("Print"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Brief identification of the problem"), + "Brief identification of the problem", + ), "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account"), + r"The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account", + ), "reference_success": MessageLookupByLibrary.simpleMessage( - "Reference created successfully!"), + "Reference created successfully!", + ), "remove": MessageLookupByLibrary.simpleMessage("Delete"), "room": MessageLookupByLibrary.simpleMessage("Room"), "school_calendar": @@ -211,7 +245,8 @@ class MessageLookup extends MessageLookupByLibrary { "semester": MessageLookupByLibrary.simpleMessage("Semester"), "send": MessageLookupByLibrary.simpleMessage("Send"), "sent_error": MessageLookupByLibrary.simpleMessage( - "An error occurred in sending"), + "An error occurred in sending", + ), "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), @@ -221,7 +256,8 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Telephone assistance"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Face-to-face and telephone assistance"), + "Face-to-face and telephone assistance", + ), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), "terms": MessageLookupByLibrary.simpleMessage("Terms and Conditions"), "title": MessageLookupByLibrary.simpleMessage("Title"), @@ -229,7 +265,8 @@ class MessageLookup extends MessageLookupByLibrary { "valid_email": MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:"), + "Choose a widget to add to your personal area:", + ), "year": MessageLookupByLibrary.simpleMessage("Year") }; } diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 38e5b71e0..8a36505af 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -19,26 +19,30 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt_PT'; - static m0(time) => "última atualização às ${time}"; + static String m0(dynamic time) => "última atualização às ${time}"; - static m1(time) => - "${Intl.plural(time as num, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + static String m1(dynamic time) => Intl.plural( + time as num, + zero: 'Atualizado há ${time} minutos', + one: 'Atualizado há ${time} minuto', + other: 'Atualizado há ${time} minutos', + ); - static m2(String title) => "${Intl.select(title, { - 'horario': 'Horário', - 'exames': 'Exames', - 'area': 'Área Pessoal', - 'cadeiras': 'Cadeiras', - 'autocarros': 'Autocarros', - 'locais': 'Locais', - 'restaurantes': 'Restaurantes', - 'calendario': 'Calendário', - 'biblioteca': 'Biblioteca', - 'uteis': 'Úteis', - 'sobre': 'Sobre', - 'bugs': 'Bugs e Sugestões', - 'other': 'Outros', - })}"; + static String m2(String title) => Intl.select(title, { + 'horario': 'Horário', + 'exames': 'Exames', + 'area': 'Área Pessoal', + 'cadeiras': 'Cadeiras', + 'autocarros': 'Autocarros', + 'locais': 'Locais', + 'restaurantes': 'Restaurantes', + 'calendario': 'Calendário', + 'biblioteca': 'Biblioteca', + 'uteis': 'Úteis', + 'sobre': 'Sobre', + 'bugs': 'Bugs e Sugestões', + 'other': 'Outros', + }); final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -50,46 +54,60 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Adicionar quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "Ao entrares confirmas que concordas com estes Termos e Condições"), + "Ao entrares confirmas que concordas com estes Termos e Condições", + ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), + "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", + ), "at_least_one_college": MessageLookupByLibrary.simpleMessage( - "Seleciona pelo menos uma faculdade"), + "Seleciona pelo menos uma faculdade", + ), "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( - "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!"), + r"Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!", + ), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug encontrado, como o reproduzir, etc"), + "Bug encontrado, como o reproduzir, etc", + ), "bus_error": MessageLookupByLibrary.simpleMessage( - "Não foi possível obter informação"), + "Não foi possível obter informação", + ), "bus_information": MessageLookupByLibrary.simpleMessage( - "Seleciona os autocarros dos quais queres informação:"), + "Seleciona os autocarros dos quais queres informação:", + ), "buses_personalize": MessageLookupByLibrary.simpleMessage( - "Configura aqui os teus autocarros"), + "Configura aqui os teus autocarros", + ), "buses_text": MessageLookupByLibrary.simpleMessage( - "Os autocarros favoritos serão apresentados no widget \'Autocarros\' dos favoritos. Os restantes serão apresentados apenas na página."), + "Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. Os restantes serão apresentados apenas na página.", + ), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), "change": MessageLookupByLibrary.simpleMessage("Alterar"), "change_prompt": MessageLookupByLibrary.simpleMessage( - "Deseja alterar a palavra-passe?"), + "Deseja alterar a palavra-passe?", + ), "check_internet": MessageLookupByLibrary.simpleMessage( - "Verifica a tua ligação à internet"), + "Verifica a tua ligação à internet", + ), "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), "college_select": MessageLookupByLibrary.simpleMessage( - "seleciona a(s) tua(s) faculdade(s)"), + "seleciona a(s) tua(s) faculdade(s)", + ), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "consent": MessageLookupByLibrary.simpleMessage( - "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido."), + "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.", + ), "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B | Edifício da AEFEUP"), + "Piso -1 do edifício B | Edifício da AEFEUP", + ), "course_class": MessageLookupByLibrary.simpleMessage("Turmas"), "course_info": MessageLookupByLibrary.simpleMessage("Ficha"), "current_state": MessageLookupByLibrary.simpleMessage("Estado atual: "), @@ -98,25 +116,30 @@ class MessageLookup extends MessageLookupByLibrary { "decrement": MessageLookupByLibrary.simpleMessage("Decrementar 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Descrição"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email em que desejas ser contactado"), + "Email em que desejas ser contactado", + ), "dona_bia": MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B (B-142)"), + "Piso -1 do edifício B (B-142)", + ), "ects": MessageLookupByLibrary.simpleMessage("ECTs realizados: "), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( - "Por favor preenche este campo"), + "Por favor preenche este campo", + ), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), "expired_password": MessageLookupByLibrary.simpleMessage("A tua palavra-passe expirou"), "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), "fee_date": MessageLookupByLibrary.simpleMessage( - "Data limite próxima prestação:"), + "Data limite próxima prestação:", + ), "fee_notification": MessageLookupByLibrary.simpleMessage( - "Notificar próxima data limite:"), + "Notificar próxima data limite:", + ), "first_year_registration": MessageLookupByLibrary.simpleMessage("Ano da primeira inscrição: "), "floor": MessageLookupByLibrary.simpleMessage("Piso"), @@ -139,7 +162,8 @@ class MessageLookup extends MessageLookupByLibrary { "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Carregando os Termos e Condições..."), + "Carregando os Termos e Condições...", + ), "login": MessageLookupByLibrary.simpleMessage("Entrar"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), @@ -150,20 +174,26 @@ class MessageLookup extends MessageLookupByLibrary { "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("Notícias"), "no_bus": MessageLookupByLibrary.simpleMessage( - "Não percas nenhum autocarro!"), + "Não percas nenhum autocarro!", + ), "no_bus_stops": MessageLookupByLibrary.simpleMessage( - "Não existe nenhuma paragem configurada"), + "Não existe nenhuma paragem configurada", + ), "no_class": MessageLookupByLibrary.simpleMessage( - "Não existem turmas para apresentar"), + "Não existem turmas para apresentar", + ), "no_classes": MessageLookupByLibrary.simpleMessage( - "Não existem aulas para apresentar"), + "Não existem aulas para apresentar", + ), "no_classes_on": MessageLookupByLibrary.simpleMessage("Não possui aulas à"), "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "Sem cadeiras no período selecionado"), + "Sem cadeiras no período selecionado", + ), "no_data": MessageLookupByLibrary.simpleMessage( - "Não há dados a mostrar neste momento"), + "Não há dados a mostrar neste momento", + ), "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), @@ -172,39 +202,50 @@ class MessageLookup extends MessageLookupByLibrary { "no_favorite_restaurants": MessageLookupByLibrary.simpleMessage("Sem restaurantes favoritos"), "no_info": MessageLookupByLibrary.simpleMessage( - "Não existem informações para apresentar"), + "Não existem informações para apresentar", + ), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "Não há informação disponível sobre refeições"), + "Não há informação disponível sobre refeições", + ), "no_menus": MessageLookupByLibrary.simpleMessage( - "Não há refeições disponíveis"), + "Não há refeições disponíveis", + ), "no_name_course": MessageLookupByLibrary.simpleMessage("Curso sem nome"), "no_references": MessageLookupByLibrary.simpleMessage( - "Não existem referências a pagar"), + "Não existem referências a pagar", + ), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "Não existem cadeiras para apresentar"), + "Não existem cadeiras para apresentar", + ), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "Não existem exames para apresentar"), + "Não existem exames para apresentar", + ), "occurrence_type": MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente."), + "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", + ), "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "pendent_references": MessageLookupByLibrary.simpleMessage("Referências pendentes"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Atendimento presencial"), "press_again": MessageLookupByLibrary.simpleMessage( - "Pressione novamente para sair"), + "Pressione novamente para sair", + ), "print": MessageLookupByLibrary.simpleMessage("Impressão"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Breve identificação do problema"), + "Breve identificação do problema", + ), "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - "Os dados da referência gerada aparecerão no Sigarra, conta corrente.\\nPerfil > Conta Corrente"), + r"Os dados da referência gerada aparecerão no Sigarra, conta corrente.\nPerfil > Conta Corrente", + ), "reference_success": MessageLookupByLibrary.simpleMessage( - "Referência criada com sucesso!"), + "Referência criada com sucesso!", + ), "remove": MessageLookupByLibrary.simpleMessage("Remover"), "room": MessageLookupByLibrary.simpleMessage("Sala"), "school_calendar": @@ -222,15 +263,18 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Atendimento presencial e telefónico"), + "Atendimento presencial e telefónico", + ), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), "terms": MessageLookupByLibrary.simpleMessage("Termos e Condições"), "title": MessageLookupByLibrary.simpleMessage("Título"), "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), "valid_email": MessageLookupByLibrary.simpleMessage( - "Por favor insere um email válido"), + "Por favor insere um email válido", + ), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:"), + "Escolhe um widget para adicionares à tua área pessoal:", + ), "year": MessageLookupByLibrary.simpleMessage("Ano") }; } diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 7b45c0e86..7704df1ae 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'intl/messages_all.dart'; +import 'package:uni/generated/intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -18,8 +18,10 @@ class S { static S? _current; static S get current { - assert(_current != null, - 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); + assert( + _current != null, + 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.', + ); return _current!; } @@ -41,8 +43,10 @@ class S { static S of(BuildContext context) { final instance = S.maybeOf(context); - assert(instance != null, - 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); + assert( + instance != null, + 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?', + ); return instance!; } @@ -193,7 +197,7 @@ class S { /// `Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.` String get buses_text { return Intl.message( - 'Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.', + "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", name: 'buses_text', desc: '', args: [], @@ -423,7 +427,7 @@ class S { /// `D. Beatriz's stationery store` String get dona_bia { return Intl.message( - 'D. Beatriz\'s stationery store', + "D. Beatriz's stationery store", name: 'dona_bia', desc: '', args: [], @@ -761,7 +765,7 @@ class S { /// `Don't miss any bus!` String get no_bus { return Intl.message( - 'Don\'t miss any bus!', + "Don't miss any bus!", name: 'no_bus', desc: '', args: [], @@ -801,7 +805,7 @@ class S { /// `You don't have classes on` String get no_classes_on { return Intl.message( - 'You don\'t have classes on', + "You don't have classes on", name: 'no_classes_on', desc: '', args: [], From 183f7ea5ad4455e328ae3d8b93983c7d763929e3 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 3 Sep 2023 21:52:35 +0100 Subject: [PATCH 100/199] Cleaning code --- uni/lib/controller/parsers/parser_calendar.dart | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/uni/lib/controller/parsers/parser_calendar.dart b/uni/lib/controller/parsers/parser_calendar.dart index e98d5467d..0d3cb2bad 100644 --- a/uni/lib/controller/parsers/parser_calendar.dart +++ b/uni/lib/controller/parsers/parser_calendar.dart @@ -7,21 +7,16 @@ Future> getCalendarFromHtml(Response response) async { final calendarHtml = document.querySelectorAll('tr'); - final eventList = calendarHtml + return calendarHtml .map( (event) => CalendarEvent( event.children[0].innerHtml, event.children[1].innerHtml, ), ) - .toList(); - - final filteredCalendar = eventList .where( (event) => event.name.trim() != ' ' && event.date.trim() != ' ', ) .toList(); - - return filteredCalendar; } From ca9479a38e1b16a923157954ff69c01859bb4e35 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 5 Sep 2023 16:02:06 +0100 Subject: [PATCH 101/199] AppLocale model implementation --- .../local_storage/app_shared_preferences.dart | 6 ++++-- uni/lib/main.dart | 9 ++++---- uni/lib/model/entities/app_locale.dart | 15 +++++++++++++ uni/lib/model/entities/exam.dart | 14 ++++++++++--- uni/lib/model/entities/login_exceptions.dart | 4 ++-- uni/lib/view/bug_report/widgets/form.dart | 14 +++++++++---- .../general/widgets/navigation_drawer.dart | 2 +- uni/lib/view/home/widgets/exam_card.dart | 7 ++++--- uni/lib/view/locale_notifier.dart | 21 ++++++++++--------- uni/lib/view/schedule/schedule.dart | 12 ++++++----- uni/test/test_widget.dart | 3 ++- 11 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 uni/lib/model/entities/app_locale.dart diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index 7efd46986..5a8b08b79 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -5,6 +5,7 @@ import 'package:encrypt/encrypt.dart' as encrypt; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tuple/tuple.dart'; +import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/utils/favorite_widget_type.dart'; @@ -124,10 +125,11 @@ class AppSharedPreferences { await prefs.setString(locale, appLocale); } - static Future getLocale() async { + static Future getLocale() async { final prefs = await SharedPreferences.getInstance(); final appLocale = prefs.getString(locale) ?? Platform.localeName; - return Locale(appLocale); + + return appLocale == 'pt' ? AppLocale.pt : AppLocale.en; } /// Deletes the user's student number and password. diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 66d95888c..b21a0ccc6 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -166,12 +166,13 @@ class MyApp extends StatefulWidget { final String initialRoute; + static final GlobalKey navigatorKey = + GlobalKey(); + @override State createState() => MyAppState(); } -final GlobalKey navigatorKey = GlobalKey(); - /// Manages the app depending on its current state class MyAppState extends State { @override @@ -185,7 +186,7 @@ class MyAppState extends State { theme: applicationLightTheme, darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), - locale: localeNotifier.getLocale(), + locale: localeNotifier.getLocale().localeCode, localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, @@ -194,7 +195,7 @@ class MyAppState extends State { ], supportedLocales: S.delegate.supportedLocales, initialRoute: widget.initialRoute, - navigatorKey: navigatorKey, + navigatorKey: MyApp.navigatorKey, onGenerateRoute: (RouteSettings settings) { final transitions = { '/${DrawerItem.navPersonalArea.title}': diff --git a/uni/lib/model/entities/app_locale.dart b/uni/lib/model/entities/app_locale.dart new file mode 100644 index 000000000..9f6cd2958 --- /dev/null +++ b/uni/lib/model/entities/app_locale.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +enum AppLocale { + en, + pt; + + Locale get localeCode { + switch (this) { + case AppLocale.en: + return const Locale('en'); + case AppLocale.pt: + return const Locale('pt'); + } + } +} diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index 0d4c61b8b..1d60fe37d 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -1,5 +1,8 @@ import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; +import 'package:provider/provider.dart'; +import 'package:uni/main.dart'; +import 'package:uni/view/locale_notifier.dart'; /// Manages a generic Exam. /// @@ -63,14 +66,19 @@ class Exam { /// Returns whether or not this exam has already ended. bool hasEnded() => DateTime.now().compareTo(end) >= 0; - String locale = Intl.getCurrentLocale(); + final locale = Provider.of(MyApp.navigatorKey.currentContext!) + .getLocale(); String get weekDay { - return DateFormat.EEEE(locale).dateSymbols.WEEKDAYS[begin.weekday - 1]; + return DateFormat.EEEE(locale.localeCode.languageCode) + .dateSymbols + .WEEKDAYS[begin.weekday - 1]; } String get month { - return DateFormat.EEEE(locale).dateSymbols.MONTHS[begin.month - 1]; + return DateFormat.EEEE(locale.localeCode.languageCode) + .dateSymbols + .MONTHS[begin.month - 1]; } String get beginTime => formatTime(begin); diff --git a/uni/lib/model/entities/login_exceptions.dart b/uni/lib/model/entities/login_exceptions.dart index 74ab67a01..ea368c4c5 100644 --- a/uni/lib/model/entities/login_exceptions.dart +++ b/uni/lib/model/entities/login_exceptions.dart @@ -7,10 +7,10 @@ class ExpiredCredentialsException implements Exception { class InternetStatusException implements Exception { InternetStatusException(); - String message = S.of(navigatorKey.currentContext!).check_internet; + String message = S.of(MyApp.navigatorKey.currentContext!).check_internet; } class WrongCredentialsException implements Exception { WrongCredentialsException(); - String message = S.of(navigatorKey.currentContext!).invalid_credentials; + String message = S.of(MyApp.navigatorKey.currentContext!).invalid_credentials; } diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 96eccb6c1..386fc8089 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -4,17 +4,20 @@ import 'package:email_validator/email_validator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; +import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/main.dart'; +import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/bug_report/widgets/text_field.dart'; import 'package:uni/view/common_widgets/page_title.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; +import 'package:uni/view/locale_notifier.dart'; class BugReportForm extends StatefulWidget { const BugReportForm({super.key}); @@ -60,14 +63,17 @@ class BugReportFormState extends State { bool _isConsentGiven = false; void loadBugClassList() { - final locale = Intl.getCurrentLocale(); + final locale = + Provider.of(MyApp.navigatorKey.currentContext!) + .getLocale(); bugList = bugDescriptions.entries .map( (entry) => DropdownMenuItem( value: entry.key, - child: - Text(locale == 'pt_PT' ? entry.value.item1 : entry.value.item2), + child: Text( + locale == AppLocale.pt ? entry.value.item1 : entry.value.item2, + ), ), ) .toList(); 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 6c5817968..5560d5611 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 @@ -101,7 +101,7 @@ class AppNavigationDrawerState extends State { child: Container( padding: const EdgeInsets.all(15), child: Text( - localeNotifier.getLocale().languageCode.toUpperCase(), + localeNotifier.getLocale().localeCode.languageCode.toUpperCase(), style: Theme.of(context) .textTheme .titleLarge! diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index a1b682102..3aeb60cf4 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -13,6 +13,7 @@ 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'; +import 'package:uni/view/locale_notifier.dart'; /// Manages the exam card section inside the personal area. class ExamCard extends GenericCard { @@ -106,10 +107,10 @@ class ExamCard extends GenericCard { /// Creates a row with the closest exam (which appears separated from the /// others in the card). Widget createRowFromExam(BuildContext context, Exam exam) { - final locale = Intl.getCurrentLocale(); + final locale = Provider.of(context).getLocale(); return Column( children: [ - if (locale == 'pt_PT') ...[ + if (locale == AppLocale.pt) ...[ DateRectangle( date: '${exam.weekDay}, ${exam.begin.day} de ${exam.month}', ) diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart index 6e8df082e..7fb5684a8 100644 --- a/uni/lib/view/locale_notifier.dart +++ b/uni/lib/view/locale_notifier.dart @@ -1,36 +1,37 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; +import 'package:uni/model/entities/app_locale.dart'; class LocaleNotifier with ChangeNotifier { LocaleNotifier(this._locale); - Locale _locale; + AppLocale _locale; - Locale getLocale() => _locale; + AppLocale getLocale() => _locale; void setNextLocale() { - final Locale nextLocale; - _locale == const Locale('pt') - ? nextLocale = const Locale('en') - : nextLocale = const Locale('pt'); + final AppLocale nextLocale; + _locale == AppLocale.pt + ? nextLocale = AppLocale.en + : nextLocale = AppLocale.pt; setLocale(nextLocale); } - void setLocale(Locale locale) { + void setLocale(AppLocale locale) { _locale = locale; - AppSharedPreferences.setLocale(locale.languageCode); + AppSharedPreferences.setLocale(locale.localeCode.languageCode); notifyListeners(); } List getWeekdaysWithLocale() { - final weekdays = DateFormat.EEEE(_locale.languageCode) + final weekdays = DateFormat.EEEE(_locale.localeCode.languageCode) .dateSymbols .WEEKDAYS .skip(1) .map((weekday) => weekday[0].toUpperCase() + weekday.substring(1)) .toList() - ..add(_locale.languageCode == 'en' ? 'Sunday' : 'Domingo'); + ..add(_locale == AppLocale.en ? 'Sunday' : 'Domingo'); return weekdays; } } diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index f18283688..084a9d856 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -124,18 +124,20 @@ class SchedulePageViewState extends GeneralPageViewState /// Returns a list of widgets empty with tabs for each day of the week. List createTabs(MediaQueryData queryData, BuildContext context) { final tabs = []; - for (var i = 0; i < 5; i++) { + final workWeekDays = Provider.of(context) + .getWeekdaysWithLocale() + .sublist(0, 5); + workWeekDays.asMap().forEach((index, day) { tabs.add( SizedBox( width: (queryData.size.width * 1) / 4, child: Tab( - key: Key('schedule-page-tab-$i'), - text: - Provider.of(context).getWeekdaysWithLocale()[i], + key: Key('schedule-page-tab-$index'), + text: day, ), ), ); - } + }); return tabs; } diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 67a4b27eb..7cdac440c 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/view/locale_notifier.dart'; Widget testableWidget( @@ -11,7 +12,7 @@ Widget testableWidget( return MultiProvider( providers: [ ChangeNotifierProvider( - create: (_) => LocaleNotifier(const Locale('pt')), + create: (_) => LocaleNotifier(AppLocale.pt), ), ...providers ], From 13a13b9448c7854213ff2b39a394795b6d84ccb1 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 6 Sep 2023 20:54:16 +0100 Subject: [PATCH 102/199] Locale tweaks --- .../local_storage/app_shared_preferences.dart | 7 ++++--- uni/lib/view/locale_notifier.dart | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index 5a8b08b79..5921e5fdd 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -120,16 +120,17 @@ class AppSharedPreferences { return prefs.setInt(themeMode, (themeIndex + 1) % 3); } - static Future setLocale(String appLocale) async { + static Future setLocale(AppLocale appLocale) async { final prefs = await SharedPreferences.getInstance(); - await prefs.setString(locale, appLocale); + await prefs.setString(locale, appLocale.name); } static Future getLocale() async { final prefs = await SharedPreferences.getInstance(); final appLocale = prefs.getString(locale) ?? Platform.localeName; - return appLocale == 'pt' ? AppLocale.pt : AppLocale.en; + return AppLocale.values + .firstWhere((e) => e.toString() == 'AppLocale.$appLocale'); } /// Deletes the user's student number and password. diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart index 7fb5684a8..36cf71bc7 100644 --- a/uni/lib/view/locale_notifier.dart +++ b/uni/lib/view/locale_notifier.dart @@ -11,16 +11,16 @@ class LocaleNotifier with ChangeNotifier { AppLocale getLocale() => _locale; void setNextLocale() { - final AppLocale nextLocale; - _locale == AppLocale.pt - ? nextLocale = AppLocale.en - : nextLocale = AppLocale.pt; + const availableLocales = AppLocale.values; + final currentIndex = availableLocales.indexOf(_locale); + final nextLocale = + availableLocales[(currentIndex + 1) % availableLocales.length]; setLocale(nextLocale); } void setLocale(AppLocale locale) { _locale = locale; - AppSharedPreferences.setLocale(locale.localeCode.languageCode); + AppSharedPreferences.setLocale(locale); notifyListeners(); } From 30c78f190806d886fb6bfb8dc83acf311b1aa75d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 6 Sep 2023 22:44:41 +0100 Subject: [PATCH 103/199] Tests and bug fix --- .../local_storage/app_shared_preferences.dart | 3 ++- uni/lib/model/entities/exam.dart | 11 +++-------- uni/lib/view/exams/exams.dart | 6 ++++-- 3 files changed, 9 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 5921e5fdd..fab87b249 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -127,7 +127,8 @@ class AppSharedPreferences { static Future getLocale() async { final prefs = await SharedPreferences.getInstance(); - final appLocale = prefs.getString(locale) ?? Platform.localeName; + final appLocale = + prefs.getString(locale) ?? Platform.localeName.substring(0, 2); return AppLocale.values .firstWhere((e) => e.toString() == 'AppLocale.$appLocale'); diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index 1d60fe37d..fb29f704a 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -1,8 +1,6 @@ import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; -import 'package:provider/provider.dart'; -import 'package:uni/main.dart'; -import 'package:uni/view/locale_notifier.dart'; +import 'package:uni/model/entities/app_locale.dart'; /// Manages a generic Exam. /// @@ -66,16 +64,13 @@ class Exam { /// Returns whether or not this exam has already ended. bool hasEnded() => DateTime.now().compareTo(end) >= 0; - final locale = Provider.of(MyApp.navigatorKey.currentContext!) - .getLocale(); - - String get weekDay { + String weekDay(AppLocale locale) { return DateFormat.EEEE(locale.localeCode.languageCode) .dateSymbols .WEEKDAYS[begin.weekday - 1]; } - String get month { + String month(AppLocale locale) { return DateFormat.EEEE(locale.localeCode.languageCode) .dateSymbols .MONTHS[begin.month - 1]; diff --git a/uni/lib/view/exams/exams.dart b/uni/lib/view/exams/exams.dart index 175e359fb..0731720e9 100644 --- a/uni/lib/view/exams/exams.dart +++ b/uni/lib/view/exams/exams.dart @@ -10,6 +10,7 @@ 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'; +import 'package:uni/view/locale_notifier.dart'; class ExamsPageView extends StatefulWidget { const ExamsPageView({super.key}); @@ -108,11 +109,12 @@ class ExamsPageViewState extends GeneralPageViewState { } Widget createExamsCards(BuildContext context, List exams) { + final locale = Provider.of(context).getLocale(); final examCards = [ DayTitle( day: exams[0].begin.day.toString(), - weekDay: exams[0].weekDay, - month: exams[0].month, + weekDay: exams[0].weekDay(locale), + month: exams[0].month(locale), ), ]; for (var i = 0; i < exams.length; i++) { From 0ac99e9ad658b03b60f44ac522e8771e1cfe2990 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 8 Sep 2023 23:10:04 +0100 Subject: [PATCH 104/199] Optimizing --- .../local_storage/app_shared_preferences.dart | 6 ++++-- uni/lib/model/entities/login_exceptions.dart | 21 +++++++++++++------ .../providers/startup/session_provider.dart | 14 ++++++++++--- uni/lib/view/bug_report/widgets/form.dart | 14 ++++++++----- .../view/bug_report/widgets/text_field.dart | 4 ++-- uni/lib/view/login/login.dart | 1 + 6 files changed, 42 insertions(+), 18 deletions(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index fab87b249..d5da1a7c4 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -130,8 +130,10 @@ class AppSharedPreferences { final appLocale = prefs.getString(locale) ?? Platform.localeName.substring(0, 2); - return AppLocale.values - .firstWhere((e) => e.toString() == 'AppLocale.$appLocale'); + return AppLocale.values.firstWhere( + (e) => e.toString() == 'AppLocale.$appLocale', + orElse: () => AppLocale.en, + ); } /// Deletes the user's student number and password. diff --git a/uni/lib/model/entities/login_exceptions.dart b/uni/lib/model/entities/login_exceptions.dart index ea368c4c5..a6a129f80 100644 --- a/uni/lib/model/entities/login_exceptions.dart +++ b/uni/lib/model/entities/login_exceptions.dart @@ -1,16 +1,25 @@ -import 'package:uni/generated/l10n.dart'; -import 'package:uni/main.dart'; +import 'package:uni/model/entities/app_locale.dart'; class ExpiredCredentialsException implements Exception { ExpiredCredentialsException(); } class InternetStatusException implements Exception { - InternetStatusException(); - String message = S.of(MyApp.navigatorKey.currentContext!).check_internet; + InternetStatusException(this.locale) + : message = locale == AppLocale.en + ? 'Check your internet connection' + : 'Verifique sua conexão com a internet'; + + final AppLocale locale; + final String message; } class WrongCredentialsException implements Exception { - WrongCredentialsException(); - String message = S.of(MyApp.navigatorKey.currentContext!).invalid_credentials; + WrongCredentialsException(this.locale) + : message = locale == AppLocale.en + ? 'Invalid credentials' + : 'Credenciais inválidas'; + + final AppLocale locale; + final String message; } diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 2126f0679..e4b006ea6 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/load_static/terms_and_conditions.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; @@ -10,6 +12,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/locale_notifier.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() @@ -59,6 +62,7 @@ class SessionProvider extends StateProviderNotifier { } Future postAuthentication( + BuildContext context, String username, String password, List faculties, { @@ -76,7 +80,9 @@ class SessionProvider extends StateProviderNotifier { ); } catch (e) { updateStatus(RequestStatus.failed); - throw InternetStatusException(); + throw InternetStatusException( + Provider.of(context).getLocale(), + ); } if (session == null) { @@ -85,10 +91,12 @@ class SessionProvider extends StateProviderNotifier { updateStatus(RequestStatus.failed); - if (isPasswordExpired(responseHtml)) { + if (isPasswordExpired(responseHtml) && context.mounted) { throw ExpiredCredentialsException(); } else { - throw WrongCredentialsException(); + throw WrongCredentialsException( + Provider.of(context).getLocale(), + ); } } diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 386fc8089..6c5e1cfda 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -10,7 +10,6 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/generated/l10n.dart'; -import 'package:uni/main.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -63,16 +62,21 @@ class BugReportFormState extends State { bool _isConsentGiven = false; void loadBugClassList() { - final locale = - Provider.of(MyApp.navigatorKey.currentContext!) - .getLocale(); + final locale = Provider.of(context).getLocale(); bugList = bugDescriptions.entries .map( (entry) => DropdownMenuItem( value: entry.key, child: Text( - locale == AppLocale.pt ? entry.value.item1 : entry.value.item2, + () { + switch (locale) { + case AppLocale.pt: + return entry.value.item1; + case AppLocale.en: + return entry.value.item2; + } + }(), ), ), ) diff --git a/uni/lib/view/bug_report/widgets/text_field.dart b/uni/lib/view/bug_report/widgets/text_field.dart index d01b076a7..037b5e3db 100644 --- a/uni/lib/view/bug_report/widgets/text_field.dart +++ b/uni/lib/view/bug_report/widgets/text_field.dart @@ -62,8 +62,8 @@ class FormTextField extends StatelessWidget { labelStyle: Theme.of(context).textTheme.bodyMedium, ), controller: controller, - validator: (value) { - if (value!.isEmpty) { + validator: (String? value) { + if (value == null || value.isEmpty) { return isOptional ? null : S.of(context).empty_text; } return formatValidator?.call(value); diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 600c9498c..544e6cf3a 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -50,6 +50,7 @@ class LoginPageViewState extends State { try { await sessionProvider.postAuthentication( + context, user, pass, faculties, From c04676f1d34a2a2dcaf055cadefb2b2393ba7ae6 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sat, 9 Sep 2023 11:10:13 +0100 Subject: [PATCH 105/199] Some missed translations --- uni/lib/generated/intl/messages_all.dart | 7 +++++-- uni/lib/generated/intl/messages_en.dart | 18 ++++++++++++----- uni/lib/generated/intl/messages_pt_PT.dart | 18 ++++++++++++----- uni/lib/generated/l10n.dart | 20 +++++++++++++++++++ uni/lib/l10n/intl_en.arb | 4 ++++ uni/lib/l10n/intl_pt_PT.arb | 4 ++++ .../request_dependent_widget_builder.dart | 7 ++++--- uni/lib/view/login/login.dart | 2 +- 8 files changed, 64 insertions(+), 16 deletions(-) diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index de96ef7c8..5c2bef3d1 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -61,8 +61,11 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = - Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); + final actualLocale = Intl.verifiedLocale( + locale, + _messagesExistFor, + onFailure: (_) => null, + ); if (actualLocale == null) return null; return _findExact(actualLocale); } diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 908784164..6c7f8c46a 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -54,10 +54,12 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "By entering you confirm that you agree with these Terms and Conditions", + "By entering you confirm that you agree with these Terms " + "and Conditions", ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "All available widgets have already been added to your personal area!", + "All available widgets have already been added to your personal " + "area!", ), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), @@ -77,7 +79,8 @@ class MessageLookup extends MessageLookupByLibrary { "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", + "Favorite buses will be displayed in the favorites 'Bus' widget. " + "The remaining ones will only be displayed on the page.", ), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "change": MessageLookupByLibrary.simpleMessage("Change"), @@ -97,7 +100,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", + "I consent to this information being reviewed by NIAEFEUP " + "and may be deleted at my request.", ), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), @@ -156,6 +160,9 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), + "load_error": MessageLookupByLibrary.simpleMessage( + "Error loading the information", + ), "loading_terms": MessageLookupByLibrary.simpleMessage( "Loading Terms and Conditions...", ), @@ -239,6 +246,7 @@ class MessageLookup extends MessageLookupByLibrary { "Reference created successfully!", ), "remove": MessageLookupByLibrary.simpleMessage("Delete"), + "report_error": MessageLookupByLibrary.simpleMessage("Report error"), "room": MessageLookupByLibrary.simpleMessage("Room"), "school_calendar": MessageLookupByLibrary.simpleMessage("School Calendar"), diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 8a36505af..9107d6c45 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -57,7 +57,8 @@ class MessageLookup extends MessageLookupByLibrary { "Ao entrares confirmas que concordas com estes Termos e Condições", ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", + "Todos os widgets disponíveis já foram adicionados à tua " + "área pessoal!", ), "at_least_one_college": MessageLookupByLibrary.simpleMessage( "Seleciona pelo menos uma faculdade", @@ -80,7 +81,8 @@ class MessageLookup extends MessageLookupByLibrary { "Configura aqui os teus autocarros", ), "buses_text": MessageLookupByLibrary.simpleMessage( - "Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. Os restantes serão apresentados apenas na página.", + "Os autocarros favoritos serão apresentados no widget 'Autocarros' " + "dos favoritos. Os restantes serão apresentados apenas na página.", ), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), "change": MessageLookupByLibrary.simpleMessage("Alterar"), @@ -101,7 +103,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "consent": MessageLookupByLibrary.simpleMessage( - "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.", + "Consinto que esta informação seja revista pelo NIAEFEUP, " + "podendo ser eliminada a meu pedido.", ), "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), @@ -161,6 +164,9 @@ class MessageLookup extends MessageLookupByLibrary { "last_timestamp": m1, "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "load_error": MessageLookupByLibrary.simpleMessage( + "Aconteceu um erro ao carregar os dados", + ), "loading_terms": MessageLookupByLibrary.simpleMessage( "Carregando os Termos e Condições...", ), @@ -226,7 +232,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", + "Por razões de segurança, as palavras-passe têm de ser " + "alteradas periodicamente.", ), "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "pendent_references": @@ -247,6 +254,7 @@ class MessageLookup extends MessageLookupByLibrary { "Referência criada com sucesso!", ), "remove": MessageLookupByLibrary.simpleMessage("Remover"), + "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), "room": MessageLookupByLibrary.simpleMessage("Sala"), "school_calendar": MessageLookupByLibrary.simpleMessage("Calendário Escolar"), diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 7704df1ae..bf85c2c4b 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -667,6 +667,16 @@ class S { ); } + /// `Error loading the information` + String get load_error { + return Intl.message( + 'Error loading the information', + name: 'load_error', + desc: '', + args: [], + ); + } + /// `Loading Terms and Conditions...` String get loading_terms { return Intl.message( @@ -1082,6 +1092,16 @@ class S { ); } + /// `Report error` + String get report_error { + return Intl.message( + 'Report error', + name: 'report_error', + desc: '', + args: [], + ); + } + /// `Room` String get room { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index d63ce3056..770f69290 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -130,6 +130,8 @@ }, "library_occupation": "Library Occupation", "@library_occupation": {}, + "load_error": "Error loading the information", + "@load_error": {}, "loading_terms": "Loading Terms and Conditions...", "@loading_terms": {}, "login": "Login", @@ -210,6 +212,8 @@ "@reference_success": {}, "remove": "Delete", "@remove": {}, + "report_error": "Report error", + "@report_error": {}, "room": "Room", "@room": {}, "school_calendar": "School Calendar", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index eaf6e2829..cda6d8639 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -130,6 +130,8 @@ }, "library_occupation": "Ocupação da Biblioteca", "@library_occupation": {}, + "load_error": "Aconteceu um erro ao carregar os dados", + "@load_error": {}, "loading_terms": "Carregando os Termos e Condições...", "@loading_terms": {}, "login": "Entrar", @@ -210,6 +212,8 @@ "@reference_success": {}, "remove": "Remover", "@remove": {}, + "report_error": "Reportar erro", + "@report_error": {}, "room": "Sala", "@room": {}, "school_calendar": "Calendário Escolar", 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 170203fdb..899de33a1 100644 --- a/uni/lib/view/common_widgets/request_dependent_widget_builder.dart +++ b/uni/lib/view/common_widgets/request_dependent_widget_builder.dart @@ -1,6 +1,7 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:shimmer/shimmer.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -74,7 +75,7 @@ class RequestDependentWidgetBuilder extends StatelessWidget { return Center( heightFactor: 3, child: Text( - 'Sem ligação à internet', + S.of(context).check_internet, style: Theme.of(context).textTheme.titleMedium, ), ); @@ -86,7 +87,7 @@ class RequestDependentWidgetBuilder extends StatelessWidget { padding: const EdgeInsets.only(top: 15, bottom: 10), child: Center( child: Text( - 'Aconteceu um erro ao carregar os dados', + S.of(context).load_error, style: Theme.of(context).textTheme.titleMedium, ), ), @@ -96,7 +97,7 @@ class RequestDependentWidgetBuilder extends StatelessWidget { context, '/${DrawerItem.navBugReport.title}', ), - child: const Text('Reportar erro'), + child: Text(S.of(context).report_error), ) ], ); diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 544e6cf3a..5a05df5f2 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -67,7 +67,7 @@ class LoginPageViewState extends State { } else if (error is WrongCredentialsException) { unawaited(ToastMessage.error(context, error.message)); } else { - unawaited(ToastMessage.error(context, 'Erro no login')); + unawaited(ToastMessage.error(context, S.of(context).failed_login)); } } } From da2afdb5a9e5ab3701b0be11cad68684f7434f3f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 10:57:07 +0100 Subject: [PATCH 106/199] Translations and context fix --- uni/lib/generated/intl/messages_en.dart | 17 ++++++++-------- uni/lib/generated/intl/messages_pt_PT.dart | 17 ++++++++-------- uni/lib/generated/l10n.dart | 20 +++++++++++++++++++ uni/lib/l10n/intl_en.arb | 4 ++++ uni/lib/l10n/intl_pt_PT.arb | 4 ++++ uni/lib/view/bug_report/widgets/form.dart | 5 ++++- uni/lib/view/locale_notifier.dart | 12 +++++------ .../view/profile/widgets/print_info_card.dart | 5 +++-- 8 files changed, 56 insertions(+), 28 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 6c7f8c46a..eccb8f146 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -54,15 +54,15 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "By entering you confirm that you agree with these Terms " - "and Conditions", + "By entering you confirm that you agree with these Terms and Conditions", ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "All available widgets have already been added to your personal " - "area!", + "All available widgets have already been added to your personal area!", ), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), + "available_amount": + MessageLookupByLibrary.simpleMessage("Available amount"), "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( @@ -79,8 +79,7 @@ class MessageLookup extends MessageLookupByLibrary { "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites 'Bus' widget. " - "The remaining ones will only be displayed on the page.", + "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", ), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "change": MessageLookupByLibrary.simpleMessage("Change"), @@ -100,8 +99,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by NIAEFEUP " - "and may be deleted at my request.", + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", ), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), @@ -236,6 +234,7 @@ class MessageLookup extends MessageLookupByLibrary { "press_again": MessageLookupByLibrary.simpleMessage("Press again to exit"), "print": MessageLookupByLibrary.simpleMessage("Print"), + "prints": MessageLookupByLibrary.simpleMessage("Prints"), "problem_id": MessageLookupByLibrary.simpleMessage( "Brief identification of the problem", ), diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 9107d6c45..800ef819f 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -4,7 +4,7 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases // ignore_for_file:unused_import, file_names @@ -57,12 +57,13 @@ class MessageLookup extends MessageLookupByLibrary { "Ao entrares confirmas que concordas com estes Termos e Condições", ), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "Todos os widgets disponíveis já foram adicionados à tua " - "área pessoal!", + "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", ), "at_least_one_college": MessageLookupByLibrary.simpleMessage( "Seleciona pelo menos uma faculdade", ), + "available_amount": + MessageLookupByLibrary.simpleMessage("Valor disponível"), "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( @@ -81,8 +82,7 @@ class MessageLookup extends MessageLookupByLibrary { "Configura aqui os teus autocarros", ), "buses_text": MessageLookupByLibrary.simpleMessage( - "Os autocarros favoritos serão apresentados no widget 'Autocarros' " - "dos favoritos. Os restantes serão apresentados apenas na página.", + "Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. Os restantes serão apresentados apenas na página.", ), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), "change": MessageLookupByLibrary.simpleMessage("Alterar"), @@ -103,8 +103,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "consent": MessageLookupByLibrary.simpleMessage( - "Consinto que esta informação seja revista pelo NIAEFEUP, " - "podendo ser eliminada a meu pedido.", + "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.", ), "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), @@ -232,8 +231,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "Por razões de segurança, as palavras-passe têm de ser " - "alteradas periodicamente.", + "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", ), "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "pendent_references": @@ -244,6 +242,7 @@ class MessageLookup extends MessageLookupByLibrary { "Pressione novamente para sair", ), "print": MessageLookupByLibrary.simpleMessage("Impressão"), + "prints": MessageLookupByLibrary.simpleMessage("Impressões"), "problem_id": MessageLookupByLibrary.simpleMessage( "Breve identificação do problema", ), diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index bf85c2c4b..3a2aec795 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -134,6 +134,16 @@ class S { ); } + /// `Available amount` + String get available_amount { + return Intl.message( + 'Available amount', + name: 'available_amount', + desc: '', + args: [], + ); + } + /// `Average: ` String get average { return Intl.message( @@ -1052,6 +1062,16 @@ class S { ); } + /// `Prints` + String get prints { + return Intl.message( + 'Prints', + name: 'prints', + desc: '', + args: [], + ); + } + /// `Brief identification of the problem` String get problem_id { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 770f69290..12a47bfbc 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -16,6 +16,8 @@ "@all_widgets_added": {}, "at_least_one_college": "Select at least one college", "@at_least_one_college": {}, + "available_amount": "Available amount", + "@available_amount": {}, "average": "Average: ", "@average": {}, "balance": "Balance:", @@ -204,6 +206,8 @@ "@press_again": {}, "print": "Print", "@print": {}, + "prints": "Prints", + "@prints": {}, "problem_id": "Brief identification of the problem", "@problem_id": {}, "reference_sigarra_help": "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index cda6d8639..ad8d0790d 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -16,6 +16,8 @@ "@all_widgets_added": {}, "at_least_one_college": "Seleciona pelo menos uma faculdade", "@at_least_one_college": {}, + "available_amount": "Valor disponível", + "@available_amount": {}, "average": "Média: ", "@average": {}, "balance": "Saldo:", @@ -204,6 +206,8 @@ "@press_again": {}, "print": "Impressão", "@print": {}, + "prints": "Impressões", + "@prints": {}, "problem_id": "Breve identificação do problema", "@problem_id": {}, "reference_sigarra_help": "Os dados da referência gerada aparecerão no Sigarra, conta corrente.\\nPerfil > Conta Corrente", diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 6c5e1cfda..95888cb30 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -10,6 +10,7 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/generated/l10n.dart'; +import 'package:uni/main.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -62,7 +63,9 @@ class BugReportFormState extends State { bool _isConsentGiven = false; void loadBugClassList() { - final locale = Provider.of(context).getLocale(); + final locale = + Provider.of(MyApp.navigatorKey.currentContext!) + .getLocale(); bugList = bugDescriptions.entries .map( diff --git a/uni/lib/view/locale_notifier.dart b/uni/lib/view/locale_notifier.dart index 36cf71bc7..5ecbccda6 100644 --- a/uni/lib/view/locale_notifier.dart +++ b/uni/lib/view/locale_notifier.dart @@ -25,13 +25,11 @@ class LocaleNotifier with ChangeNotifier { } List getWeekdaysWithLocale() { - final weekdays = DateFormat.EEEE(_locale.localeCode.languageCode) - .dateSymbols - .WEEKDAYS - .skip(1) + final allWeekDays = DateFormat.EEEE().dateSymbols.WEEKDAYS; + final europeanWeekDays = allWeekDays.skip(1).toList() + ..add(allWeekDays.first); + return europeanWeekDays .map((weekday) => weekday[0].toUpperCase() + weekday.substring(1)) - .toList() - ..add(_locale == AppLocale.en ? 'Sunday' : 'Domingo'); - return weekdays; + .toList(); } } diff --git a/uni/lib/view/profile/widgets/print_info_card.dart b/uni/lib/view/profile/widgets/print_info_card.dart index 05b128f0e..fa26a3ebb 100644 --- a/uni/lib/view/profile/widgets/print_info_card.dart +++ b/uni/lib/view/profile/widgets/print_info_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.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'; @@ -38,7 +39,7 @@ class PrintInfoCard extends GenericCard { left: 20, ), child: Text( - 'Valor disponível: ', + S.of(context).available_amount, style: Theme.of(context).textTheme.titleSmall, ), ), @@ -76,7 +77,7 @@ class PrintInfoCard extends GenericCard { } @override - String getTitle(BuildContext context) => 'Impressões'; + String getTitle(BuildContext context) => S.of(context).prints; @override void onClick(BuildContext context) {} From e1849901dff47eef64c32b865f9ed0216a668cff Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Sun, 10 Sep 2023 10:02:11 +0000 Subject: [PATCH 107/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 1e7f5c2d4..162a8e3d3 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.58+176 \ No newline at end of file +1.5.59+177 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 7b170b1d6..c28281224 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.58+176 +version: 1.5.59+177 environment: sdk: '>=3.0.0 <4.0.0' From 17c5449f0a36ef0f805372bb0fbe9f2411f49e7a Mon Sep 17 00:00:00 2001 From: thePeras Date: Sun, 10 Sep 2023 10:08:03 +0000 Subject: [PATCH 108/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 162a8e3d3..212c19aef 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.59+177 \ No newline at end of file +1.5.60+178 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index c28281224..04d64aa81 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.59+177 +version: 1.5.60+178 environment: sdk: '>=3.0.0 <4.0.0' From c84ad695d09b630bf56ce63f84d73f5802ee108a Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 12:24:33 +0100 Subject: [PATCH 109/199] Upgrading intl to 0.18.0 --- uni/lib/controller/local_storage/app_bus_stop_database.dart | 3 +-- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/uni/lib/controller/local_storage/app_bus_stop_database.dart b/uni/lib/controller/local_storage/app_bus_stop_database.dart index a62476004..fa87d324d 100644 --- a/uni/lib/controller/local_storage/app_bus_stop_database.dart +++ b/uni/lib/controller/local_storage/app_bus_stop_database.dart @@ -38,8 +38,7 @@ class AppBusStopDatabase extends AppDatabase { } final stops = {}; - groupBy(buses, (stop) => (stop! as Map)['stopCode']) - .forEach( + groupBy(buses, (stop) => stop['stopCode']).forEach( (stopCode, busCodeList) => stops[stopCode as String] = BusStopData( configuredBuses: Set.from( busCodeList.map((busEntry) => busEntry['busCode']), diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 0f7a15e56..3e0ffa867 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: html: ^0.15.0 http: ^0.13.0 image: ^4.0.13 - intl: ^0.17.0 + intl: ^0.18.0 latlong2: ^0.8.1 logger: ^1.1.0 material_design_icons_flutter: ^7.0.7296 From 12f5a9d4377a92a83d980fd6ec5f5da822a763ec Mon Sep 17 00:00:00 2001 From: thePeras Date: Sun, 10 Sep 2023 12:37:44 +0100 Subject: [PATCH 110/199] Remove .env from action and readme --- .github/workflows/deploy.yaml | 6 ------ uni/.gitignore | 1 - uni/README.md | 12 ------------ 3 files changed, 19 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 2017cb745..051ac1bda 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -54,12 +54,6 @@ jobs: with: flutter-version: ${{ env.FLUTTER_VERSION }} - - name: Setup production environment - run: | - mkdir -p assets/env - rm -f -- assets/env/env.json - echo "{\"gh_token\": \"${{ secrets.NIAEFEUPBOT_PAT }}\"}" >> assets/env/env.json - - name: Download Android keystore run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > /tmp/key.jks diff --git a/uni/.gitignore b/uni/.gitignore index 69fd250d8..a0cabb6dc 100644 --- a/uni/.gitignore +++ b/uni/.gitignore @@ -9,7 +9,6 @@ .buildlog/ .history .svn/ -assets/env/env.json *.env # IntelliJ related diff --git a/uni/README.md b/uni/README.md index b6c91e4eb..200d3c193 100644 --- a/uni/README.md +++ b/uni/README.md @@ -4,18 +4,6 @@ This is a Flutter project, totally compatible with Android and iOS. To run it, you need to have Flutter installed on your machine. If you don't, you can follow the instructions on https://flutter.dev/docs/get-started/install. -### Further requirements - -In order to submit bug reports to the Github API (needed in order to enable in-app bug reporting), a Github Personal Access Token is required. If you don't have one, you can create it on https://github.com/settings/tokens. The only permission it needs is **repo > public_repo**. - -The token is read from the file assets/env/env.json, which you may need to create, and must be in the following format: - -```json -{ - "gh_token" : "your super secret token" -} -``` - ### Automated formatting In order to contribute, you must format your changed files using `dart format` manually or enabing _formatting on save_ using your IDE ([VSCode or IntelliJ](https://docs.flutter.dev/tools/formatting)). Alternatively, you can install the git pre-commit hook that formats your changed files when you commit, doing the following command at the **root directory of the repository**: From f1e85dfa29c0c6c6f414c552dba3910582727080 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Sun, 10 Sep 2023 12:35:47 +0000 Subject: [PATCH 111/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 212c19aef..8ae44e95a 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.60+178 \ No newline at end of file +1.5.61+179 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index a8bf549e0..0ae5d5616 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.60+178 +version: 1.5.61+179 environment: sdk: '>=3.0.0 <4.0.0' From ad377b89eb36f46747d38b0954d68b59dc25263d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 15:20:49 +0100 Subject: [PATCH 112/199] Removing navigator context --- uni/lib/main.dart | 4 ---- uni/lib/view/bug_report/widgets/form.dart | 8 ++++---- uni/lib/view/useful_info/widgets/other_links_card.dart | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/uni/lib/main.dart b/uni/lib/main.dart index b21a0ccc6..6f2e29a30 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -166,9 +166,6 @@ class MyApp extends StatefulWidget { final String initialRoute; - static final GlobalKey navigatorKey = - GlobalKey(); - @override State createState() => MyAppState(); } @@ -195,7 +192,6 @@ class MyAppState extends State { ], supportedLocales: S.delegate.supportedLocales, initialRoute: widget.initialRoute, - navigatorKey: MyApp.navigatorKey, onGenerateRoute: (RouteSettings settings) { final transitions = { '/${DrawerItem.navPersonalArea.title}': diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index 95888cb30..b20cba429 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -10,7 +10,6 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/generated/l10n.dart'; -import 'package:uni/main.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -30,7 +29,9 @@ class BugReportForm extends StatefulWidget { /// Manages the 'Bugs and Suggestions' section of the app class BugReportFormState extends State { - BugReportFormState() { + @override + void didChangeDependencies() { + super.didChangeDependencies(); loadBugClassList(); } @@ -64,8 +65,7 @@ class BugReportFormState extends State { void loadBugClassList() { final locale = - Provider.of(MyApp.navigatorKey.currentContext!) - .getLocale(); + Provider.of(context, listen: false).getLocale(); bugList = bugDescriptions.entries .map( diff --git a/uni/lib/view/useful_info/widgets/other_links_card.dart b/uni/lib/view/useful_info/widgets/other_links_card.dart index 42e7fd713..47ae82046 100644 --- a/uni/lib/view/useful_info/widgets/other_links_card.dart +++ b/uni/lib/view/useful_info/widgets/other_links_card.dart @@ -10,8 +10,8 @@ class OtherLinksCard extends GenericExpansionCard { @override Widget buildCardContent(BuildContext context) { - return Column( - children: const [ + return const Column( + children: [ // LinkButton(title: S.of(context).print, link: 'https://print.up.pt'), // TODO(Process-ing): Get fixed link LinkButton( From 1bc0faed41ccbd577aa6271a537646013de3336d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 19:22:19 +0100 Subject: [PATCH 113/199] Testable widget fix --- uni/test/test_widget.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 7cdac440c..a84960a72 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -3,6 +3,9 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/app_locale.dart'; + +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/locale_notifier.dart'; Widget testableWidget( @@ -11,6 +14,8 @@ Widget testableWidget( }) { return MultiProvider( providers: [ + ChangeNotifierProvider(create: (context) => SessionProvider()), + ChangeNotifierProvider(create: (context) => ProfileProvider()), ChangeNotifierProvider( create: (_) => LocaleNotifier(AppLocale.pt), ), From 552370165eaa1870160b900a0a94b7d8c9301c60 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 19:32:47 +0100 Subject: [PATCH 114/199] Test fixing --- uni/test/mocks/integration/src/schedule_page_test.mocks.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/uni/test/mocks/integration/src/schedule_page_test.mocks.dart b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart index c3259a73a..d46eb9577 100644 --- a/uni/test/mocks/integration/src/schedule_page_test.mocks.dart +++ b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -9,6 +9,7 @@ import 'dart:typed_data' as _i6; import 'dart:ui' as _i11; import 'package:flutter/material.dart' as _i10; +import 'package:flutter/widgets.dart'; import 'package:http/http.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:uni/model/entities/profile.dart' as _i9; @@ -493,6 +494,7 @@ class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { ); @override _i4.Future postAuthentication( + BuildContext context, String? username, String? password, List? faculties, { From 5e1cb2c4361aa7f8d8bcc24ff7582b0cd1d623e7 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 10 Sep 2023 20:13:45 +0100 Subject: [PATCH 115/199] Generated mock file --- uni/test/mocks/integration/src/schedule_page_test.mocks.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/test/mocks/integration/src/schedule_page_test.mocks.dart b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart index d46eb9577..e5e3b4548 100644 --- a/uni/test/mocks/integration/src/schedule_page_test.mocks.dart +++ b/uni/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -9,7 +9,6 @@ import 'dart:typed_data' as _i6; import 'dart:ui' as _i11; import 'package:flutter/material.dart' as _i10; -import 'package:flutter/widgets.dart'; import 'package:http/http.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:uni/model/entities/profile.dart' as _i9; @@ -494,7 +493,7 @@ class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { ); @override _i4.Future postAuthentication( - BuildContext context, + _i10.BuildContext? context, String? username, String? password, List? faculties, { @@ -504,6 +503,7 @@ class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { Invocation.method( #postAuthentication, [ + context, username, password, faculties, From 1ff9249661cf425e3a85983c1f8526ae84c555ab Mon Sep 17 00:00:00 2001 From: thePeras Date: Mon, 11 Sep 2023 13:08:20 +0100 Subject: [PATCH 116/199] Update xcode project file --- uni/ios/Runner.xcodeproj/project.pbxproj | 3 ++- .../Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/uni/ios/Runner.xcodeproj/project.pbxproj b/uni/ios/Runner.xcodeproj/project.pbxproj index d9fdaf94b..ef55cd3bd 100644 --- a/uni/ios/Runner.xcodeproj/project.pbxproj +++ b/uni/ios/Runner.xcodeproj/project.pbxproj @@ -155,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -204,6 +204,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a33..a6b826db2 100644 --- a/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 12 Sep 2023 13:17:00 +0100 Subject: [PATCH 117/199] Log provider flow more extensively and fix lecture provider offline load --- .../local_storage/app_lectures_database.dart | 2 +- .../controller/networking/network_router.dart | 5 ++- .../providers/state_provider_notifier.dart | 34 +++++++++++++------ uni/lib/view/lazy_consumer.dart | 4 ++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/uni/lib/controller/local_storage/app_lectures_database.dart b/uni/lib/controller/local_storage/app_lectures_database.dart index e1cce3121..a4e6b55c5 100644 --- a/uni/lib/controller/local_storage/app_lectures_database.dart +++ b/uni/lib/controller/local_storage/app_lectures_database.dart @@ -37,7 +37,7 @@ CREATE TABLE lectures(subject TEXT, typeClass TEXT, return Lecture.fromApi( maps[i]['subject'] as String, maps[i]['typeClass'] as String, - maps[i]['startDateTime'] as DateTime, + DateTime.parse(maps[i]['startDateTime'] as String), maps[i]['blocks'] as int, maps[i]['room'] as String, maps[i]['teacher'] as String, diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index 5d64c5ecc..ce60f4a68 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -176,6 +176,9 @@ class NetworkRouter { final userIsLoggedIn = _cachedSession != null && await userLoggedIn(session); if (!userIsLoggedIn) { + Logger() + .d('User is not logged in; performing re-login from saved data'); + final newSession = await reLoginFromSession(session); if (newSession == null) { @@ -209,7 +212,7 @@ class NetworkRouter { /// performing a health check on the user's personal page. static Future userLoggedIn(Session session) async { return _loginLock.synchronized(() async { - Logger().i('Checking if user is still logged in'); + Logger().d('Checking if user is still logged in'); final url = '${getBaseUrl(session.faculties[0])}' 'fest_geral.cursos_list?pv_num_unico=${session.username}'; diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index de3e71696..d437089c2 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -16,7 +16,8 @@ abstract class StateProviderNotifier extends ChangeNotifier { this.dependsOnSession = true, RequestStatus initialStatus = RequestStatus.busy, bool initialize = true, - }) : _initialStatus = initialStatus, + }) + : _initialStatus = initialStatus, _status = initialStatus, _initializedFromStorage = !initialize, _initializedFromRemote = !initialize; @@ -42,6 +43,8 @@ abstract class StateProviderNotifier extends ChangeNotifier { } Future _loadFromStorage() async { + Logger().d('Loading $runtimeType info from storage'); + _lastUpdateTime = await AppSharedPreferences.getLastDataClassUpdateTime( runtimeType.toString(), ); @@ -51,11 +54,12 @@ abstract class StateProviderNotifier extends ChangeNotifier { Logger().i('Loaded $runtimeType info from storage'); } - Future _loadFromRemote( - Session session, - Profile profile, { - bool force = false, - }) async { + Future _loadFromRemote(Session session, + Profile profile, { + bool force = false, + }) async { + Logger().d('Loading $runtimeType info from remote'); + final shouldReload = force || _lastUpdateTime == null || cacheDuration == null || @@ -109,15 +113,19 @@ abstract class StateProviderNotifier extends ChangeNotifier { const Duration(minutes: 1)) { Logger().w( 'Last update for $runtimeType was less than a minute ago; ' - 'skipping refresh', + 'skipping refresh', ); return; } final session = - Provider.of(context, listen: false).session; + Provider + .of(context, listen: false) + .session; final profile = - Provider.of(context, listen: false).profile; + Provider + .of(context, listen: false) + .profile; await _loadFromRemote(session, profile, force: true); }); @@ -140,9 +148,13 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromRemote = true; final session = - Provider.of(context, listen: false).session; + Provider + .of(context, listen: false) + .session; final profile = - Provider.of(context, listen: false).profile; + Provider + .of(context, listen: false) + .profile; await _loadFromRemote(session, profile); }); diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 7364306b4..40a39e2e5 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -47,7 +47,9 @@ class LazyConsumer extends StatelessWidget { }); } } catch (e) { - Logger().e('Failed to initialize $T: $e'); + Logger().e( + 'Failed to initialize $T: $e', + ); } }); From ebd1e8d1c78c68f7e7bf45e867f85032a4e25cbc Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 12 Sep 2023 13:34:23 +0100 Subject: [PATCH 118/199] Catch storage load exceptions in LazyConsumer --- .../providers/state_provider_notifier.dart | 30 +++++-------- uni/lib/view/lazy_consumer.dart | 45 +++++++++++++------ 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index d437089c2..beb4b7616 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -16,8 +16,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { this.dependsOnSession = true, RequestStatus initialStatus = RequestStatus.busy, bool initialize = true, - }) - : _initialStatus = initialStatus, + }) : _initialStatus = initialStatus, _status = initialStatus, _initializedFromStorage = !initialize, _initializedFromRemote = !initialize; @@ -54,10 +53,11 @@ abstract class StateProviderNotifier extends ChangeNotifier { Logger().i('Loaded $runtimeType info from storage'); } - Future _loadFromRemote(Session session, - Profile profile, { - bool force = false, - }) async { + Future _loadFromRemote( + Session session, + Profile profile, { + bool force = false, + }) async { Logger().d('Loading $runtimeType info from remote'); final shouldReload = force || @@ -113,19 +113,15 @@ abstract class StateProviderNotifier extends ChangeNotifier { const Duration(minutes: 1)) { Logger().w( 'Last update for $runtimeType was less than a minute ago; ' - 'skipping refresh', + 'skipping refresh', ); return; } final session = - Provider - .of(context, listen: false) - .session; + Provider.of(context, listen: false).session; final profile = - Provider - .of(context, listen: false) - .profile; + Provider.of(context, listen: false).profile; await _loadFromRemote(session, profile, force: true); }); @@ -148,13 +144,9 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromRemote = true; final session = - Provider - .of(context, listen: false) - .session; + Provider.of(context, listen: false).session; final profile = - Provider - .of(context, listen: false) - .profile; + Provider.of(context, listen: false).profile; await _loadFromRemote(session, profile); }); diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 40a39e2e5..c1cfe4add 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; +import 'package:sentry_flutter/sentry_flutter.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'; @@ -23,12 +24,20 @@ class LazyConsumer extends StatelessWidget { @override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) async { + StateProviderNotifier? provider; try { - final provider = Provider.of(context, listen: false); + provider = Provider.of(context, listen: false); + } catch (e) { + // The provider was not found. This should only happen in tests. + Logger().e('LazyConsumer: ${T.runtimeType} not found'); + return; + } - // If the provider fetchers depend on the session, make sure that - // SessionProvider and ProfileProvider are initialized - final sessionFuture = provider.dependsOnSession + // If the provider fetchers depend on the session, make sure that + // SessionProvider and ProfileProvider are initialized + Future? sessionFuture; + try { + sessionFuture = provider.dependsOnSession ? Provider.of(context, listen: false) .ensureInitialized(context) .then((_) async { @@ -36,20 +45,30 @@ class LazyConsumer extends StatelessWidget { .ensureInitialized(context); }) : Future(() {}); + } catch (e) { + Logger().e( + 'Failed to initialize startup providers: $e', + ); + await Sentry.captureException(e); + } - // Load data stored in the database immediately + // Load data stored in the database immediately + try { await provider.ensureInitializedFromStorage(); - - // Finally, complete provider initialization - if (context.mounted) { - await sessionFuture.then((_) async { - await provider.ensureInitializedFromRemote(context); - }); - } } catch (e) { Logger().e( - 'Failed to initialize $T: $e', + 'Failed to initialize ${T.runtimeType} from storage: $e', ); + await Sentry.captureException(e); + } + + // Finally, complete provider initialization + if (context.mounted) { + // This will fail if the session initialization failed. + // That is the expected behavior. + await sessionFuture!.then((_) async { + await provider!.ensureInitializedFromRemote(context); + }); } }); From d18a6ad6ef22680500dd65828d384c6311a7e56b Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 12 Sep 2023 13:49:15 +0100 Subject: [PATCH 119/199] Consider conditioned course units as valid --- uni/lib/model/entities/course_units/course_unit.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/lib/model/entities/course_units/course_unit.dart b/uni/lib/model/entities/course_units/course_unit.dart index 8ac041fd5..25bf40338 100644 --- a/uni/lib/model/entities/course_units/course_unit.dart +++ b/uni/lib/model/entities/course_units/course_unit.dart @@ -82,7 +82,7 @@ class CourseUnit { } bool enrollmentIsValid() { - return status == 'V'; + return status == 'V' || status == 'C'; } static String toSchoolYear(int year) { From e1026f0bb3e88d7de6ed780e711e45b2ade7c237 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Tue, 12 Sep 2023 13:57:25 +0100 Subject: [PATCH 120/199] Send stack trace to Sentry on provider error --- uni/lib/view/lazy_consumer.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index c1cfe4add..c1a15dcb3 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -45,21 +45,21 @@ class LazyConsumer extends StatelessWidget { .ensureInitialized(context); }) : Future(() {}); - } catch (e) { + } catch (exception, stackTrace) { Logger().e( - 'Failed to initialize startup providers: $e', + 'Failed to initialize startup providers: $exception', ); - await Sentry.captureException(e); + await Sentry.captureException(exception, stackTrace: stackTrace); } // Load data stored in the database immediately try { await provider.ensureInitializedFromStorage(); - } catch (e) { + } catch (exception, stackTrace) { Logger().e( - 'Failed to initialize ${T.runtimeType} from storage: $e', + 'Failed to initialize ${T.runtimeType} from storage: $exception', ); - await Sentry.captureException(e); + await Sentry.captureException(exception, stackTrace: stackTrace); } // Finally, complete provider initialization From a1cb407bc1d5d71929489e721869d508e87adaf5 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Tue, 12 Sep 2023 13:02:49 +0000 Subject: [PATCH 121/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 8ae44e95a..adf98caa0 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.61+179 \ No newline at end of file +1.5.62+180 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 0ae5d5616..b9b44c113 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.61+179 +version: 1.5.62+180 environment: sdk: '>=3.0.0 <4.0.0' From 7e8d915f419bf33c22d4b6c56ecfaf3b9bbc95cf Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 13 Sep 2023 11:57:43 +0100 Subject: [PATCH 122/199] Removing session provider --- uni/test/test_widget.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index a84960a72..1cae5ed12 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -5,7 +5,6 @@ import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; -import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/locale_notifier.dart'; Widget testableWidget( @@ -14,7 +13,6 @@ Widget testableWidget( }) { return MultiProvider( providers: [ - ChangeNotifierProvider(create: (context) => SessionProvider()), ChangeNotifierProvider(create: (context) => ProfileProvider()), ChangeNotifierProvider( create: (_) => LocaleNotifier(AppLocale.pt), From e7bae044207dabaf3e121848391ce9d2286176b7 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 13 Sep 2023 12:42:30 +0100 Subject: [PATCH 123/199] Do not log missing startup providers in testing mode --- uni/lib/view/lazy_consumer.dart | 13 +++++++++---- uni/test/integration/src/schedule_page_test.dart | 2 +- uni/test/test_widget.dart | 3 --- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index c1a15dcb3..49b19d748 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:logger/logger.dart'; @@ -46,10 +47,14 @@ class LazyConsumer extends StatelessWidget { }) : Future(() {}); } catch (exception, stackTrace) { - Logger().e( - 'Failed to initialize startup providers: $exception', - ); - await Sentry.captureException(exception, stackTrace: stackTrace); + // In tests, it is ok to not find the startup providers: + // all provider data should be mocked by the test itself. + if (!Platform.environment.containsKey('FLUTTER_TEST')) { + Logger().e( + 'Failed to initialize startup providers: $exception', + ); + await Sentry.captureException(exception, stackTrace: stackTrace); + } } // Load data stored in the database immediately diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index 12906429f..e775c86b2 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -58,7 +58,7 @@ void main() { final providers = [ ChangeNotifierProvider(create: (_) => scheduleProvider), - ChangeNotifierProvider(create: (_) => sessionProvider), + ChangeNotifierProvider(create: (_) => sessionProvider), ]; await tester.pumpWidget(testableWidget(widget, providers: providers)); diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 1cae5ed12..7cdac440c 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -3,8 +3,6 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/app_locale.dart'; - -import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/view/locale_notifier.dart'; Widget testableWidget( @@ -13,7 +11,6 @@ Widget testableWidget( }) { return MultiProvider( providers: [ - ChangeNotifierProvider(create: (context) => ProfileProvider()), ChangeNotifierProvider( create: (_) => LocaleNotifier(AppLocale.pt), ), From 4c232c95b64cae5e9042ec3f95b2359f8a7aba34 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 13 Sep 2023 15:10:06 +0100 Subject: [PATCH 124/199] Fix untranslated page titles --- uni/analysis_options.yaml | 1 + uni/lib/generated/intl/messages_all.dart | 36 ++-- uni/lib/generated/intl/messages_en.dart | 153 ++++++---------- uni/lib/generated/intl/messages_pt_PT.dart | 168 +++++++----------- uni/lib/generated/l10n.dart | 34 ++-- uni/lib/l10n/intl_en.arb | 6 +- uni/lib/l10n/intl_pt_PT.arb | 2 +- uni/lib/view/calendar/calendar.dart | 7 +- .../view/exams/widgets/exam_filter_form.dart | 12 +- uni/lib/view/locations/locations.dart | 9 +- .../view/restaurant/restaurant_page_view.dart | 5 +- 11 files changed, 182 insertions(+), 251 deletions(-) diff --git a/uni/analysis_options.yaml b/uni/analysis_options.yaml index 6acf469de..540e952da 100644 --- a/uni/analysis_options.yaml +++ b/uni/analysis_options.yaml @@ -5,6 +5,7 @@ analyzer: exclude: - "**.g.dart" - "**.mocks.dart" + - "**generated/**" # Custom linter rules. A list of all rules can be found at # https://dart-lang.github.io/linter/lints/options/options.html diff --git a/uni/lib/generated/intl/messages_all.dart b/uni/lib/generated/intl/messages_all.dart index 5c2bef3d1..b77f94db2 100644 --- a/uni/lib/generated/intl/messages_all.dart +++ b/uni/lib/generated/intl/messages_all.dart @@ -11,17 +11,18 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; -import 'package:uni/generated/intl/messages_en.dart' as messages_en; -import 'package:uni/generated/intl/messages_pt_PT.dart' as messages_pt_pt; +import 'messages_en.dart' as messages_en; +import 'messages_pt_PT.dart' as messages_pt_pt; typedef Future LibraryLoader(); Map _deferredLibraries = { - 'en': Future.value, - 'pt_PT': Future.value, + 'en': () => new SynchronousFuture(null), + 'pt_PT': () => new SynchronousFuture(null), }; MessageLookupByLibrary? _findExact(String localeName) { @@ -36,20 +37,18 @@ MessageLookupByLibrary? _findExact(String localeName) { } /// User programs should call this before using [localeName] for messages. -Future initializeMessages(String localeName) async { - final availableLocale = Intl.verifiedLocale( - localeName, - (locale) => _deferredLibraries[locale] != null, - onFailure: (_) => null, - ); +Future initializeMessages(String localeName) { + var availableLocale = Intl.verifiedLocale( + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { - return new Future.value(false); + return new SynchronousFuture(false); } - final lib = _deferredLibraries[availableLocale]; - await (lib == null ? new Future.value(false) : lib()); - initializeInternalMessageLookup(CompositeMessageLookup.new); + var lib = _deferredLibraries[availableLocale]; + lib == null ? new SynchronousFuture(false) : lib(); + initializeInternalMessageLookup(() => new CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); - return new Future.value(true); + return new SynchronousFuture(true); } bool _messagesExistFor(String locale) { @@ -61,11 +60,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - final actualLocale = Intl.verifiedLocale( - locale, - _messagesExistFor, - onFailure: (_) => null, - ); + var actualLocale = + Intl.verifiedLocale(locale, _messagesExistFor, onFailure: (_) => null); if (actualLocale == null) return null; return _findExact(actualLocale); } diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index eccb8f146..8df0e5ffd 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -4,10 +4,11 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; @@ -19,30 +20,26 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; - static String m0(dynamic time) => "last refresh at ${time}"; + static String m0(time) => "last refresh at ${time}"; - static String m1(dynamic time) => Intl.plural( - time as num, - zero: 'Refreshed ${time} minutes ago', - one: 'Refreshed ${time} minute ago', - other: 'Refreshed ${time} minutes ago', - ); + static String m1(time) => + "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - static String m2(String title) => Intl.select(title, { - 'horario': 'Schedule', - 'exames': 'Exams', - 'area': 'Personal Area', - 'cadeiras': 'Course Units', - 'autocarros': 'Buses', - 'locais': 'Places', - 'restaurantes': 'Restaurants', - 'calendario': 'Calendar', - 'biblioteca': 'Library', - 'uteis': 'Utils', - 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', - 'other': 'Other', - }); + static String m2(title) => "${Intl.select(title, { + 'horario': 'Schedule', + 'exames': 'Exams', + 'area': 'Personal Area', + 'cadeiras': 'Course Units', + 'autocarros': 'Buses', + 'locais': 'Places', + 'restaurantes': 'Restaurants', + 'calendario': 'Calendar', + 'biblioteca': 'Library', + 'uteis': 'Utils', + 'sobre': 'About', + 'bugs': 'Bugs/Suggestions', + 'other': 'Other', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -54,11 +51,9 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Add quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Add widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "By entering you confirm that you agree with these Terms and Conditions", - ), + "By entering you confirm that you agree with these Terms and Conditions"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "All available widgets have already been added to your personal area!", - ), + "All available widgets have already been added to your personal area!"), "at_least_one_college": MessageLookupByLibrary.simpleMessage("Select at least one college"), "available_amount": @@ -66,29 +61,23 @@ class MessageLookup extends MessageLookupByLibrary { "average": MessageLookupByLibrary.simpleMessage("Average: "), "balance": MessageLookupByLibrary.simpleMessage("Balance:"), "bs_description": MessageLookupByLibrary.simpleMessage( - r"Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!", - ), + "Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!"), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug found, how to reproduce it, etc.", - ), + "Bug found, how to reproduce it, etc."), "bus_error": MessageLookupByLibrary.simpleMessage("Unable to get information"), "bus_information": MessageLookupByLibrary.simpleMessage( - "Select the buses you want information about:", - ), + "Select the buses you want information about:"), "buses_personalize": MessageLookupByLibrary.simpleMessage("Personalize your buses here"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", - ), + "Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page."), "cancel": MessageLookupByLibrary.simpleMessage("Cancel"), "change": MessageLookupByLibrary.simpleMessage("Change"), "change_prompt": MessageLookupByLibrary.simpleMessage( - "Do you want to change the password?", - ), + "Do you want to change the password?"), "check_internet": MessageLookupByLibrary.simpleMessage( - "Check your internet connection", - ), + "Check your internet connection"), "class_registration": MessageLookupByLibrary.simpleMessage("Class Registration"), "college": MessageLookupByLibrary.simpleMessage("College: "), @@ -99,13 +88,11 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Configured Buses"), "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), "consent": MessageLookupByLibrary.simpleMessage( - "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request.", - ), + "I consent to this information being reviewed by NIAEFEUP and may be deleted at my request."), "contact": MessageLookupByLibrary.simpleMessage("Contact (optional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Copy center"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B | AEFEUP building", - ), + "Floor -1 of building B | AEFEUP building"), "course_class": MessageLookupByLibrary.simpleMessage("Classes"), "course_info": MessageLookupByLibrary.simpleMessage("Info"), "current_state": @@ -115,21 +102,18 @@ class MessageLookup extends MessageLookupByLibrary { "decrement": MessageLookupByLibrary.simpleMessage("Decrement 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Description"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email where you want to be contacted", - ), + "Email where you want to be contacted"), "dona_bia": MessageLookupByLibrary.simpleMessage( - "D. Beatriz's stationery store", - ), + "D. Beatriz\'s stationery store"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B (B-142)", - ), + "Floor -1 of building B (B-142)"), "ects": MessageLookupByLibrary.simpleMessage("ECTs performed: "), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "empty_text": MessageLookupByLibrary.simpleMessage("Please fill in this field"), "exams_filter": - MessageLookupByLibrary.simpleMessage("Exam Filter Settings"), + MessageLookupByLibrary.simpleMessage("Exams Filter Settings"), "expired_password": MessageLookupByLibrary.simpleMessage("Your password has expired"), "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), @@ -138,8 +122,7 @@ class MessageLookup extends MessageLookupByLibrary { "fee_notification": MessageLookupByLibrary.simpleMessage("Notify next deadline:"), "first_year_registration": MessageLookupByLibrary.simpleMessage( - "Year of first registration: ", - ), + "Year of first registration: "), "floor": MessageLookupByLibrary.simpleMessage("Floor"), "floors": MessageLookupByLibrary.simpleMessage("Floors"), "forgot_password": @@ -159,11 +142,9 @@ class MessageLookup extends MessageLookupByLibrary { "library_occupation": MessageLookupByLibrary.simpleMessage("Library Occupation"), "load_error": MessageLookupByLibrary.simpleMessage( - "Error loading the information", - ), + "Error loading the information"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Loading Terms and Conditions...", - ), + "Loading Terms and Conditions..."), "login": MessageLookupByLibrary.simpleMessage("Login"), "logout": MessageLookupByLibrary.simpleMessage("Log out"), "menus": MessageLookupByLibrary.simpleMessage("Menus"), @@ -173,59 +154,47 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("News"), - "no_bus": MessageLookupByLibrary.simpleMessage("Don't miss any bus!"), + "no_bus": MessageLookupByLibrary.simpleMessage("Don\'t miss any bus!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), "no_class": MessageLookupByLibrary.simpleMessage( - "There are no classes to display", - ), + "There are no classes to display"), "no_classes": MessageLookupByLibrary.simpleMessage("No classes to present"), "no_classes_on": - MessageLookupByLibrary.simpleMessage("You don't have classes on"), + MessageLookupByLibrary.simpleMessage("You don\'t have classes on"), "no_college": MessageLookupByLibrary.simpleMessage("no college"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "No course units in the selected period", - ), + "No course units in the selected period"), "no_data": MessageLookupByLibrary.simpleMessage( - "There is no data to show at this time", - ), + "There is no data to show at this time"), "no_date": MessageLookupByLibrary.simpleMessage("No date"), "no_exams": MessageLookupByLibrary.simpleMessage( - "You have no exams scheduled\n", - ), + "You have no exams scheduled\n"), "no_exams_label": MessageLookupByLibrary.simpleMessage( - "Looks like you are on vacation!", - ), + "Looks like you are on vacation!"), "no_favorite_restaurants": MessageLookupByLibrary.simpleMessage("No favorite restaurants"), "no_info": MessageLookupByLibrary.simpleMessage( - "There is no information to display", - ), + "There is no information to display"), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "There is no information available about meals", - ), + "There is no information available about meals"), "no_menus": MessageLookupByLibrary.simpleMessage( - "There are no meals available", - ), + "There are no meals available"), "no_name_course": MessageLookupByLibrary.simpleMessage("Unnamed course"), "no_references": MessageLookupByLibrary.simpleMessage( - "There are no references to pay", - ), + "There are no references to pay"), "no_results": MessageLookupByLibrary.simpleMessage("No match"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "There are no course units to display", - ), + "There are no course units to display"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "There are no exams to present", - ), + "There are no exams to present"), "occurrence_type": MessageLookupByLibrary.simpleMessage("Type of occurrence"), "other_links": MessageLookupByLibrary.simpleMessage("Other links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "For security reasons, passwords must be changed periodically.", - ), + "For security reasons, passwords must be changed periodically."), "password": MessageLookupByLibrary.simpleMessage("password"), "pendent_references": MessageLookupByLibrary.simpleMessage("Pending references"), @@ -236,14 +205,11 @@ class MessageLookup extends MessageLookupByLibrary { "print": MessageLookupByLibrary.simpleMessage("Print"), "prints": MessageLookupByLibrary.simpleMessage("Prints"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Brief identification of the problem", - ), + "Brief identification of the problem"), "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - r"The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account", - ), + "The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account"), "reference_success": MessageLookupByLibrary.simpleMessage( - "Reference created successfully!", - ), + "Reference created successfully!"), "remove": MessageLookupByLibrary.simpleMessage("Delete"), "report_error": MessageLookupByLibrary.simpleMessage("Report error"), "room": MessageLookupByLibrary.simpleMessage("Room"), @@ -252,8 +218,7 @@ class MessageLookup extends MessageLookupByLibrary { "semester": MessageLookupByLibrary.simpleMessage("Semester"), "send": MessageLookupByLibrary.simpleMessage("Send"), "sent_error": MessageLookupByLibrary.simpleMessage( - "An error occurred in sending", - ), + "An error occurred in sending"), "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), "stcp_stops": MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), @@ -263,8 +228,7 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Telephone assistance"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Face-to-face and telephone assistance", - ), + "Face-to-face and telephone assistance"), "telephone": MessageLookupByLibrary.simpleMessage("Telephone"), "terms": MessageLookupByLibrary.simpleMessage("Terms and Conditions"), "title": MessageLookupByLibrary.simpleMessage("Title"), @@ -272,8 +236,7 @@ class MessageLookup extends MessageLookupByLibrary { "valid_email": MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:", - ), + "Choose a widget to add to your personal area:"), "year": MessageLookupByLibrary.simpleMessage("Year") }; } diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 800ef819f..34347734b 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -4,10 +4,11 @@ // function name. // Ignore issues from commonly used lints in this file. -// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new, lines_longer_than_80_chars +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases -// ignore_for_file:unused_import, file_names +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; @@ -19,30 +20,26 @@ typedef String MessageIfAbsent(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'pt_PT'; - static String m0(dynamic time) => "última atualização às ${time}"; + static String m0(time) => "última atualização às ${time}"; - static String m1(dynamic time) => Intl.plural( - time as num, - zero: 'Atualizado há ${time} minutos', - one: 'Atualizado há ${time} minuto', - other: 'Atualizado há ${time} minutos', - ); + static String m1(time) => + "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static String m2(String title) => Intl.select(title, { - 'horario': 'Horário', - 'exames': 'Exames', - 'area': 'Área Pessoal', - 'cadeiras': 'Cadeiras', - 'autocarros': 'Autocarros', - 'locais': 'Locais', - 'restaurantes': 'Restaurantes', - 'calendario': 'Calendário', - 'biblioteca': 'Biblioteca', - 'uteis': 'Úteis', - 'sobre': 'Sobre', - 'bugs': 'Bugs e Sugestões', - 'other': 'Outros', - }); + static String m2(title) => "${Intl.select(title, { + 'horario': 'Horário', + 'exames': 'Exames', + 'area': 'Área Pessoal', + 'cadeiras': 'Cadeiras', + 'autocarros': 'Autocarros', + 'locais': 'Locais', + 'restaurantes': 'Restaurantes', + 'calendario': 'Calendário', + 'biblioteca': 'Biblioteca', + 'uteis': 'Úteis', + 'sobre': 'Sobre', + 'bugs': 'Bugs e Sugestões', + 'other': 'Outros', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); static Map _notInlinedMessages(_) => { @@ -54,62 +51,48 @@ class MessageLookup extends MessageLookupByLibrary { "add_quota": MessageLookupByLibrary.simpleMessage("Adicionar quota"), "add_widget": MessageLookupByLibrary.simpleMessage("Adicionar widget"), "agree_terms": MessageLookupByLibrary.simpleMessage( - "Ao entrares confirmas que concordas com estes Termos e Condições", - ), + "Ao entrares confirmas que concordas com estes Termos e Condições"), "all_widgets_added": MessageLookupByLibrary.simpleMessage( - "Todos os widgets disponíveis já foram adicionados à tua área pessoal!", - ), + "Todos os widgets disponíveis já foram adicionados à tua área pessoal!"), "at_least_one_college": MessageLookupByLibrary.simpleMessage( - "Seleciona pelo menos uma faculdade", - ), + "Seleciona pelo menos uma faculdade"), "available_amount": MessageLookupByLibrary.simpleMessage("Valor disponível"), "average": MessageLookupByLibrary.simpleMessage("Média: "), "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), "bs_description": MessageLookupByLibrary.simpleMessage( - r"Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!", - ), + "Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!"), "bug_description": MessageLookupByLibrary.simpleMessage( - "Bug encontrado, como o reproduzir, etc", - ), + "Bug encontrado, como o reproduzir, etc"), "bus_error": MessageLookupByLibrary.simpleMessage( - "Não foi possível obter informação", - ), + "Não foi possível obter informação"), "bus_information": MessageLookupByLibrary.simpleMessage( - "Seleciona os autocarros dos quais queres informação:", - ), + "Seleciona os autocarros dos quais queres informação:"), "buses_personalize": MessageLookupByLibrary.simpleMessage( - "Configura aqui os teus autocarros", - ), + "Configura aqui os teus autocarros"), "buses_text": MessageLookupByLibrary.simpleMessage( - "Os autocarros favoritos serão apresentados no widget 'Autocarros' dos favoritos. Os restantes serão apresentados apenas na página.", - ), + "Os autocarros favoritos serão apresentados no widget \'Autocarros\' dos favoritos. Os restantes serão apresentados apenas na página."), "cancel": MessageLookupByLibrary.simpleMessage("Cancelar\n"), "change": MessageLookupByLibrary.simpleMessage("Alterar"), "change_prompt": MessageLookupByLibrary.simpleMessage( - "Deseja alterar a palavra-passe?", - ), + "Deseja alterar a palavra-passe?"), "check_internet": MessageLookupByLibrary.simpleMessage( - "Verifica a tua ligação à internet", - ), + "Verifica a tua ligação à internet"), "class_registration": MessageLookupByLibrary.simpleMessage("Inscrição de Turmas"), "college": MessageLookupByLibrary.simpleMessage("Faculdade: "), "college_select": MessageLookupByLibrary.simpleMessage( - "seleciona a(s) tua(s) faculdade(s)", - ), + "seleciona a(s) tua(s) faculdade(s)"), "conclude": MessageLookupByLibrary.simpleMessage("Concluído"), "configured_buses": MessageLookupByLibrary.simpleMessage("Autocarros Configurados"), "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), "consent": MessageLookupByLibrary.simpleMessage( - "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido.", - ), + "Consinto que esta informação seja revista pelo NIAEFEUP, podendo ser eliminada a meu pedido."), "contact": MessageLookupByLibrary.simpleMessage("Contacto (opcional)"), "copy_center": MessageLookupByLibrary.simpleMessage("Centro de cópias"), "copy_center_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B | Edifício da AEFEUP", - ), + "Piso -1 do edifício B | Edifício da AEFEUP"), "course_class": MessageLookupByLibrary.simpleMessage("Turmas"), "course_info": MessageLookupByLibrary.simpleMessage("Ficha"), "current_state": MessageLookupByLibrary.simpleMessage("Estado atual: "), @@ -118,30 +101,25 @@ class MessageLookup extends MessageLookupByLibrary { "decrement": MessageLookupByLibrary.simpleMessage("Decrementar 1,00€"), "description": MessageLookupByLibrary.simpleMessage("Descrição"), "desired_email": MessageLookupByLibrary.simpleMessage( - "Email em que desejas ser contactado", - ), + "Email em que desejas ser contactado"), "dona_bia": MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B (B-142)", - ), + "Piso -1 do edifício B (B-142)"), "ects": MessageLookupByLibrary.simpleMessage("ECTs realizados: "), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( - "Por favor preenche este campo", - ), + "Por favor preenche este campo"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), "expired_password": MessageLookupByLibrary.simpleMessage("A tua palavra-passe expirou"), "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), "fee_date": MessageLookupByLibrary.simpleMessage( - "Data limite próxima prestação:", - ), + "Data limite próxima prestação:"), "fee_notification": MessageLookupByLibrary.simpleMessage( - "Notificar próxima data limite:", - ), + "Notificar próxima data limite:"), "first_year_registration": MessageLookupByLibrary.simpleMessage("Ano da primeira inscrição: "), "floor": MessageLookupByLibrary.simpleMessage("Piso"), @@ -164,11 +142,9 @@ class MessageLookup extends MessageLookupByLibrary { "library_occupation": MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), "load_error": MessageLookupByLibrary.simpleMessage( - "Aconteceu um erro ao carregar os dados", - ), + "Aconteceu um erro ao carregar os dados"), "loading_terms": MessageLookupByLibrary.simpleMessage( - "Carregando os Termos e Condições...", - ), + "Carregando os Termos e Condições..."), "login": MessageLookupByLibrary.simpleMessage("Entrar"), "logout": MessageLookupByLibrary.simpleMessage("Terminar sessão"), "menus": MessageLookupByLibrary.simpleMessage("Ementas"), @@ -179,26 +155,20 @@ class MessageLookup extends MessageLookupByLibrary { "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("Notícias"), "no_bus": MessageLookupByLibrary.simpleMessage( - "Não percas nenhum autocarro!", - ), + "Não percas nenhum autocarro!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage( - "Não existe nenhuma paragem configurada", - ), + "Não existe nenhuma paragem configurada"), "no_class": MessageLookupByLibrary.simpleMessage( - "Não existem turmas para apresentar", - ), + "Não existem turmas para apresentar"), "no_classes": MessageLookupByLibrary.simpleMessage( - "Não existem aulas para apresentar", - ), + "Não existem aulas para apresentar"), "no_classes_on": MessageLookupByLibrary.simpleMessage("Não possui aulas à"), "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), "no_course_units": MessageLookupByLibrary.simpleMessage( - "Sem cadeiras no período selecionado", - ), + "Sem cadeiras no período selecionado"), "no_data": MessageLookupByLibrary.simpleMessage( - "Não há dados a mostrar neste momento", - ), + "Não há dados a mostrar neste momento"), "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), "no_exams": MessageLookupByLibrary.simpleMessage("Não possui exames marcados"), @@ -207,51 +177,40 @@ class MessageLookup extends MessageLookupByLibrary { "no_favorite_restaurants": MessageLookupByLibrary.simpleMessage("Sem restaurantes favoritos"), "no_info": MessageLookupByLibrary.simpleMessage( - "Não existem informações para apresentar", - ), + "Não existem informações para apresentar"), "no_menu_info": MessageLookupByLibrary.simpleMessage( - "Não há informação disponível sobre refeições", - ), + "Não há informação disponível sobre refeições"), "no_menus": MessageLookupByLibrary.simpleMessage( - "Não há refeições disponíveis", - ), + "Não há refeições disponíveis"), "no_name_course": MessageLookupByLibrary.simpleMessage("Curso sem nome"), "no_references": MessageLookupByLibrary.simpleMessage( - "Não existem referências a pagar", - ), + "Não existem referências a pagar"), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), "no_selected_courses": MessageLookupByLibrary.simpleMessage( - "Não existem cadeiras para apresentar", - ), + "Não existem cadeiras para apresentar"), "no_selected_exams": MessageLookupByLibrary.simpleMessage( - "Não existem exames para apresentar", - ), + "Não existem exames para apresentar"), "occurrence_type": MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), "other_links": MessageLookupByLibrary.simpleMessage("Outros links"), "pass_change_request": MessageLookupByLibrary.simpleMessage( - "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", - ), + "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente."), "password": MessageLookupByLibrary.simpleMessage("palavra-passe"), "pendent_references": MessageLookupByLibrary.simpleMessage("Referências pendentes"), "personal_assistance": MessageLookupByLibrary.simpleMessage("Atendimento presencial"), "press_again": MessageLookupByLibrary.simpleMessage( - "Pressione novamente para sair", - ), + "Pressione novamente para sair"), "print": MessageLookupByLibrary.simpleMessage("Impressão"), "prints": MessageLookupByLibrary.simpleMessage("Impressões"), "problem_id": MessageLookupByLibrary.simpleMessage( - "Breve identificação do problema", - ), + "Breve identificação do problema"), "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - r"Os dados da referência gerada aparecerão no Sigarra, conta corrente.\nPerfil > Conta Corrente", - ), + "Os dados da referência gerada aparecerão no Sigarra, conta corrente.\\nPerfil > Conta Corrente"), "reference_success": MessageLookupByLibrary.simpleMessage( - "Referência criada com sucesso!", - ), + "Referência criada com sucesso!"), "remove": MessageLookupByLibrary.simpleMessage("Remover"), "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), "room": MessageLookupByLibrary.simpleMessage("Sala"), @@ -270,18 +229,15 @@ class MessageLookup extends MessageLookupByLibrary { "tele_assistance": MessageLookupByLibrary.simpleMessage("Atendimento telefónico"), "tele_personal_assistance": MessageLookupByLibrary.simpleMessage( - "Atendimento presencial e telefónico", - ), + "Atendimento presencial e telefónico"), "telephone": MessageLookupByLibrary.simpleMessage("Telefone"), "terms": MessageLookupByLibrary.simpleMessage("Termos e Condições"), "title": MessageLookupByLibrary.simpleMessage("Título"), "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), "valid_email": MessageLookupByLibrary.simpleMessage( - "Por favor insere um email válido", - ), + "Por favor insere um email válido"), "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:", - ), + "Escolhe um widget para adicionares à tua área pessoal:"), "year": MessageLookupByLibrary.simpleMessage("Ano") }; } diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 3a2aec795..a1b6550a3 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import 'package:uni/generated/intl/messages_all.dart'; +import 'intl/messages_all.dart'; // ************************************************************************** // Generator: Flutter Intl IDE plugin @@ -10,7 +10,7 @@ import 'package:uni/generated/intl/messages_all.dart'; // ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars // ignore_for_file: join_return_with_assignment, prefer_final_in_for_each -// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_redundant_argument_values, avoid_escaping_inner_quotes class S { S(); @@ -18,10 +18,8 @@ class S { static S? _current; static S get current { - assert( - _current != null, - 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.', - ); + assert(_current != null, + 'No instance of S was loaded. Try to initialize the S delegate before accessing S.current.'); return _current!; } @@ -43,10 +41,8 @@ class S { static S of(BuildContext context) { final instance = S.maybeOf(context); - assert( - instance != null, - 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?', - ); + assert(instance != null, + 'No instance of S present in the widget tree. Did you add S.delegate in localizationsDelegates?'); return instance!; } @@ -207,7 +203,7 @@ class S { /// `Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.` String get buses_text { return Intl.message( - "Favorite buses will be displayed in the favorites 'Bus' widget. The remaining ones will only be displayed on the page.", + 'Favorite buses will be displayed in the favorites \'Bus\' widget. The remaining ones will only be displayed on the page.', name: 'buses_text', desc: '', args: [], @@ -437,7 +433,7 @@ class S { /// `D. Beatriz's stationery store` String get dona_bia { return Intl.message( - "D. Beatriz's stationery store", + 'D. Beatriz\'s stationery store', name: 'dona_bia', desc: '', args: [], @@ -494,10 +490,10 @@ class S { ); } - /// `Exam Filter Settings` + /// `Exams Filter Settings` String get exams_filter { return Intl.message( - 'Exam Filter Settings', + 'Exams Filter Settings', name: 'exams_filter', desc: '', args: [], @@ -747,7 +743,7 @@ class S { ); } - /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}` + /// `{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/Suggestions} other{Other}}` String nav_title(Object title) { return Intl.select( title, @@ -763,7 +759,7 @@ class S { 'biblioteca': 'Library', 'uteis': 'Utils', 'sobre': 'About', - 'bugs': 'Bugs/ Suggestions', + 'bugs': 'Bugs/Suggestions', 'other': 'Other', }, name: 'nav_title', @@ -785,7 +781,7 @@ class S { /// `Don't miss any bus!` String get no_bus { return Intl.message( - "Don't miss any bus!", + 'Don\'t miss any bus!', name: 'no_bus', desc: '', args: [], @@ -825,7 +821,7 @@ class S { /// `You don't have classes on` String get no_classes_on { return Intl.message( - "You don't have classes on", + 'You don\'t have classes on', name: 'no_classes_on', desc: '', args: [], @@ -1085,7 +1081,7 @@ class S { /// `The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account` String get reference_sigarra_help { return Intl.message( - 'The generated reference data will appear in Sigarra, checking account.\nProfile > Checking Account', + 'The generated reference data will appear in Sigarra, checking account.\\nProfile > Checking Account', name: 'reference_sigarra_help', desc: '', args: [], diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 12a47bfbc..e856e2123 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -22,7 +22,7 @@ "@average": {}, "balance": "Balance:", "@balance": {}, - "bs_description": "Did you find any bugs in the application?\\nDo you have any suggestions for the app?\\nTell us so we can improve!", + "bs_description": "Did you find any bugs in the application?\nDo you have any suggestions for the app?\nTell us so we can improve!", "@bs_description": {}, "bug_description": "Bug found, how to reproduce it, etc.", "@bug_description": {}, @@ -88,7 +88,7 @@ "@edit_on": {}, "empty_text": "Please fill in this field", "@empty_text": {}, - "exams_filter": "Exam Filter Settings", + "exams_filter": "Exams Filter Settings", "@exams_filter": {}, "expired_password": "Your password has expired", "@expired_password": {}, @@ -146,7 +146,7 @@ "@min_value_reference": {}, "multimedia_center": "Multimedia center", "@multimedia_center": {}, - "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/ Suggestions} other{Other}}", + "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} sobre{About} bugs{Bugs/Suggestions} other{Other}}", "@nav_title": {}, "news": "News", "@news": {}, diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index ad8d0790d..16ac83f09 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -22,7 +22,7 @@ "@average": {}, "balance": "Saldo:", "@balance": {}, - "bs_description": "Encontraste algum bug na aplicação?\\nTens alguma sugestão para a app?\\nConta-nos para que possamos melhorar!", + "bs_description": "Encontraste algum bug na aplicação?\nTens alguma sugestão para a app?\nConta-nos para que possamos melhorar!", "@bs_description": {}, "bug_description": "Bug encontrado, como o reproduzir, etc", "@bug_description": {}, diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 4e4f3ed83..90d5ce2ff 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -3,12 +3,15 @@ import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; +import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/calendar/widgets/calendar_tile.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 '../../generated/l10n.dart'; + class CalendarPageView extends StatefulWidget { const CalendarPageView({super.key}); @@ -24,7 +27,9 @@ class CalendarPageViewState extends GeneralPageViewState { children: [ Container( padding: const EdgeInsets.only(bottom: 6), - child: const PageTitle(name: 'Calendário Escolar'), + child: PageTitle( + name: S.of(context).nav_title(DrawerItem.navCalendar.title), + ), ), RequestDependentWidgetBuilder( status: calendarProvider.status, diff --git a/uni/lib/view/exams/widgets/exam_filter_form.dart b/uni/lib/view/exams/widgets/exam_filter_form.dart index 91a1483aa..baf86edfb 100644 --- a/uni/lib/view/exams/widgets/exam_filter_form.dart +++ b/uni/lib/view/exams/widgets/exam_filter_form.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; class ExamFilterForm extends StatefulWidget { const ExamFilterForm(this.filteredExamsTypes, {super.key}); + final Map filteredExamsTypes; @override @@ -16,17 +18,19 @@ class ExamFilterFormState extends State { Widget build(BuildContext context) { return AlertDialog( title: Text( - 'Definições Filtro de Exames', + S.of(context).exams_filter, style: Theme.of(context).textTheme.headlineSmall, ), actions: [ TextButton( - child: - Text('Cancelar', style: Theme.of(context).textTheme.bodyMedium), + child: Text( + S.of(context).cancel, + style: Theme.of(context).textTheme.bodyMedium, + ), onPressed: () => Navigator.pop(context), ), ElevatedButton( - child: const Text('Confirmar'), + child: Text(S.of(context).confirm), onPressed: () { Provider.of(context, listen: false) .setFilteredExams(widget.filteredExamsTypes); diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index 777647ac2..b072e673b 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -8,6 +8,9 @@ import 'package:uni/view/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/lazy_consumer.dart'; import 'package:uni/view/locations/widgets/faculty_map.dart'; +import '../../generated/l10n.dart'; +import '../../utils/drawer_items.dart'; + class LocationsPage extends StatefulWidget { const LocationsPage({super.key}); @@ -46,6 +49,7 @@ class LocationsPageView extends StatelessWidget { required this.status, super.key, }); + final List locations; final RequestStatus status; @@ -56,7 +60,10 @@ class LocationsPageView extends StatelessWidget { Container( width: MediaQuery.of(context).size.width * 0.95, padding: const EdgeInsets.fromLTRB(0, 0, 0, 4), - child: PageTitle(name: 'Locais: ${getLocation()}'), + child: PageTitle( + name: '${S.of(context).nav_title(DrawerItem.navLocations.title)}:' + ' ${getLocation()}', + ), ), Container( padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), diff --git a/uni/lib/view/restaurant/restaurant_page_view.dart b/uni/lib/view/restaurant/restaurant_page_view.dart index 0d74bad07..80a1c96b5 100644 --- a/uni/lib/view/restaurant/restaurant_page_view.dart +++ b/uni/lib/view/restaurant/restaurant_page_view.dart @@ -5,6 +5,7 @@ import 'package:uni/model/entities/meal.dart'; import 'package:uni/model/entities/restaurant.dart'; import 'package:uni/model/providers/lazy/restaurant_provider.dart'; import 'package:uni/model/utils/day_of_week.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'; @@ -49,7 +50,9 @@ class _RestaurantPageViewState extends GeneralPageViewState padding: const EdgeInsets.fromLTRB(20, 20, 20, 10), alignment: Alignment.center, child: PageTitle( - name: S.of(context).menus, + name: S + .of(context) + .nav_title(DrawerItem.navRestaurants.title), center: false, pad: false, ), From a2865e8a11a22805fef55004b5e0db00d19ee91c Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 13 Sep 2023 15:25:17 +0100 Subject: [PATCH 125/199] Add missing translations --- uni/lib/generated/intl/messages_en.dart | 8 +++- uni/lib/generated/intl/messages_pt_PT.dart | 8 +++- uni/lib/generated/l10n.dart | 40 +++++++++++++++++++ uni/lib/l10n/intl_en.arb | 8 ++++ uni/lib/l10n/intl_pt_PT.arb | 8 ++++ uni/lib/view/calendar/calendar.dart | 3 +- .../view/home/widgets/exit_app_dialog.dart | 7 ++-- .../view/home/widgets/restaurant_card.dart | 2 +- uni/lib/view/locations/locations.dart | 8 ++-- uni/lib/view/locations/widgets/map.dart | 3 +- .../view/locations/widgets/marker_popup.dart | 8 +++- 11 files changed, 88 insertions(+), 15 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 8df0e5ffd..7c9d65e6c 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -114,6 +114,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Please fill in this field"), "exams_filter": MessageLookupByLibrary.simpleMessage("Exams Filter Settings"), + "exit_confirm": + MessageLookupByLibrary.simpleMessage("Do you really want to exit?"), "expired_password": MessageLookupByLibrary.simpleMessage("Your password has expired"), "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), @@ -154,6 +156,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Multimedia center"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("News"), + "no": MessageLookupByLibrary.simpleMessage("No"), "no_bus": MessageLookupByLibrary.simpleMessage("Don\'t miss any bus!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage("No configured stops"), @@ -183,6 +186,8 @@ class MessageLookup extends MessageLookupByLibrary { "There are no meals available"), "no_name_course": MessageLookupByLibrary.simpleMessage("Unnamed course"), + "no_places_info": MessageLookupByLibrary.simpleMessage( + "There is no information available about places"), "no_references": MessageLookupByLibrary.simpleMessage( "There are no references to pay"), "no_results": MessageLookupByLibrary.simpleMessage("No match"), @@ -237,6 +242,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Please enter a valid email"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Choose a widget to add to your personal area:"), - "year": MessageLookupByLibrary.simpleMessage("Year") + "year": MessageLookupByLibrary.simpleMessage("Year"), + "yes": MessageLookupByLibrary.simpleMessage("Yes") }; } diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index 34347734b..c86c90267 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -113,6 +113,8 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor preenche este campo"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), + "exit_confirm": MessageLookupByLibrary.simpleMessage( + "Tem a certeza de que pretende sair?"), "expired_password": MessageLookupByLibrary.simpleMessage("A tua palavra-passe expirou"), "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), @@ -154,6 +156,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Centro de multimédia"), "nav_title": m2, "news": MessageLookupByLibrary.simpleMessage("Notícias"), + "no": MessageLookupByLibrary.simpleMessage("Não"), "no_bus": MessageLookupByLibrary.simpleMessage( "Não percas nenhum autocarro!"), "no_bus_stops": MessageLookupByLibrary.simpleMessage( @@ -184,6 +187,8 @@ class MessageLookup extends MessageLookupByLibrary { "Não há refeições disponíveis"), "no_name_course": MessageLookupByLibrary.simpleMessage("Curso sem nome"), + "no_places_info": MessageLookupByLibrary.simpleMessage( + "Não há informação disponível sobre locais"), "no_references": MessageLookupByLibrary.simpleMessage( "Não existem referências a pagar"), "no_results": MessageLookupByLibrary.simpleMessage("Sem resultados"), @@ -238,6 +243,7 @@ class MessageLookup extends MessageLookupByLibrary { "Por favor insere um email válido"), "widget_prompt": MessageLookupByLibrary.simpleMessage( "Escolhe um widget para adicionares à tua área pessoal:"), - "year": MessageLookupByLibrary.simpleMessage("Ano") + "year": MessageLookupByLibrary.simpleMessage("Ano"), + "yes": MessageLookupByLibrary.simpleMessage("Sim") }; } diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index a1b6550a3..804bd1400 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -50,6 +50,36 @@ class S { return Localizations.of(context, S); } + /// `Do you really want to exit?` + String get exit_confirm { + return Intl.message( + 'Do you really want to exit?', + name: 'exit_confirm', + desc: '', + args: [], + ); + } + + /// `No` + String get no { + return Intl.message( + 'No', + name: 'no', + desc: '', + args: [], + ); + } + + /// `Yes` + String get yes { + return Intl.message( + 'Yes', + name: 'yes', + desc: '', + args: [], + ); + } + /// `Academic services` String get academic_services { return Intl.message( @@ -918,6 +948,16 @@ class S { ); } + /// `There is no information available about places` + String get no_places_info { + return Intl.message( + 'There is no information available about places', + name: 'no_places_info', + desc: '', + args: [], + ); + } + /// `There are no meals available` String get no_menus { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index e856e2123..acc5d7b7c 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -1,5 +1,11 @@ { "@@locale": "en", + "exit_confirm": "Do you really want to exit?", + "@exit_confirm": {}, + "no": "No", + "@no": {}, + "yes": "Yes", + "@yes": {}, "academic_services": "Academic services", "@academic_services": {}, "account_card_title": "Checking account", @@ -178,6 +184,8 @@ "@no_info": {}, "no_menu_info": "There is no information available about meals", "@no_menu_info": {}, + "no_places_info": "There is no information available about places", + "@no_places_info": {}, "no_menus": "There are no meals available", "@no_menus": {}, "no_name_course": "Unnamed course", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 16ac83f09..7552ae5c3 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -1,5 +1,11 @@ { "@@locale": "pt_PT", + "exit_confirm": "Tem a certeza de que pretende sair?", + "@exit_confirm": {}, + "no": "Não", + "@no": {}, + "yes": "Sim", + "@yes": {}, "academic_services": "Serviços académicos", "@academic_services": {}, "account_card_title": "Conta Corrente", @@ -178,6 +184,8 @@ "@no_info": {}, "no_menu_info": "Não há informação disponível sobre refeições", "@no_menu_info": {}, + "no_places_info": "Não há informação disponível sobre locais", + "@no_places_info": {}, "no_menus": "Não há refeições disponíveis", "@no_menus": {}, "no_name_course": "Curso sem nome", diff --git a/uni/lib/view/calendar/calendar.dart b/uni/lib/view/calendar/calendar.dart index 90d5ce2ff..5e5e79b68 100644 --- a/uni/lib/view/calendar/calendar.dart +++ b/uni/lib/view/calendar/calendar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:timelines/timelines.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/calendar_event.dart'; import 'package:uni/model/providers/lazy/calendar_provider.dart'; import 'package:uni/utils/drawer_items.dart'; @@ -10,8 +11,6 @@ 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 '../../generated/l10n.dart'; - class CalendarPageView extends StatefulWidget { const CalendarPageView({super.key}); diff --git a/uni/lib/view/home/widgets/exit_app_dialog.dart b/uni/lib/view/home/widgets/exit_app_dialog.dart index 58be3e236..fe6ed0ab5 100644 --- a/uni/lib/view/home/widgets/exit_app_dialog.dart +++ b/uni/lib/view/home/widgets/exit_app_dialog.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:uni/generated/l10n.dart'; /// Manages the app section displayed when the user presses the back button class BackButtonExitWrapper extends StatelessWidget { @@ -17,18 +18,18 @@ class BackButtonExitWrapper extends StatelessWidget { context: context, builder: (context) => AlertDialog( title: Text( - 'Tens a certeza de que pretendes sair?', + S.of(context).exit_confirm, style: Theme.of(context).textTheme.headlineSmall, ), actions: [ ElevatedButton( onPressed: () => Navigator.of(context).pop(false), - child: const Text('Não'), + child: Text(S.of(context).no), ), ElevatedButton( onPressed: () => SystemChannels.platform.invokeMethod('SystemNavigator.pop'), - child: const Text('Sim'), + child: Text(S.of(context).yes), ) ], ), diff --git a/uni/lib/view/home/widgets/restaurant_card.dart b/uni/lib/view/home/widgets/restaurant_card.dart index 77eacada5..ea23dc5be 100644 --- a/uni/lib/view/home/widgets/restaurant_card.dart +++ b/uni/lib/view/home/widgets/restaurant_card.dart @@ -139,7 +139,7 @@ class RestaurantCard extends GenericCard { child: Container( padding: const EdgeInsets.fromLTRB(9, 0, 0, 0), width: 400, - child: const Text('Não há refeições disponíveis'), + child: Text(S.of(context).no_menu_info), ), ), ) diff --git a/uni/lib/view/locations/locations.dart b/uni/lib/view/locations/locations.dart index b072e673b..f722cc7dd 100644 --- a/uni/lib/view/locations/locations.dart +++ b/uni/lib/view/locations/locations.dart @@ -1,16 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/location_group.dart'; import 'package:uni/model/providers/lazy/faculty_locations_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/locations/widgets/faculty_map.dart'; -import '../../generated/l10n.dart'; -import '../../utils/drawer_items.dart'; - class LocationsPage extends StatefulWidget { const LocationsPage({super.key}); @@ -73,8 +72,7 @@ class LocationsPageView extends StatelessWidget { status: status, builder: () => FacultyMap(faculty: 'FEUP', locations: locations), hasContentPredicate: locations.isNotEmpty, - onNullContent: - const Center(child: Text('Não existem locais disponíveis')), + onNullContent: Center(child: Text(S.of(context).no_places_info)), ), // TODO(bdmendes): add support for multiple faculties ) diff --git a/uni/lib/view/locations/widgets/map.dart b/uni/lib/view/locations/widgets/map.dart index f810d1a3a..1cb1b3365 100644 --- a/uni/lib/view/locations/widgets/map.dart +++ b/uni/lib/view/locations/widgets/map.dart @@ -17,6 +17,7 @@ class LocationsMap extends StatelessWidget { required this.locations, super.key, }); + final PopupController _popupLayerController = PopupController(); final List locations; final LatLng northEastBoundary; @@ -78,7 +79,7 @@ class LocationsMap extends StatelessWidget { ? FloorlessLocationMarkerPopup(marker.locationGroup) : LocationMarkerPopup(marker.locationGroup); } - return const Card(child: Text('undefined')); + return const Card(child: Text('')); }, ), ), diff --git a/uni/lib/view/locations/widgets/marker_popup.dart b/uni/lib/view/locations/widgets/marker_popup.dart index a683f613b..068bae2d6 100644 --- a/uni/lib/view/locations/widgets/marker_popup.dart +++ b/uni/lib/view/locations/widgets/marker_popup.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/location.dart'; import 'package:uni/model/entities/location_group.dart'; import 'package:uni/view/locations/widgets/faculty_map.dart'; @@ -46,6 +47,7 @@ class LocationMarkerPopup extends StatelessWidget { class Floor extends StatelessWidget { const Floor({required this.locations, required this.floor, super.key}); + final List locations; final int floor; @@ -62,7 +64,10 @@ class Floor extends StatelessWidget { children: [ Container( padding: const EdgeInsets.fromLTRB(8, 0, 8, 0), - child: Text('Andar $floorString', style: TextStyle(color: fontColor)), + child: Text( + '${S.of(context).floor} $floorString', + style: TextStyle(color: fontColor), + ), ) ], ); @@ -86,6 +91,7 @@ class Floor extends StatelessWidget { class LocationRow extends StatelessWidget { const LocationRow({required this.location, required this.color, super.key}); + final Location location; final Color color; From c8ecb5d5212b73f1539093c04c45f8bda73f1ea5 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 13 Sep 2023 21:42:20 +0100 Subject: [PATCH 126/199] Add intl documentation --- uni/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/uni/README.md b/uni/README.md index 200d3c193..a4904acf7 100644 --- a/uni/README.md +++ b/uni/README.md @@ -46,6 +46,16 @@ But you can also watch for changes in `.dart` files and automatically run the `b dart run build_runner watch ``` +## Translation files + +Intl package allows the internationalization of the app, currently supporting Portuguese ('pt_PT') and English ('en_EN). This package creates `.arb` files (one for each language), mapping a key to the correspondent translated string. +In order to access those translations through getters, you must add the translations you want to the `.arb` files and run: +``` +dart pub global run intl_utils:generate +``` +This will generate `.dart` files with the getters you need to access the translations. +You must include `'package:uni/generated/l10n.dart'` and, depending on the locale of the application, `S.of(context).{key_of_translation}` will get you the translated string. + ## Project structure ### Overview From 10a3f33edb58442fbe097922a01955eac087a2d1 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 18 Sep 2023 16:08:07 +0100 Subject: [PATCH 127/199] Fixing test error --- uni/test/integration/src/exams_page_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index 44622790c..0035361dc 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -154,7 +154,7 @@ void main() { await tester.tap(find.byWidget(mtCheckboxTile)); await tester.pumpAndSettle(); - final okButton = find.widgetWithText(ElevatedButton, 'Confirmar'); + final okButton = find.widgetWithText(ElevatedButton, 'Confirm'); expect(okButton, findsOneWidget); await tester.tap(okButton); From 2e04b642a7a34ff9e0508a5c92e572e26ff2ec55 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 18 Sep 2023 16:15:23 +0100 Subject: [PATCH 128/199] Changing testable widget locale --- uni/test/integration/src/exams_page_test.dart | 2 +- uni/test/test_widget.dart | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index 0035361dc..44622790c 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -154,7 +154,7 @@ void main() { await tester.tap(find.byWidget(mtCheckboxTile)); await tester.pumpAndSettle(); - final okButton = find.widgetWithText(ElevatedButton, 'Confirm'); + final okButton = find.widgetWithText(ElevatedButton, 'Confirmar'); expect(okButton, findsOneWidget); await tester.tap(okButton); diff --git a/uni/test/test_widget.dart b/uni/test/test_widget.dart index 7cdac440c..b710b524a 100644 --- a/uni/test/test_widget.dart +++ b/uni/test/test_widget.dart @@ -28,6 +28,7 @@ Widget wrapWidget(Widget widget) { GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], + locale: const Locale('pt'), supportedLocales: S.delegate.supportedLocales, home: Scaffold( body: widget, From 263f2d274f35154de231c8592026ae7510a690ac Mon Sep 17 00:00:00 2001 From: bdmendes Date: Tue, 19 Sep 2023 10:07:48 +0000 Subject: [PATCH 129/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index adf98caa0..d280932d9 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.62+180 \ No newline at end of file +1.5.63+181 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index de303dbde..d00c17a78 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.62+180 +version: 1.5.63+181 environment: sdk: '>=3.0.0 <4.0.0' From 4906c4688d6a200cf72b2ba22cf1d3715921c30d Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 20 Sep 2023 16:15:29 +0100 Subject: [PATCH 130/199] Fix status parsing of multiple year UCs --- .../controller/parsers/parser_course_units.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/parsers/parser_course_units.dart b/uni/lib/controller/parsers/parser_course_units.dart index 179ba7b77..bd103ad09 100644 --- a/uni/lib/controller/parsers/parser_course_units.dart +++ b/uni/lib/controller/parsers/parser_course_units.dart @@ -59,14 +59,19 @@ List parseCourseUnitsAndCourseAverage( if (row.children.length <= 6 + i) { break; } - yearIncrement++; - grade = row.children[6 + i].innerHtml.replaceAll(' ', ' ').trim(); - status = row.children[7 + i].innerHtml.replaceAll(' ', ' ').trim(); - if (status != '') { + final candidateStatus = + row.children[7 + i].innerHtml.replaceAll(' ', ' ').trim(); + if (status != null && candidateStatus.isEmpty) { break; } + yearIncrement++; + if (candidateStatus.isNotEmpty) { + grade = row.children[6 + i].innerHtml.replaceAll(' ', ' ').trim(); + status = candidateStatus; + } } - if (yearIncrement < 0) { + + if (status == null) { continue; } From b15861a97cb1ebf575eebf9331ddbe7fd244235d Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 20 Sep 2023 17:44:15 +0100 Subject: [PATCH 131/199] Use different models for different occurrences --- .../parsers/parser_course_units.dart | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/uni/lib/controller/parsers/parser_course_units.dart b/uni/lib/controller/parsers/parser_course_units.dart index bd103ad09..8131dc51b 100644 --- a/uni/lib/controller/parsers/parser_course_units.dart +++ b/uni/lib/controller/parsers/parser_course_units.dart @@ -52,42 +52,36 @@ List parseCourseUnitsAndCourseAverage( final codeName = row.children[2].children[0].innerHtml; final name = row.children[3].children[0].innerHtml; final ects = row.children[5].innerHtml.replaceAll(',', '.'); - String? grade; - String? status; + var yearIncrement = -1; for (var i = 0;; i += 2) { if (row.children.length <= 6 + i) { break; } - final candidateStatus = - row.children[7 + i].innerHtml.replaceAll(' ', ' ').trim(); - if (status != null && candidateStatus.isEmpty) { - break; - } yearIncrement++; - if (candidateStatus.isNotEmpty) { - grade = row.children[6 + i].innerHtml.replaceAll(' ', ' ').trim(); - status = candidateStatus; + final status = + row.children[7 + i].innerHtml.replaceAll(' ', ' ').trim(); + final grade = + row.children[6 + i].innerHtml.replaceAll(' ', ' ').trim(); + + if (status.isEmpty) { + continue; } - } - if (status == null) { - continue; + final courseUnit = CourseUnit( + schoolYear: + '${firstSchoolYear + yearIncrement}/${firstSchoolYear + yearIncrement + 1}', + occurrId: int.parse(occurId), + abbreviation: codeName, + status: status, + grade: grade, + ects: double.parse(ects), + name: name, + curricularYear: int.parse(year), + semesterCode: semester, + ); + courseUnits.add(courseUnit); } - - final courseUnit = CourseUnit( - schoolYear: - '${firstSchoolYear + yearIncrement}/${firstSchoolYear + yearIncrement + 1}', - occurrId: int.parse(occurId), - abbreviation: codeName, - status: status, - grade: grade, - ects: double.parse(ects), - name: name, - curricularYear: int.parse(year), - semesterCode: semester, - ); - courseUnits.add(courseUnit); } return courseUnits; From 6e3ec9600912f5486ceeee9ce72d9c48f162fb8e Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Wed, 20 Sep 2023 19:20:13 +0000 Subject: [PATCH 132/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index d280932d9..7ebc9097f 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.63+181 \ No newline at end of file +1.5.64+182 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index d00c17a78..d1c137447 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.63+181 +version: 1.5.64+182 environment: sdk: '>=3.0.0 <4.0.0' From aae1f6fefdfcb3cfc299a707edd3da1c654bbe9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:29:50 +0000 Subject: [PATCH 133/199] Bump very_good_analysis from 4.0.0+1 to 5.1.0 in /uni Bumps [very_good_analysis](https://github.com/VeryGoodOpenSource/very_good_analysis) from 4.0.0+1 to 5.1.0. - [Release notes](https://github.com/VeryGoodOpenSource/very_good_analysis/releases) - [Changelog](https://github.com/VeryGoodOpenSource/very_good_analysis/blob/main/CHANGELOG.md) - [Commits](https://github.com/VeryGoodOpenSource/very_good_analysis/compare/v4.0.0...v5.1.0) --- updated-dependencies: - dependency-name: very_good_analysis dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- uni/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index d1c137447..76875e25c 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -68,7 +68,7 @@ dev_dependencies: url: https://github.com/dart-lang/mockito.git ref: "e54a006" test: any - very_good_analysis: ^4.0.0+1 + very_good_analysis: ^5.1.0 flutter: generate: true From 610751ef1893a5ba34401012c6b8212ac5545dae Mon Sep 17 00:00:00 2001 From: bdmendes Date: Fri, 22 Sep 2023 07:46:00 +0000 Subject: [PATCH 134/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 7ebc9097f..8f2c3c19e 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.64+182 \ No newline at end of file +1.5.65+183 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 76875e25c..51a32fd64 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.64+182 +version: 1.5.65+183 environment: sdk: '>=3.0.0 <4.0.0' From 3b4397ea44a54474d714bdfc2c70acffa9224084 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 23 Sep 2023 11:28:30 +0100 Subject: [PATCH 135/199] Bump encrypt version --- uni/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 51a32fd64..944950dc9 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: cupertino_icons: ^1.0.2 currency_text_input_formatter: ^2.1.5 email_validator: ^2.0.1 - encrypt: ^5.0.0-beta.1 + encrypt: ^5.0.3 expansion_tile_card: ^3.0.0 flutter: sdk: flutter From 09f3191ca00c01cc6d48ca573d7707c8a7de6b1f Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 23 Sep 2023 12:40:53 +0100 Subject: [PATCH 136/199] Use same key for encryption purposes --- .../background_workers/notifications.dart | 4 ++ .../local_storage/app_shared_preferences.dart | 38 +++++++++---------- .../controller/networking/network_router.dart | 7 ++++ uni/lib/main.dart | 4 +- .../model/providers/lazy/exam_provider.dart | 12 +++--- .../providers/lazy/lecture_provider.dart | 8 ++-- .../providers/startup/profile_provider.dart | 8 ++-- .../providers/startup/session_provider.dart | 5 +++ .../view/common_widgets/page_transition.dart | 9 ----- uni/lib/view/login/login.dart | 2 + uni/lib/view/terms_and_condition_dialog.dart | 7 +--- uni/test/integration/src/exams_page_test.dart | 5 +-- .../integration/src/schedule_page_test.dart | 3 +- .../unit/providers/exams_provider_test.dart | 17 ++++----- .../unit/providers/lecture_provider_test.dart | 6 +-- 15 files changed, 65 insertions(+), 70 deletions(-) diff --git a/uni/lib/controller/background_workers/notifications.dart b/uni/lib/controller/background_workers/notifications.dart index f6c7f52f8..b09b0365a 100644 --- a/uni/lib/controller/background_workers/notifications.dart +++ b/uni/lib/controller/background_workers/notifications.dart @@ -71,6 +71,10 @@ class NotificationManager { final userInfo = await AppSharedPreferences.getPersistentUserInfo(); final faculties = await AppSharedPreferences.getUserFaculties(); + if (userInfo == null || faculties.isEmpty) { + return; + } + final session = await NetworkRouter.login( userInfo.item1, userInfo.item2, diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index d5da1a7c4..cf447d340 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -14,6 +14,10 @@ import 'package:uni/utils/favorite_widget_type.dart'; /// This database stores the user's student number, password and favorite /// widgets. class AppSharedPreferences { + static final iv = encrypt.IV.fromLength(16); + static final key = + encrypt.Key.fromBase64('DT3/GTNYldhwOD3ZbpVLoAwA/mncsN7U7sJxfFn3y0A='); + static const lastUpdateTimeKeySuffix = '_last_update_time'; static const String userNumber = 'user_number'; static const String userPw = 'user_password'; @@ -24,10 +28,6 @@ class AppSharedPreferences { 'tuition_notification_toogle'; static const String themeMode = 'theme_mode'; static const String locale = 'app_locale'; - static const int keyLength = 32; - static const int ivLength = 16; - static final iv = encrypt.IV.fromLength(ivLength); - static const String favoriteCards = 'favorite_cards'; static final List defaultFavoriteCards = [ FavoriteWidgetType.schedule, @@ -149,9 +149,12 @@ class AppSharedPreferences { /// * the first element in the tuple is the user's student number. /// * the second element in the tuple is the user's password, in plain text /// format. - static Future> getPersistentUserInfo() async { + static Future?> getPersistentUserInfo() async { final userNum = await getUserNumber(); final userPass = await getUserPassword(); + if (userNum == null || userPass == null) { + return null; + } return Tuple2(userNum, userPass); } @@ -164,22 +167,16 @@ class AppSharedPreferences { } /// Returns the user's student number. - static Future getUserNumber() async { + static Future getUserNumber() async { final prefs = await SharedPreferences.getInstance(); - return prefs.getString(userNumber) ?? - ''; // empty string for the case it does not exist + return prefs.getString(userNumber); } /// Returns the user's password, in plain text format. - static Future getUserPassword() async { + static Future getUserPassword() async { final prefs = await SharedPreferences.getInstance(); - var pass = prefs.getString(userPw) ?? ''; - - if (pass != '') { - pass = decode(pass); - } - - return pass; + final password = prefs.getString(userPw); + return password != null ? decode(password) : null; } /// Replaces the user's favorite widgets with [newFavorites]. @@ -270,15 +267,18 @@ class AppSharedPreferences { } /// Decrypts [base64Text]. - static String decode(String base64Text) { + static String? decode(String base64Text) { final encrypter = _createEncrypter(); - return encrypter.decrypt64(base64Text, iv: iv); + try { + return encrypter.decrypt64(base64Text, iv: iv); + } catch (e) { + return null; + } } /// Creates an [encrypt.Encrypter] for encrypting and decrypting the user's /// password. static encrypt.Encrypter _createEncrypter() { - final key = encrypt.Key.fromLength(keyLength); return encrypt.Encrypter(encrypt.AES(key)); } diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index ce60f4a68..a72f59b98 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -71,6 +71,7 @@ class NetworkRouter { faculties, persistentSession: persistentSession, ); + if (session == null) { Logger().e('Login failed: user not authenticated'); return null; @@ -90,6 +91,12 @@ class NetworkRouter { static Future reLoginFromSession(Session session) async { final username = session.username; final password = await AppSharedPreferences.getUserPassword(); + + if (password == null) { + Logger().e('Re-login failed: password not found'); + return null; + } + final faculties = session.faculties; final persistentSession = session.persistentSession; diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 6f2e29a30..407d18030 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -52,10 +52,8 @@ SentryEvent? beforeSend(SentryEvent event) { Future firstRoute() async { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - final userName = userPersistentInfo.item1; - final password = userPersistentInfo.item2; - if (userName != '' && password != '') { + if (userPersistentInfo != null) { return '/${DrawerItem.navPersonalArea.title}'; } diff --git a/uni/lib/model/providers/lazy/exam_provider.dart b/uni/lib/model/providers/lazy/exam_provider.dart index 562424f80..4327df8b3 100644 --- a/uni/lib/model/providers/lazy/exam_provider.dart +++ b/uni/lib/model/providers/lazy/exam_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:collection'; -import 'package:tuple/tuple.dart'; 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'; @@ -42,27 +41,28 @@ class ExamProvider extends StateProviderNotifier { Future loadFromRemote(Session session, Profile profile) async { await fetchUserExams( ParserExams(), - await AppSharedPreferences.getPersistentUserInfo(), profile, session, profile.courseUnits, + persistentSession: + (await AppSharedPreferences.getPersistentUserInfo()) != null, ); } Future fetchUserExams( ParserExams parserExams, - Tuple2 userPersistentInfo, Profile profile, Session session, - List userUcs, - ) async { + List userUcs, { + required bool persistentSession, + }) async { try { final exams = await ExamFetcher(profile.courses, userUcs) .extractExams(session, parserExams); exams.sort((exam1, exam2) => exam1.begin.compareTo(exam2.begin)); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (persistentSession) { await AppExamsDatabase().saveNewExams(exams); } diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index a9f832a5f..fd5789ef7 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:collection'; -import 'package:tuple/tuple.dart'; 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'; @@ -30,23 +29,24 @@ class LectureProvider extends StateProviderNotifier { @override Future loadFromRemote(Session session, Profile profile) async { await fetchUserLectures( - await AppSharedPreferences.getPersistentUserInfo(), session, profile, + persistentSession: + (await AppSharedPreferences.getPersistentUserInfo()) != null, ); } Future fetchUserLectures( - Tuple2 userPersistentInfo, Session session, Profile profile, { + required bool persistentSession, ScheduleFetcher? fetcher, }) async { try { final lectures = await getLecturesFromFetcherOrElse(fetcher, session, profile); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (persistentSession) { final db = AppLecturesDatabase(); await db.saveNewLectures(lectures); } diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index 81d386fad..c6f05d31a 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -75,7 +75,7 @@ class ProfileProvider extends StateProviderNotifier { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (userPersistentInfo != null) { final profileDb = AppUserDataDatabase(); await profileDb.saveUserFees(feesBalance, feesLimit); } @@ -95,7 +95,7 @@ class ProfileProvider extends StateProviderNotifier { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (userPersistentInfo != null) { final profileDb = AppUserDataDatabase(); await profileDb.saveUserPrintBalance(printBalance); } @@ -119,7 +119,7 @@ class ProfileProvider extends StateProviderNotifier { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (userPersistentInfo != null) { // Course units are saved later, so we don't it here final profileDb = AppUserDataDatabase(); await profileDb.insertUserData(_profile); @@ -144,7 +144,7 @@ class ProfileProvider extends StateProviderNotifier { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo.item1 != '' && userPersistentInfo.item2 != '') { + if (userPersistentInfo != null) { final coursesDb = AppCoursesDatabase(); await coursesDb.saveNewCourses(courses); diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index e4b006ea6..6131432dd 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -35,6 +35,11 @@ class SessionProvider extends StateProviderNotifier { Future loadFromStorage() async { final userPersistentInfo = await AppSharedPreferences.getPersistentUserInfo(); + + if (userPersistentInfo == null) { + return; + } + final userName = userPersistentInfo.item1; final password = userPersistentInfo.item2; diff --git a/uni/lib/view/common_widgets/page_transition.dart b/uni/lib/view/common_widgets/page_transition.dart index 494f8097f..2f3581a0d 100644 --- a/uni/lib/view/common_widgets/page_transition.dart +++ b/uni/lib/view/common_widgets/page_transition.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; - -import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/view/navigation_service.dart'; import 'package:uni/view/terms_and_condition_dialog.dart'; @@ -49,16 +47,9 @@ class PageTransition { static Future requestTermsAndConditionsAcceptanceIfNeeded( BuildContext context, ) async { - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - final userName = userPersistentInfo.item1; - final password = userPersistentInfo.item2; - if (context.mounted) { final termsAcceptance = await TermsAndConditionDialog.buildIfTermsChanged( context, - userName, - password, ); switch (termsAcceptance) { diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 7cea404ee..a7cd92df5 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.dart'; @@ -67,6 +68,7 @@ class LoginPageViewState extends State { } else if (error is WrongCredentialsException) { unawaited(ToastMessage.error(context, error.message)); } else { + Logger().e(error); unawaited(ToastMessage.error(context, S.of(context).failed_login)); } } diff --git a/uni/lib/view/terms_and_condition_dialog.dart b/uni/lib/view/terms_and_condition_dialog.dart index a1b1e2a8e..245cd0747 100644 --- a/uni/lib/view/terms_and_condition_dialog.dart +++ b/uni/lib/view/terms_and_condition_dialog.dart @@ -13,8 +13,6 @@ class TermsAndConditionDialog { static Future buildIfTermsChanged( BuildContext context, - String userName, - String password, ) async { final termsAreAccepted = await updateTermsAndConditionsAcceptancePreference(); @@ -22,8 +20,7 @@ class TermsAndConditionDialog { if (!termsAreAccepted) { final routeCompleter = Completer(); SchedulerBinding.instance.addPostFrameCallback( - (timestamp) => - _buildShowDialog(context, routeCompleter, userName, password), + (timestamp) => _buildShowDialog(context, routeCompleter), ); return routeCompleter.future; } @@ -34,8 +31,6 @@ class TermsAndConditionDialog { static Future _buildShowDialog( BuildContext context, Completer userTermsDecision, - String userName, - String password, ) { return showDialog( context: context, diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index 44622790c..03779534f 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -6,7 +6,6 @@ import 'package:http/http.dart' as http; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; -import 'package:tuple/tuple.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; import 'package:uni/model/entities/course.dart'; @@ -82,10 +81,10 @@ void main() { await examProvider.fetchUserExams( ParserExams(), - const Tuple2('', ''), profile, Session(username: '', cookies: '', faculties: ['feup']), [sopeCourseUnit, sdisCourseUnit], + persistentSession: false, ); await tester.pumpAndSettle(); @@ -118,10 +117,10 @@ void main() { await examProvider.fetchUserExams( ParserExams(), - const Tuple2('', ''), profile, Session(username: '', cookies: '', faculties: ['feup']), [sopeCourseUnit, sdisCourseUnit], + persistentSession: false, ); await tester.pumpAndSettle(); diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index e775c86b2..0deb663d2 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -7,7 +7,6 @@ import 'package:http/http.dart' as http; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; -import 'package:tuple/tuple.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; @@ -71,9 +70,9 @@ void main() { expect(find.byKey(const Key(scheduleSlotTimeKey2)), findsNothing); await scheduleProvider.fetchUserLectures( - const Tuple2('', ''), Session(username: '', cookies: '', faculties: ['feup']), profile, + persistentSession: false, ); await tester.tap(find.byKey(const Key('schedule-page-tab-2'))); diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index 2f4c33ddd..5c696a338 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:tuple/tuple.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; import 'package:uni/model/entities/course.dart'; @@ -61,8 +60,6 @@ void main() { 'feup', ); - const userPersistentInfo = Tuple2('', ''); - final profile = Profile()..courses = [Course(id: 7474)]; final session = Session(username: '', cookies: '', faculties: ['feup']); final userUcs = [sopeCourseUnit, sdisCourseUnit]; @@ -85,10 +82,10 @@ void main() { await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.exams.isNotEmpty, true); @@ -102,10 +99,10 @@ void main() { await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.successful); @@ -132,10 +129,10 @@ When given three exams but one is to be parsed out, await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.successful); @@ -148,10 +145,10 @@ When given three exams but one is to be parsed out, await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.failed); }); @@ -174,10 +171,10 @@ When given three exams but one is to be parsed out, await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.successful); @@ -202,10 +199,10 @@ When given three exams but one is to be parsed out, await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.successful); @@ -230,10 +227,10 @@ When given three exams but one is to be parsed out, await provider.fetchUserExams( parserExams, - userPersistentInfo, profile, session, userUcs, + persistentSession: false, ); expect(provider.status, RequestStatus.successful); diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index 8498f01c2..77edb5e27 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:tuple/tuple.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course.dart'; @@ -22,7 +21,6 @@ void main() { final fetcherMock = MockScheduleFetcher(); final mockClient = MockClient(); final mockResponse = MockResponse(); - const userPersistentInfo = Tuple2('', ''); final profile = Profile()..courses = [Course(id: 7474)]; final session = Session(username: '', cookies: '', faculties: ['feup']); final day = DateTime(2021, 06); @@ -66,10 +64,10 @@ void main() { .thenAnswer((_) async => [lecture1, lecture2]); await provider.fetchUserLectures( - userPersistentInfo, session, profile, fetcher: fetcherMock, + persistentSession: false, ); expect(provider.lectures, [lecture1, lecture2]); @@ -81,10 +79,10 @@ void main() { .thenAnswer((_) async => throw Exception('💥')); await provider.fetchUserLectures( - userPersistentInfo, session, profile, fetcher: fetcherMock, + persistentSession: false, ); expect(provider.status, RequestStatus.failed); From c1e3c9668649244205e23415dad464d1db811d8f Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 23 Sep 2023 14:43:29 +0100 Subject: [PATCH 137/199] Use fixed iv for AES --- uni/lib/controller/local_storage/app_shared_preferences.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/lib/controller/local_storage/app_shared_preferences.dart b/uni/lib/controller/local_storage/app_shared_preferences.dart index cf447d340..faca04476 100644 --- a/uni/lib/controller/local_storage/app_shared_preferences.dart +++ b/uni/lib/controller/local_storage/app_shared_preferences.dart @@ -14,7 +14,7 @@ import 'package:uni/utils/favorite_widget_type.dart'; /// This database stores the user's student number, password and favorite /// widgets. class AppSharedPreferences { - static final iv = encrypt.IV.fromLength(16); + static final iv = encrypt.IV.fromBase64('jF9jjdSEPgsKnf0jCl1GAQ=='); static final key = encrypt.Key.fromBase64('DT3/GTNYldhwOD3ZbpVLoAwA/mncsN7U7sJxfFn3y0A='); From c4a2238086ee2e426e3327838dac0ea294697bc8 Mon Sep 17 00:00:00 2001 From: limwa Date: Sat, 23 Sep 2023 15:46:20 +0000 Subject: [PATCH 138/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 8f2c3c19e..85999cd62 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.65+183 \ No newline at end of file +1.5.66+184 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 944950dc9..30d9542d8 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.65+183 +version: 1.5.66+184 environment: sdk: '>=3.0.0 <4.0.0' From 1f27e34c850c05c17a4c5c34e8dbb4c7776c13fa Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 23 Sep 2023 15:00:59 +0100 Subject: [PATCH 139/199] Remove useless login locks and checks --- .../controller/networking/network_router.dart | 60 ++++++++----------- .../providers/state_provider_notifier.dart | 10 ---- 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index a72f59b98..f05d88d54 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -55,7 +55,6 @@ class NetworkRouter { final url = '${NetworkRouter.getBaseUrls(faculties)[0]}mob_val_geral.autentica'; - final response = await http.post( url.toUri(), body: {'pv_login': username, 'pv_password': password}, @@ -100,8 +99,6 @@ class NetworkRouter { final faculties = session.faculties; final persistentSession = session.persistentSession; - Logger().d('Re-login from session: $username, $faculties'); - return login( username, password, @@ -117,17 +114,13 @@ class NetworkRouter { String pass, List faculties, ) async { - return _loginLock.synchronized(() async { - final url = - '${NetworkRouter.getBaseUrls(faculties)[0]}vld_validacao.validacao'; - - final response = await http.post( - url.toUri(), - body: {'p_user': user, 'p_pass': pass}, - ).timeout(_requestTimeout); - - return response.body; - }); + final url = + '${NetworkRouter.getBaseUrls(faculties)[0]}vld_validacao.validacao'; + final response = await http.post( + url.toUri(), + body: {'p_user': user, 'p_pass': pass}, + ).timeout(_requestTimeout); + return response.body; } /// Extracts the cookies present in [headers]. @@ -192,6 +185,7 @@ class NetworkRouter { NavigationService.logoutAndPopHistory(null); return Future.error('Login failed'); } + session ..username = newSession.username ..cookies = newSession.cookies; @@ -218,20 +212,18 @@ class NetworkRouter { /// Check if the user is still logged in, /// performing a health check on the user's personal page. static Future userLoggedIn(Session session) async { - return _loginLock.synchronized(() async { - Logger().d('Checking if user is still logged in'); + Logger().d('Checking if user is still logged in'); - final url = '${getBaseUrl(session.faculties[0])}' - 'fest_geral.cursos_list?pv_num_unico=${session.username}'; - final headers = {}; - headers['cookie'] = session.cookies; + final url = '${getBaseUrl(session.faculties[0])}' + 'fest_geral.cursos_list?pv_num_unico=${session.username}'; + final headers = {}; + headers['cookie'] = session.cookies; - final response = await (httpClient != null - ? httpClient!.get(url.toUri(), headers: headers) - : http.get(url.toUri(), headers: headers)); + final response = await (httpClient != null + ? httpClient!.get(url.toUri(), headers: headers) + : http.get(url.toUri(), headers: headers)); - return response.statusCode == 200; - }); + return response.statusCode == 200; } /// Returns the base url of the user's faculties. @@ -253,17 +245,15 @@ class NetworkRouter { static Future killSigarraAuthentication( List faculties, ) async { - return _loginLock.synchronized(() async { - final url = '${NetworkRouter.getBaseUrl(faculties[0])}vld_validacao.sair'; - final response = await http.get(url.toUri()).timeout(_requestTimeout); + final url = '${NetworkRouter.getBaseUrl(faculties[0])}vld_validacao.sair'; + final response = await http.get(url.toUri()).timeout(_requestTimeout); - if (response.statusCode == 200) { - Logger().i('Logout Successful'); - } else { - Logger().i('Logout Failed'); - } + if (response.statusCode == 200) { + Logger().i('Logout Successful'); + } else { + Logger().i('Logout Failed'); + } - return response; - }); + return response; } } diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index beb4b7616..41e80ed28 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -108,16 +108,6 @@ abstract class StateProviderNotifier extends ChangeNotifier { Future forceRefresh(BuildContext context) async { 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; - } - final session = Provider.of(context, listen: false).session; final profile = From eda231e2b7d9897a32a65bece5999117ec72d46a Mon Sep 17 00:00:00 2001 From: bdmendes Date: Mon, 25 Sep 2023 10:16:43 +0000 Subject: [PATCH 140/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 85999cd62..c88b05e01 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.66+184 \ No newline at end of file +1.5.67+185 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 30d9542d8..f08c60ccf 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.66+184 +version: 1.5.67+185 environment: sdk: '>=3.0.0 <4.0.0' From 5d66caddfd76b064d3fa6471d7720d37e119f13d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 20 Sep 2023 18:02:43 +0100 Subject: [PATCH 141/199] Bug fix --- uni/lib/model/entities/lecture.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uni/lib/model/entities/lecture.dart b/uni/lib/model/entities/lecture.dart index 8ff9da9db..1df6d1426 100644 --- a/uni/lib/model/entities/lecture.dart +++ b/uni/lib/model/entities/lecture.dart @@ -25,7 +25,7 @@ class Lecture { String classNumber, int occurrId, ) { - final endTime = startTime.add(Duration(seconds: 60 * 30 * blocks)); + final endTime = startTime.add(Duration(minutes: 30 * blocks)); final lecture = Lecture( subject, typeClass, @@ -62,8 +62,8 @@ class Lecture { day.add(Duration(hours: startTimeHours, minutes: startTimeMinutes)), day.add( Duration( - hours: startTimeMinutes + endTimeHours, - minutes: startTimeMinutes + endTimeMinutes, + hours: endTimeHours, + minutes: endTimeMinutes, ), ), blocks, From 70799b5442c94d3f2c042ec50a3d40e3b61d2b56 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Wed, 20 Sep 2023 18:42:49 +0100 Subject: [PATCH 142/199] Code improvement --- uni/lib/model/entities/lecture.dart | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/uni/lib/model/entities/lecture.dart b/uni/lib/model/entities/lecture.dart index 1df6d1426..f91658b2e 100644 --- a/uni/lib/model/entities/lecture.dart +++ b/uni/lib/model/entities/lecture.dart @@ -44,28 +44,25 @@ class Lecture { String subject, String typeClass, DateTime day, - String startTime, + String startTimeString, int blocks, String room, String teacher, String classNumber, int occurrId, ) { - final startTimeHours = int.parse(startTime.substring(0, 2)); - final startTimeMinutes = int.parse(startTime.substring(3, 5)); - final endTimeHours = - (startTimeMinutes + (blocks * 30)) ~/ 60 + startTimeHours; - final endTimeMinutes = (startTimeMinutes + (blocks * 30)) % 60; + final startTime = day.add( + Duration( + hours: int.parse(startTimeString.substring(0, 2)), + minutes: int.parse(startTimeString.substring(3, 5)), + ), + ); + final endTime = startTime.add(Duration(minutes: 30 * blocks)); return Lecture( subject, typeClass, - day.add(Duration(hours: startTimeHours, minutes: startTimeMinutes)), - day.add( - Duration( - hours: endTimeHours, - minutes: endTimeMinutes, - ), - ), + startTime, + endTime, blocks, room, teacher, From a2b0625decc0c27fb2e792bf86a73129ec649bc9 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Mon, 25 Sep 2023 10:17:33 +0000 Subject: [PATCH 143/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index c88b05e01..72db98ade 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.67+185 \ No newline at end of file +1.5.68+186 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index f08c60ccf..09af5e880 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.67+185 +version: 1.5.68+186 environment: sdk: '>=3.0.0 <4.0.0' From fd71a9b7264c9244b4b79671cb2d0aa4e0cd4fc4 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 20 Sep 2023 16:54:19 +0100 Subject: [PATCH 144/199] Use home back button action on login page --- .../view/home/widgets/exit_app_dialog.dart | 58 ++++++++++--------- .../view/home/widgets/main_cards_list.dart | 2 +- uni/lib/view/login/login.dart | 23 +------- 3 files changed, 34 insertions(+), 49 deletions(-) diff --git a/uni/lib/view/home/widgets/exit_app_dialog.dart b/uni/lib/view/home/widgets/exit_app_dialog.dart index fe6ed0ab5..0abd03550 100644 --- a/uni/lib/view/home/widgets/exit_app_dialog.dart +++ b/uni/lib/view/home/widgets/exit_app_dialog.dart @@ -1,45 +1,49 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:uni/generated/l10n.dart'; /// Manages the app section displayed when the user presses the back button class BackButtonExitWrapper extends StatelessWidget { const BackButtonExitWrapper({ - required this.context, required this.child, super.key, }); - final BuildContext context; final Widget child; - Future backButton() { - return showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text( - S.of(context).exit_confirm, - style: Theme.of(context).textTheme.headlineSmall, - ), - actions: [ - ElevatedButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text(S.of(context).no), - ), - ElevatedButton( - onPressed: () => - SystemChannels.platform.invokeMethod('SystemNavigator.pop'), - child: Text(S.of(context).yes), - ) - ], - ), - ); - } - @override Widget build(BuildContext context) { return WillPopScope( - onWillPop: () => backButton() as Future, + onWillPop: () { + final userActionCompleter = Completer(); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text( + S.of(context).exit_confirm, + style: Theme.of(context).textTheme.headlineSmall, + ), + actions: [ + ElevatedButton( + onPressed: () { + userActionCompleter.complete(false); + Navigator.of(context).pop(false); + }, + child: Text(S.of(context).no), + ), + ElevatedButton( + onPressed: () { + userActionCompleter.complete(true); + Navigator.of(context).pop(false); + }, + child: Text(S.of(context).yes), + ) + ], + ), + ); + return userActionCompleter.future; + }, child: child, ); } diff --git a/uni/lib/view/home/widgets/main_cards_list.dart b/uni/lib/view/home/widgets/main_cards_list.dart index b044dccf2..f28665a1c 100644 --- a/uni/lib/view/home/widgets/main_cards_list.dart +++ b/uni/lib/view/home/widgets/main_cards_list.dart @@ -24,6 +24,7 @@ typedef CardCreator = GenericCard Function( class MainCardsList extends StatelessWidget { const MainCardsList({super.key}); + static Map cardCreators = { FavoriteWidgetType.schedule: ScheduleCard.fromEditingInformation, FavoriteWidgetType.exams: ExamCard.fromEditingInformation, @@ -44,7 +45,6 @@ class MainCardsList extends StatelessWidget { return LazyConsumer( builder: (context, homePageProvider) => Scaffold( body: BackButtonExitWrapper( - context: context, child: SizedBox( height: MediaQuery.of(context).size.height, child: homePageProvider.isEditing diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index a7cd92df5..8a0131a3e 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -11,6 +11,7 @@ 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/home/widgets/exit_app_dialog.dart'; import 'package:uni/view/login/widgets/inputs.dart'; import 'package:uni/view/theme.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -37,7 +38,6 @@ class LoginPageViewState extends State { TextEditingController(); final GlobalKey _formKey = GlobalKey(); - static bool _exitApp = false; bool _keepSignedIn = true; bool _obscurePasswordInput = true; @@ -113,7 +113,7 @@ class LoginPageViewState extends State { child: Builder( builder: (context) => Scaffold( backgroundColor: darkRed, - body: WillPopScope( + body: BackButtonExitWrapper( child: Padding( padding: EdgeInsets.only( left: queryData.size.width / 8, @@ -160,31 +160,12 @@ class LoginPageViewState extends State { ], ), ), - onWillPop: () => onWillPop(context), ), ), ), ); } - /// Delay time before the user leaves the app - Future exitAppWaiter() async { - _exitApp = true; - await Future.delayed(const Duration(seconds: 2)); - _exitApp = false; - } - - /// If the user tries to leave, displays a quick prompt for him to confirm. - /// If this is already the second time, the user leaves the app. - Future onWillPop(BuildContext context) { - if (_exitApp) { - return Future.value(true); - } - ToastMessage.info(context, S.of(context).press_again); - exitAppWaiter(); - return Future.value(false); - } - /// Creates the title for the login menu. Widget createTitle(MediaQueryData queryData, BuildContext context) { return ConstrainedBox( From 8a20d6b1d15a5f9ae55dbcffd13df85e2894761b Mon Sep 17 00:00:00 2001 From: bdmendes Date: Mon, 25 Sep 2023 10:18:09 +0000 Subject: [PATCH 145/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 72db98ade..79acc0972 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.5.68+186 \ No newline at end of file +1.5.69+187 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 09af5e880..97cb195fd 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.5.68+186 +version: 1.5.69+187 environment: sdk: '>=3.0.0 <4.0.0' From 60c7d5b35821bb81442bcc4daa5c0bc17fe313c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Mon, 25 Sep 2023 15:02:50 +0100 Subject: [PATCH 146/199] Fixed username format while persisting --- uni/lib/model/providers/startup/session_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 6131432dd..cccdc536e 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -109,7 +109,7 @@ class SessionProvider extends StateProviderNotifier { if (persistentSession) { await AppSharedPreferences.savePersistentUserInfo( - username, + session.username, password, faculties, ); From 85d7277884badd65b9a8abdab87e5444af7a3436 Mon Sep 17 00:00:00 2001 From: thePeras Date: Mon, 25 Sep 2023 14:27:01 +0000 Subject: [PATCH 147/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 4a90543d4..c1f4ccf54 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.6.0+188 \ No newline at end of file +1.6.1+189 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 7695674c0..fdbccd0c1 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.6.0+188 +version: 1.6.1+189 environment: sdk: '>=3.0.0 <4.0.0' From 1bf751bb84099923cfa2f0d6150a17e5f69482c3 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Tue, 26 Sep 2023 15:51:21 +0000 Subject: [PATCH 148/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index c1f4ccf54..3a04413b4 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.6.1+189 \ No newline at end of file +1.7.0+190 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index fdbccd0c1..78292fb41 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.6.1+189 +version: 1.7.0+190 environment: sdk: '>=3.0.0 <4.0.0' From 123fecc0fee8bc8a1736d122b9050cc273384d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Wed, 27 Sep 2023 16:24:42 +0100 Subject: [PATCH 149/199] Fix overlapping classes bugs --- .../parsers/parser_schedule_html.dart | 27 ++++++++++++------- uni/lib/model/entities/lecture.dart | 5 ++-- .../providers/lazy/lecture_provider.dart | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/uni/lib/controller/parsers/parser_schedule_html.dart b/uni/lib/controller/parsers/parser_schedule_html.dart index 88ac5ce8c..5b040dddb 100644 --- a/uni/lib/controller/parsers/parser_schedule_html.dart +++ b/uni/lib/controller/parsers/parser_schedule_html.dart @@ -9,9 +9,7 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/entities/time_utilities.dart'; Future> getOverlappedClasses( - Session session, - Document document, -) async { + Session session, Document document, Uri uri) async { final lecturesList = []; final monday = DateTime.now().getClosestMonday(); @@ -21,7 +19,7 @@ Future> getOverlappedClasses( final subject = element.querySelector('acronym > a')?.text; final typeClass = element .querySelector('td[headers=t1]') - ?.nodes[2] + ?.nodes[1] .text ?.trim() .replaceAll(RegExp('[()]+'), ''); @@ -37,20 +35,28 @@ Future> getOverlappedClasses( final classNumber = element.querySelector('td[headers=t6] > a')?.text; try { + final startTimeList = startTime?.split(':') ?? []; + if (startTimeList.isEmpty) { + throw FormatException( + 'Overlapping class $subject has invalid startTime', + ); + } final fullStartTime = monday.add( Duration( days: day, - hours: int.parse(startTime!.substring(0, 2)), - minutes: int.parse(startTime.substring(3, 5)), + hours: int.parse(startTimeList[0]), + minutes: int.parse(startTimeList[1]), ), ); - final link = + final href = element.querySelector('td[headers=t6] > a')?.attributes['href']; - if (link == null) { + if (href == null) { throw Exception(); } - final response = await NetworkRouter.getWithCookies(link, {}, session); + final faculty = uri.path.split('/')[1]; + final response = + await NetworkRouter.getWithCookies('https://${uri.host}/$faculty/$href', {}, session); final classLectures = await getScheduleFromHtml(response, session); @@ -148,7 +154,8 @@ Future> getScheduleFromHtml( }); lecturesList - ..addAll(await getOverlappedClasses(session, document)) + ..addAll( + await getOverlappedClasses(session, document, response.request!.url),) ..sort((a, b) => a.compare(b)); return lecturesList; diff --git a/uni/lib/model/entities/lecture.dart b/uni/lib/model/entities/lecture.dart index f91658b2e..b93aac32c 100644 --- a/uni/lib/model/entities/lecture.dart +++ b/uni/lib/model/entities/lecture.dart @@ -51,10 +51,11 @@ class Lecture { String classNumber, int occurrId, ) { + final startTimeList = startTimeString.split(':'); final startTime = day.add( Duration( - hours: int.parse(startTimeString.substring(0, 2)), - minutes: int.parse(startTimeString.substring(3, 5)), + hours: int.parse(startTimeList[0]), + minutes: int.parse(startTimeList[1]), ), ); final endTime = startTime.add(Duration(minutes: 30 * blocks)); diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index fd5789ef7..3c234c224 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -53,7 +53,7 @@ class LectureProvider extends StateProviderNotifier { _lectures = lectures; updateStatus(RequestStatus.successful); - } catch (e) { + } catch (e, stacktrace) { updateStatus(RequestStatus.failed); } } From 25360622d39a9af433dca26fea0b6f8a64b72ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Wed, 27 Sep 2023 17:08:48 +0100 Subject: [PATCH 150/199] fix formatting and linting --- .../controller/parsers/parser_schedule_html.dart | 15 +++++++++++---- .../model/providers/lazy/lecture_provider.dart | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/parsers/parser_schedule_html.dart b/uni/lib/controller/parsers/parser_schedule_html.dart index 5b040dddb..1e706d8a3 100644 --- a/uni/lib/controller/parsers/parser_schedule_html.dart +++ b/uni/lib/controller/parsers/parser_schedule_html.dart @@ -9,7 +9,10 @@ import 'package:uni/model/entities/session.dart'; import 'package:uni/model/entities/time_utilities.dart'; Future> getOverlappedClasses( - Session session, Document document, Uri uri) async { + Session session, + Document document, + Uri uri, +) async { final lecturesList = []; final monday = DateTime.now().getClosestMonday(); @@ -55,8 +58,11 @@ Future> getOverlappedClasses( throw Exception(); } final faculty = uri.path.split('/')[1]; - final response = - await NetworkRouter.getWithCookies('https://${uri.host}/$faculty/$href', {}, session); + final response = await NetworkRouter.getWithCookies( + 'https://${uri.host}/$faculty/$href', + {}, + session, + ); final classLectures = await getScheduleFromHtml(response, session); @@ -155,7 +161,8 @@ Future> getScheduleFromHtml( lecturesList ..addAll( - await getOverlappedClasses(session, document, response.request!.url),) + await getOverlappedClasses(session, document, response.request!.url), + ) ..sort((a, b) => a.compare(b)); return lecturesList; diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index 3c234c224..fd5789ef7 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -53,7 +53,7 @@ class LectureProvider extends StateProviderNotifier { _lectures = lectures; updateStatus(RequestStatus.successful); - } catch (e, stacktrace) { + } catch (e) { updateStatus(RequestStatus.failed); } } From 134cad31e8c88b6b161c1163d9bd81b8bb41cbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 28 Sep 2023 14:27:09 +0100 Subject: [PATCH 151/199] refactor and fix tests --- .../schedule_fetcher/schedule_fetcher_html.dart | 8 ++++++-- uni/lib/controller/parsers/parser_schedule_html.dart | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 6d9594a4b..7fdf7ed16 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:http/http.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; @@ -39,8 +40,11 @@ class ScheduleFetcherHtml extends ScheduleFetcher { } final lectures = await Future.wait( - lectureResponses - .map((response) => getScheduleFromHtml(response, session)), + IterableZip( + [lectureResponses, NetworkRouter.getBaseUrlsFromSession(session)], + ).map( + (e) => getScheduleFromHtml(e[0] as Response, session, e[1] as String), + ), ).then((schedules) => schedules.expand((schedule) => schedule).toList()); lectures.sort((l1, l2) => l1.compare(l2)); diff --git a/uni/lib/controller/parsers/parser_schedule_html.dart b/uni/lib/controller/parsers/parser_schedule_html.dart index 1e706d8a3..6843f749d 100644 --- a/uni/lib/controller/parsers/parser_schedule_html.dart +++ b/uni/lib/controller/parsers/parser_schedule_html.dart @@ -11,7 +11,7 @@ import 'package:uni/model/entities/time_utilities.dart'; Future> getOverlappedClasses( Session session, Document document, - Uri uri, + String faculty, ) async { final lecturesList = []; @@ -57,14 +57,14 @@ Future> getOverlappedClasses( if (href == null) { throw Exception(); } - final faculty = uri.path.split('/')[1]; final response = await NetworkRouter.getWithCookies( - 'https://${uri.host}/$faculty/$href', + '$faculty$href', {}, session, ); - final classLectures = await getScheduleFromHtml(response, session); + final classLectures = + await getScheduleFromHtml(response, session, faculty); lecturesList.add( classLectures @@ -100,6 +100,7 @@ Future> getOverlappedClasses( Future> getScheduleFromHtml( http.Response response, Session session, + String faculty, ) async { final document = parse(response.body); var semana = [0, 0, 0, 0, 0, 0]; @@ -161,7 +162,7 @@ Future> getScheduleFromHtml( lecturesList ..addAll( - await getOverlappedClasses(session, document, response.request!.url), + await getOverlappedClasses(session, document, faculty), ) ..sort((a, b) => a.compare(b)); From 60bd1418380f74d7d50f05eef8c4c267c2c623b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 28 Sep 2023 14:49:07 +0100 Subject: [PATCH 152/199] make ci bump patch version if it doesn't come from develop --- .github/workflows/deploy.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 051ac1bda..555b767ae 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -14,12 +14,19 @@ jobs: with: token: ${{ secrets.NIAEFEUPBOT_PAT }} + - name: Get develop hash + if: github.ref == 'refs/heads/master' + run: | + git fetch origin develop + current_hash=$(git rev-parse HEAD) + echo "DEVELOPHASH=$current_hash" >> $GITHUB_ENV + - name: Bump flutter patch version - if: github.ref == 'refs/heads/develop' + if: github.ref == 'refs/heads/develop' || (github.ref == 'refs/heads/master' && $${{github.sha == env.DEVELOPHASH}}) run: perl -i -pe 's/^(\d+\.\d+\.)(\d+)(\+)(\d+)$/$1.($2+1).($3).($4+1)/e' ${{ env.APP_VERSION_PATH }} - name: Bump flutter minor version - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' && $${{github.sha == env.DEVELOPHASH}} run: perl -i -pe 's/^(\d+)(\.)(\d+)(\.)(\d+)(\+)(\d+)$/$1.($2).($3+1).($4).(0).($6).($7+1)/e' ${{ env.APP_VERSION_PATH }} - name: Copy app version to pubspec From 5c55963cf1e4bed1008894954f40339bc37a3f27 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 28 Sep 2023 14:51:50 +0100 Subject: [PATCH 153/199] Remove error handling in providers --- .../providers/lazy/bus_stop_provider.dart | 24 +--- .../providers/lazy/calendar_provider.dart | 14 +- .../lazy/course_units_info_provider.dart | 27 +--- .../model/providers/lazy/exam_provider.dart | 20 +-- .../lazy/faculty_locations_provider.dart | 7 +- .../providers/lazy/home_page_provider.dart | 5 +- .../providers/lazy/lecture_provider.dart | 20 +-- .../lazy/library_occupation_provider.dart | 15 +- .../providers/lazy/reference_provider.dart | 16 +-- .../providers/lazy/restaurant_provider.dart | 15 +- .../providers/startup/profile_provider.dart | 131 ++++++++---------- .../providers/startup/session_provider.dart | 10 +- .../providers/state_provider_notifier.dart | 60 ++++---- uni/lib/view/schedule/schedule.dart | 8 +- .../unit/providers/exams_provider_test.dart | 21 ++- .../unit/providers/lecture_provider_test.dart | 15 +- 16 files changed, 145 insertions(+), 263 deletions(-) diff --git a/uni/lib/model/providers/lazy/bus_stop_provider.dart b/uni/lib/model/providers/lazy/bus_stop_provider.dart index 6df3626c1..b739dd8d0 100644 --- a/uni/lib/model/providers/lazy/bus_stop_provider.dart +++ b/uni/lib/model/providers/lazy/bus_stop_provider.dart @@ -1,14 +1,12 @@ import 'dart:async'; 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/entities/bus_stop.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 BusStopProvider extends StateProviderNotifier { BusStopProvider() : super(dependsOnSession: false, cacheDuration: null); @@ -33,20 +31,14 @@ class BusStopProvider extends StateProviderNotifier { } Future fetchUserBusTrips() async { - try { - for (final stopCode in configuredBusStops.keys) { - final stopTrips = await DeparturesFetcher.getNextArrivalsStop( - stopCode, - configuredBusStops[stopCode]!, - ); - _configuredBusStops[stopCode]?.trips = stopTrips; - } - _timeStamp = DateTime.now(); - updateStatus(RequestStatus.successful); - } catch (e) { - Logger().e('Failed to get Bus Stop information'); - updateStatus(RequestStatus.failed); + for (final stopCode in configuredBusStops.keys) { + final stopTrips = await DeparturesFetcher.getNextArrivalsStop( + stopCode, + configuredBusStops[stopCode]!, + ); + _configuredBusStops[stopCode]?.trips = stopTrips; } + _timeStamp = DateTime.now(); } Future addUserBusStop(String stopCode, BusStopData stopData) async { @@ -59,7 +51,6 @@ class BusStopProvider extends StateProviderNotifier { _configuredBusStops[stopCode] = stopData; } - updateStatus(RequestStatus.busy); await fetchUserBusTrips(); final db = AppBusStopDatabase(); @@ -69,7 +60,6 @@ class BusStopProvider extends StateProviderNotifier { Future removeUserBusStop( String stopCode, ) async { - updateStatus(RequestStatus.busy); _configuredBusStops.remove(stopCode); notifyListeners(); diff --git a/uni/lib/model/providers/lazy/calendar_provider.dart b/uni/lib/model/providers/lazy/calendar_provider.dart index 5be749683..3e532b718 100644 --- a/uni/lib/model/providers/lazy/calendar_provider.dart +++ b/uni/lib/model/providers/lazy/calendar_provider.dart @@ -7,7 +7,6 @@ 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'; class CalendarProvider extends StateProviderNotifier { CalendarProvider() @@ -23,16 +22,9 @@ class CalendarProvider extends StateProviderNotifier { } Future fetchCalendar(Session session) async { - try { - _calendar = await CalendarFetcherHtml().getCalendar(session); - - final db = CalendarDatabase(); - unawaited(db.saveCalendar(calendar)); - - updateStatus(RequestStatus.successful); - } catch (e) { - updateStatus(RequestStatus.failed); - } + _calendar = await CalendarFetcherHtml().getCalendar(session); + final db = CalendarDatabase(); + unawaited(db.saveCalendar(calendar)); } @override diff --git a/uni/lib/model/providers/lazy/course_units_info_provider.dart b/uni/lib/model/providers/lazy/course_units_info_provider.dart index 1f1e76a0b..2a9901870 100644 --- a/uni/lib/model/providers/lazy/course_units_info_provider.dart +++ b/uni/lib/model/providers/lazy/course_units_info_provider.dart @@ -1,6 +1,5 @@ import 'dart:collection'; -import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; @@ -8,7 +7,6 @@ import 'package:uni/model/entities/course_units/course_unit_sheet.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 CourseUnitsInfoProvider extends StateProviderNotifier { CourseUnitsInfoProvider() @@ -26,33 +24,16 @@ class CourseUnitsInfoProvider extends StateProviderNotifier { CourseUnit courseUnit, Session session, ) async { - updateStatus(RequestStatus.busy); - try { - _courseUnitsSheets[courseUnit] = await CourseUnitsInfoFetcher() - .fetchCourseUnitSheet(session, courseUnit.occurrId); - } catch (e) { - updateStatus(RequestStatus.failed); - Logger().e('Failed to get course unit sheet for ${courseUnit.name}: $e'); - return; - } - updateStatus(RequestStatus.successful); + _courseUnitsSheets[courseUnit] = await CourseUnitsInfoFetcher() + .fetchCourseUnitSheet(session, courseUnit.occurrId); } Future fetchCourseUnitClasses( CourseUnit courseUnit, Session session, ) async { - updateStatus(RequestStatus.busy); - try { - _courseUnitsClasses[courseUnit] = await CourseUnitsInfoFetcher() - .fetchCourseUnitClasses(session, courseUnit.occurrId); - } catch (e) { - updateStatus(RequestStatus.failed); - Logger() - .e('Failed to get course unit classes for ${courseUnit.name}: $e'); - return; - } - updateStatus(RequestStatus.successful); + _courseUnitsClasses[courseUnit] = await CourseUnitsInfoFetcher() + .fetchCourseUnitClasses(session, courseUnit.occurrId); } @override diff --git a/uni/lib/model/providers/lazy/exam_provider.dart b/uni/lib/model/providers/lazy/exam_provider.dart index 4327df8b3..3b809372d 100644 --- a/uni/lib/model/providers/lazy/exam_provider.dart +++ b/uni/lib/model/providers/lazy/exam_provider.dart @@ -10,7 +10,6 @@ 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 { ExamProvider() @@ -56,21 +55,16 @@ class ExamProvider extends StateProviderNotifier { List userUcs, { required bool persistentSession, }) async { - try { - final exams = await ExamFetcher(profile.courses, userUcs) - .extractExams(session, parserExams); + final exams = await ExamFetcher(profile.courses, userUcs) + .extractExams(session, parserExams); - exams.sort((exam1, exam2) => exam1.begin.compareTo(exam2.begin)); + exams.sort((exam1, exam2) => exam1.begin.compareTo(exam2.begin)); - if (persistentSession) { - await AppExamsDatabase().saveNewExams(exams); - } - - _exams = exams; - updateStatus(RequestStatus.successful); - } catch (e) { - updateStatus(RequestStatus.failed); + if (persistentSession) { + await AppExamsDatabase().saveNewExams(exams); } + + _exams = exams; } Future updateFilteredExams() async { diff --git a/uni/lib/model/providers/lazy/faculty_locations_provider.dart b/uni/lib/model/providers/lazy/faculty_locations_provider.dart index 2952f0e57..f43da6743 100644 --- a/uni/lib/model/providers/lazy/faculty_locations_provider.dart +++ b/uni/lib/model/providers/lazy/faculty_locations_provider.dart @@ -5,7 +5,6 @@ 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 'package:uni/model/request_status.dart'; class FacultyLocationsProvider extends StateProviderNotifier { FacultyLocationsProvider() @@ -17,13 +16,9 @@ class FacultyLocationsProvider extends StateProviderNotifier { @override Future loadFromStorage() async { - updateStatus(RequestStatus.busy); _locations = await LocationFetcherAsset().getLocations(); - updateStatus(RequestStatus.successful); } @override - Future loadFromRemote(Session session, Profile profile) async { - updateStatus(RequestStatus.successful); - } + Future loadFromRemote(Session session, Profile profile) async {} } diff --git a/uni/lib/model/providers/lazy/home_page_provider.dart b/uni/lib/model/providers/lazy/home_page_provider.dart index 891495761..48d162e33 100644 --- a/uni/lib/model/providers/lazy/home_page_provider.dart +++ b/uni/lib/model/providers/lazy/home_page_provider.dart @@ -2,7 +2,6 @@ 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/model/request_status.dart'; import 'package:uni/utils/favorite_widget_type.dart'; class HomePageProvider extends StateProviderNotifier { @@ -20,9 +19,7 @@ class HomePageProvider extends StateProviderNotifier { } @override - Future loadFromRemote(Session session, Profile profile) async { - updateStatus(RequestStatus.successful); - } + Future loadFromRemote(Session session, Profile profile) async {} void setHomePageEditingMode({required bool editingMode}) { _isEditing = editingMode; diff --git a/uni/lib/model/providers/lazy/lecture_provider.dart b/uni/lib/model/providers/lazy/lecture_provider.dart index fd5789ef7..93201bdbd 100644 --- a/uni/lib/model/providers/lazy/lecture_provider.dart +++ b/uni/lib/model/providers/lazy/lecture_provider.dart @@ -10,7 +10,6 @@ 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 { LectureProvider() @@ -42,20 +41,15 @@ class LectureProvider extends StateProviderNotifier { required bool persistentSession, ScheduleFetcher? fetcher, }) async { - try { - final lectures = - await getLecturesFromFetcherOrElse(fetcher, session, profile); + final lectures = + await getLecturesFromFetcherOrElse(fetcher, session, profile); - if (persistentSession) { - final db = AppLecturesDatabase(); - await db.saveNewLectures(lectures); - } - - _lectures = lectures; - updateStatus(RequestStatus.successful); - } catch (e) { - updateStatus(RequestStatus.failed); + if (persistentSession) { + final db = AppLecturesDatabase(); + await db.saveNewLectures(lectures); } + + _lectures = lectures; } Future> getLecturesFromFetcherOrElse( diff --git a/uni/lib/model/providers/lazy/library_occupation_provider.dart b/uni/lib/model/providers/lazy/library_occupation_provider.dart index ee1ab2292..c1fb18199 100644 --- a/uni/lib/model/providers/lazy/library_occupation_provider.dart +++ b/uni/lib/model/providers/lazy/library_occupation_provider.dart @@ -6,7 +6,6 @@ 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'; class LibraryOccupationProvider extends StateProviderNotifier { LibraryOccupationProvider() @@ -28,16 +27,10 @@ class LibraryOccupationProvider extends StateProviderNotifier { } Future fetchLibraryOccupation(Session session) async { - try { - _occupation = await LibraryOccupationFetcherSheets() - .getLibraryOccupationFromSheets(session); + _occupation = await LibraryOccupationFetcherSheets() + .getLibraryOccupationFromSheets(session); - final db = LibraryOccupationDatabase(); - unawaited(db.saveOccupation(_occupation!)); - - updateStatus(RequestStatus.successful); - } catch (e) { - updateStatus(RequestStatus.failed); - } + final db = LibraryOccupationDatabase(); + unawaited(db.saveOccupation(_occupation!)); } } diff --git a/uni/lib/model/providers/lazy/reference_provider.dart b/uni/lib/model/providers/lazy/reference_provider.dart index d795e070f..619090669 100644 --- a/uni/lib/model/providers/lazy/reference_provider.dart +++ b/uni/lib/model/providers/lazy/reference_provider.dart @@ -8,7 +8,6 @@ import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/reference.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 ReferenceProvider extends StateProviderNotifier { ReferenceProvider() @@ -31,18 +30,11 @@ class ReferenceProvider extends StateProviderNotifier { } Future fetchUserReferences(Session session) async { - try { - final response = - await ReferenceFetcher().getUserReferenceResponse(session); + final response = await ReferenceFetcher().getUserReferenceResponse(session); - _references = await parseReferences(response); + _references = await parseReferences(response); - updateStatus(RequestStatus.successful); - - final referencesDb = AppReferencesDatabase(); - unawaited(referencesDb.saveNewReferences(references)); - } catch (e) { - updateStatus(RequestStatus.failed); - } + final referencesDb = AppReferencesDatabase(); + unawaited(referencesDb.saveNewReferences(references)); } } diff --git a/uni/lib/model/providers/lazy/restaurant_provider.dart b/uni/lib/model/providers/lazy/restaurant_provider.dart index cebefd30e..d0db39f40 100644 --- a/uni/lib/model/providers/lazy/restaurant_provider.dart +++ b/uni/lib/model/providers/lazy/restaurant_provider.dart @@ -8,7 +8,6 @@ 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'; -import 'package:uni/model/request_status.dart'; class RestaurantProvider extends StateProviderNotifier { RestaurantProvider() @@ -37,18 +36,12 @@ class RestaurantProvider extends StateProviderNotifier { } Future fetchRestaurants(Session session) async { - try { - final restaurants = await RestaurantFetcher().getRestaurants(session); + final restaurants = await RestaurantFetcher().getRestaurants(session); - final db = RestaurantDatabase(); - unawaited(db.saveRestaurants(restaurants)); + final db = RestaurantDatabase(); + unawaited(db.saveRestaurants(restaurants)); - _restaurants = filterPastMeals(restaurants); - - updateStatus(RequestStatus.successful); - } catch (e) { - updateStatus(RequestStatus.failed); - } + _restaurants = filterPastMeals(restaurants); } Future toggleFavoriteRestaurant( diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index c6f05d31a..c3e1bd9d0 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -16,7 +16,6 @@ import 'package:uni/controller/parsers/parser_print_balance.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 ProfileProvider extends StateProviderNotifier { ProfileProvider() @@ -43,10 +42,6 @@ class ProfileProvider extends StateProviderNotifier { fetchUserPrintBalance(session), fetchCourseUnitsAndCourseAverages(session) ]); - - if (status != RequestStatus.failed) { - updateStatus(RequestStatus.successful); - } } Future loadProfile() async { @@ -66,93 +61,75 @@ class ProfileProvider extends StateProviderNotifier { } Future fetchUserFees(Session session) async { - try { - final response = await FeesFetcher().getUserFeesResponse(session); + final response = await FeesFetcher().getUserFeesResponse(session); - final feesBalance = parseFeesBalance(response); - final feesLimit = parseFeesNextLimit(response); + final feesBalance = parseFeesBalance(response); + final feesLimit = parseFeesNextLimit(response); - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo != null) { - final profileDb = AppUserDataDatabase(); - await profileDb.saveUserFees(feesBalance, feesLimit); - } - - _profile - ..feesBalance = feesBalance - ..feesLimit = feesLimit; - } catch (e) { - updateStatus(RequestStatus.failed); + if (userPersistentInfo != null) { + final profileDb = AppUserDataDatabase(); + await profileDb.saveUserFees(feesBalance, feesLimit); } + + _profile + ..feesBalance = feesBalance + ..feesLimit = feesLimit; } Future fetchUserPrintBalance(Session session) async { - try { - final response = await PrintFetcher().getUserPrintsResponse(session); - final printBalance = await getPrintsBalance(response); - - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo != null) { - final profileDb = AppUserDataDatabase(); - await profileDb.saveUserPrintBalance(printBalance); - } - - _profile.printBalance = printBalance; - } catch (e) { - updateStatus(RequestStatus.failed); + final response = await PrintFetcher().getUserPrintsResponse(session); + final printBalance = await getPrintsBalance(response); + + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + if (userPersistentInfo != null) { + final profileDb = AppUserDataDatabase(); + await profileDb.saveUserPrintBalance(printBalance); } + + _profile.printBalance = printBalance; } Future fetchUserInfo(Session session) async { - try { - final profile = await ProfileFetcher.fetchProfile(session); - final currentCourseUnits = - await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); - - _profile = profile ?? Profile(); - _profile.courseUnits = currentCourseUnits; - - updateStatus(RequestStatus.successful); - - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo != null) { - // Course units are saved later, so we don't it here - final profileDb = AppUserDataDatabase(); - await profileDb.insertUserData(_profile); - } - } catch (e) { - updateStatus(RequestStatus.failed); + final profile = await ProfileFetcher.fetchProfile(session); + final currentCourseUnits = + await CurrentCourseUnitsFetcher().getCurrentCourseUnits(session); + + _profile = profile ?? Profile(); + _profile.courseUnits = currentCourseUnits; + + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + if (userPersistentInfo != null) { + // Course units are saved later, so we don't it here + final profileDb = AppUserDataDatabase(); + await profileDb.insertUserData(_profile); } } Future fetchCourseUnitsAndCourseAverages(Session session) async { - try { - final courses = profile.courses; - final allCourseUnits = await AllCourseUnitsFetcher() - .getAllCourseUnitsAndCourseAverages(profile.courses, session); - - if (allCourseUnits != null) { - _profile.courseUnits = allCourseUnits; - } else { - // Current course units should already have been fetched, - // so this is not a fatal error - } - - final userPersistentInfo = - await AppSharedPreferences.getPersistentUserInfo(); - if (userPersistentInfo != null) { - final coursesDb = AppCoursesDatabase(); - await coursesDb.saveNewCourses(courses); - - final courseUnitsDatabase = AppCourseUnitsDatabase(); - await courseUnitsDatabase.saveNewCourseUnits(_profile.courseUnits); - } - } catch (e) { - updateStatus(RequestStatus.failed); + final courses = profile.courses; + final allCourseUnits = await AllCourseUnitsFetcher() + .getAllCourseUnitsAndCourseAverages(profile.courses, session); + + if (allCourseUnits != null) { + _profile.courseUnits = allCourseUnits; + } else { + // Current course units should already have been fetched, + // so this is not a fatal error + } + + final userPersistentInfo = + await AppSharedPreferences.getPersistentUserInfo(); + if (userPersistentInfo != null) { + final coursesDb = AppCoursesDatabase(); + await coursesDb.saveNewCourses(courses); + + final courseUnitsDatabase = AppCourseUnitsDatabase(); + await courseUnitsDatabase.saveNewCourseUnits(_profile.courseUnits); } } diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index cccdc536e..823742d0e 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -49,9 +49,7 @@ class SessionProvider extends StateProviderNotifier { } @override - Future loadFromRemote(Session session, Profile profile) async { - updateStatus(RequestStatus.successful); - } + Future loadFromRemote(Session session, Profile profile) async {} void restoreSession( String username, @@ -73,8 +71,6 @@ class SessionProvider extends StateProviderNotifier { List faculties, { required bool persistentSession, }) async { - updateStatus(RequestStatus.busy); - Session? session; try { session = await NetworkRouter.login( @@ -84,7 +80,6 @@ class SessionProvider extends StateProviderNotifier { persistentSession: persistentSession, ); } catch (e) { - updateStatus(RequestStatus.failed); throw InternetStatusException( Provider.of(context).getLocale(), ); @@ -94,8 +89,6 @@ class SessionProvider extends StateProviderNotifier { final responseHtml = await NetworkRouter.loginInSigarra(username, password, faculties); - updateStatus(RequestStatus.failed); - if (isPasswordExpired(responseHtml) && context.mounted) { throw ExpiredCredentialsException(); } else { @@ -121,6 +114,5 @@ class SessionProvider extends StateProviderNotifier { ); await acceptTermsAndConditions(); - updateStatus(RequestStatus.successful); } } diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 41e80ed28..82bb8ffbf 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -41,6 +41,11 @@ abstract class StateProviderNotifier extends ChangeNotifier { _lastUpdateTime = null; } + void _updateStatus(RequestStatus status) { + _status = status; + notifyListeners(); + } + Future _loadFromStorage() async { Logger().d('Loading $runtimeType info from storage'); @@ -48,8 +53,14 @@ abstract class StateProviderNotifier extends ChangeNotifier { runtimeType.toString(), ); - await loadFromStorage(); - notifyListeners(); + try { + await loadFromStorage(); + notifyListeners(); + } catch (e, stackTrace) { + Logger() + .e('Failed to load $runtimeType info from storage: $e\n$stackTrace'); + } + Logger().i('Loaded $runtimeType info from storage'); } @@ -68,7 +79,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { if (!shouldReload) { Logger().d('Last info for $runtimeType is within cache period ' '(last updated on $_lastUpdateTime); skipping remote load'); - updateStatus(RequestStatus.successful); + _updateStatus(RequestStatus.successful); return; } @@ -77,42 +88,35 @@ abstract class StateProviderNotifier extends ChangeNotifier { if (!hasConnectivity) { Logger().w('No internet connection; skipping $runtimeType remote load'); - updateStatus(RequestStatus.successful); + _updateStatus(RequestStatus.successful); return; } - updateStatus(RequestStatus.busy); + _updateStatus(RequestStatus.busy); - await loadFromRemote(session, profile); + try { + await loadFromRemote(session, profile); - if (_status == RequestStatus.successful) { Logger().i('Loaded $runtimeType info from remote'); _lastUpdateTime = DateTime.now(); - notifyListeners(); + _updateStatus(RequestStatus.successful); + await AppSharedPreferences.setLastDataClassUpdateTime( runtimeType.toString(), _lastUpdateTime!, ); - } else if (_status == RequestStatus.failed) { - Logger().e('Failed to load $runtimeType info from remote'); - } else { + } catch (e, stackTrace) { Logger() - .w('$runtimeType remote load method did not update request status'); + .e('Failed to load $runtimeType info from remote: $e\n$stackTrace'); + _updateStatus(RequestStatus.failed); } } - void updateStatus(RequestStatus status) { - _status = status; - notifyListeners(); - } - Future forceRefresh(BuildContext context) async { await _lock.synchronized(() async { - final session = - Provider.of(context, listen: false).session; - final profile = - Provider.of(context, listen: false).profile; - + final session = context.read().session; + final profile = context.read().profile; + _updateStatus(RequestStatus.busy); await _loadFromRemote(session, profile, force: true); }); } @@ -133,10 +137,8 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromRemote = true; - final session = - Provider.of(context, listen: false).session; - final profile = - Provider.of(context, listen: false).profile; + final session = context.read().session; + final profile = context.read().profile; await _loadFromRemote(session, profile); }); @@ -160,10 +162,6 @@ abstract class StateProviderNotifier extends ChangeNotifier { /// Loads data from the remote server into the provider. /// This will run once when the provider is first initialized. - /// If the data is not available from the remote server - /// or the data is filled into the provider on demand, - /// this method should simply set the - /// request status to [RequestStatus.successful]; - /// otherwise, it should set the status accordingly. + /// This method must not catch data loading errors. Future loadFromRemote(Session session, Profile profile); } diff --git a/uni/lib/view/schedule/schedule.dart b/uni/lib/view/schedule/schedule.dart index 084a9d856..0651fe625 100644 --- a/uni/lib/view/schedule/schedule.dart +++ b/uni/lib/view/schedule/schedule.dart @@ -43,7 +43,7 @@ class SchedulePageView extends StatefulWidget { }); final List lectures; - final RequestStatus? scheduleStatus; + final RequestStatus scheduleStatus; final int weekDay = DateTime.now().weekday; @@ -144,7 +144,7 @@ class SchedulePageViewState extends GeneralPageViewState List createSchedule( BuildContext context, List lectures, - RequestStatus? scheduleStatus, + RequestStatus scheduleStatus, ) { final tabBarViewContent = []; for (var i = 0; i < 5; i++) { @@ -194,13 +194,13 @@ class SchedulePageViewState extends GeneralPageViewState BuildContext context, int day, List lectures, - RequestStatus? scheduleStatus, + RequestStatus scheduleStatus, ) { final weekday = Provider.of(context).getWeekdaysWithLocale()[day]; final aggLectures = SchedulePageView.groupLecturesByDay(lectures); return RequestDependentWidgetBuilder( - status: scheduleStatus ?? RequestStatus.none, + status: scheduleStatus, builder: () => dayColumnBuilder(day, aggLectures[day], context), hasContentPredicate: aggLectures[day].isNotEmpty, onNullContent: Center( diff --git a/uni/test/unit/providers/exams_provider_test.dart b/uni/test/unit/providers/exams_provider_test.dart index 5c696a338..d424a2a48 100644 --- a/uni/test/unit/providers/exams_provider_test.dart +++ b/uni/test/unit/providers/exams_provider_test.dart @@ -90,7 +90,6 @@ void main() { expect(provider.exams.isNotEmpty, true); expect(provider.exams, [sopeExam]); - expect(provider.status, RequestStatus.successful); }); test('When given two exams', () async { @@ -105,7 +104,6 @@ void main() { persistentSession: false, ); - expect(provider.status, RequestStatus.successful); expect(provider.exams, [sopeExam, sdisExam]); }); @@ -135,7 +133,6 @@ When given three exams but one is to be parsed out, persistentSession: false, ); - expect(provider.status, RequestStatus.successful); expect(provider.exams, [sopeExam, sdisExam]); }); @@ -143,14 +140,15 @@ When given three exams but one is to be parsed out, when(parserExams.parseExams(any, any)) .thenAnswer((_) async => throw Exception('RIP')); - await provider.fetchUserExams( - parserExams, - profile, - session, - userUcs, - persistentSession: false, + throwsA( + () async => provider.fetchUserExams( + parserExams, + profile, + session, + userUcs, + persistentSession: false, + ), ); - expect(provider.status, RequestStatus.failed); }); test('When Exam is today in one hour', () async { @@ -177,7 +175,6 @@ When given three exams but one is to be parsed out, persistentSession: false, ); - expect(provider.status, RequestStatus.successful); expect(provider.exams, [todayExam]); }); @@ -205,7 +202,6 @@ When given three exams but one is to be parsed out, persistentSession: false, ); - expect(provider.status, RequestStatus.successful); expect(provider.exams, []); }); @@ -233,7 +229,6 @@ When given three exams but one is to be parsed out, persistentSession: false, ); - expect(provider.status, RequestStatus.successful); expect(provider.exams, [todayExam]); }); }); diff --git a/uni/test/unit/providers/lecture_provider_test.dart b/uni/test/unit/providers/lecture_provider_test.dart index 77edb5e27..78a1bbb3b 100644 --- a/uni/test/unit/providers/lecture_provider_test.dart +++ b/uni/test/unit/providers/lecture_provider_test.dart @@ -71,21 +71,20 @@ void main() { ); expect(provider.lectures, [lecture1, lecture2]); - expect(provider.status, RequestStatus.successful); }); test('When an error occurs while trying to obtain the schedule', () async { when(fetcherMock.getLectures(any, any)) .thenAnswer((_) async => throw Exception('💥')); - await provider.fetchUserLectures( - session, - profile, - fetcher: fetcherMock, - persistentSession: false, + throwsA( + () async => provider.fetchUserLectures( + session, + profile, + fetcher: fetcherMock, + persistentSession: false, + ), ); - - expect(provider.status, RequestStatus.failed); }); }); } From cfb937c38158dccedb6d941525d61b8baf0d7551 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 28 Sep 2023 15:15:14 +0100 Subject: [PATCH 154/199] Fix tests --- uni/lib/model/providers/state_provider_notifier.dart | 9 +++++++++ uni/test/integration/src/exams_page_test.dart | 4 ++++ uni/test/integration/src/schedule_page_test.dart | 2 ++ 3 files changed, 15 insertions(+) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 82bb8ffbf..f894e710c 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -34,11 +34,20 @@ abstract class StateProviderNotifier extends ChangeNotifier { DateTime? get lastUpdateTime => _lastUpdateTime; + void markAsInitialized() { + _initializedFromStorage = true; + _initializedFromRemote = true; + _status = RequestStatus.successful; + _lastUpdateTime = DateTime.now(); + notifyListeners(); + } + void markAsNotInitialized() { _initializedFromStorage = false; _initializedFromRemote = false; _status = _initialStatus; _lastUpdateTime = null; + notifyListeners(); } void _updateStatus(RequestStatus status) { diff --git a/uni/test/integration/src/exams_page_test.dart b/uni/test/integration/src/exams_page_test.dart index 03779534f..4e37ebd3f 100644 --- a/uni/test/integration/src/exams_page_test.dart +++ b/uni/test/integration/src/exams_page_test.dart @@ -87,6 +87,8 @@ void main() { persistentSession: false, ); + examProvider.markAsInitialized(); + await tester.pumpAndSettle(); expect(find.byKey(Key('$sdisExam-exam')), findsOneWidget); expect(find.byKey(Key('$sopeExam-exam')), findsOneWidget); @@ -123,6 +125,8 @@ void main() { persistentSession: false, ); + examProvider.markAsInitialized(); + await tester.pumpAndSettle(); expect(find.byKey(Key('$sdisExam-exam')), findsOneWidget); expect(find.byKey(Key('$sopeExam-exam')), findsOneWidget); diff --git a/uni/test/integration/src/schedule_page_test.dart b/uni/test/integration/src/schedule_page_test.dart index 0deb663d2..2f040fc0b 100644 --- a/uni/test/integration/src/schedule_page_test.dart +++ b/uni/test/integration/src/schedule_page_test.dart @@ -75,6 +75,8 @@ void main() { persistentSession: false, ); + scheduleProvider.markAsInitialized(); + 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'))); From 74f2ad2d12db3e635d86f071535c6affbf942bf6 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 28 Sep 2023 15:37:28 +0100 Subject: [PATCH 155/199] Report exceptions to Sentry --- uni/lib/model/providers/state_provider_notifier.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index f894e710c..49431ed12 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -2,6 +2,7 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:synchronized/synchronized.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; import 'package:uni/model/entities/profile.dart'; @@ -66,6 +67,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { await loadFromStorage(); notifyListeners(); } catch (e, stackTrace) { + await Sentry.captureException(e, stackTrace: stackTrace); Logger() .e('Failed to load $runtimeType info from storage: $e\n$stackTrace'); } @@ -115,6 +117,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { _lastUpdateTime!, ); } catch (e, stackTrace) { + await Sentry.captureException(e, stackTrace: stackTrace); Logger() .e('Failed to load $runtimeType info from remote: $e\n$stackTrace'); _updateStatus(RequestStatus.failed); From 38d7561b5db0ccc5b5c4071184efed87fd6ea39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 28 Sep 2023 14:52:48 +0000 Subject: [PATCH 156/199] Fix deploy --- .github/workflows/deploy.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 555b767ae..56b862eb1 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -18,24 +18,26 @@ jobs: if: github.ref == 'refs/heads/master' run: | git fetch origin develop - current_hash=$(git rev-parse HEAD) + current_hash=$(git rev-parse origin/develop) echo "DEVELOPHASH=$current_hash" >> $GITHUB_ENV - name: Bump flutter patch version - if: github.ref == 'refs/heads/develop' || (github.ref == 'refs/heads/master' && $${{github.sha == env.DEVELOPHASH}}) + if: github.ref == 'refs/heads/develop' || github.sha != env.DEVELOPHASH run: perl -i -pe 's/^(\d+\.\d+\.)(\d+)(\+)(\d+)$/$1.($2+1).($3).($4+1)/e' ${{ env.APP_VERSION_PATH }} - name: Bump flutter minor version - if: github.ref == 'refs/heads/master' && $${{github.sha == env.DEVELOPHASH}} + if: github.ref == 'refs/heads/master' && github.sha == env.DEVELOPHASH run: perl -i -pe 's/^(\d+)(\.)(\d+)(\.)(\d+)(\+)(\d+)$/$1.($2).($3+1).($4).(0).($6).($7+1)/e' ${{ env.APP_VERSION_PATH }} - name: Copy app version to pubspec run: cat ${{ env.APP_VERSION_PATH }} | perl -i -pe 's/^(version:\s+)(\d+\.\d+\.\d+\+\d+)$/$1.()/e' ${{ env.PUBSPEC_PATH }} + - name: debug cansdo + run: git --no-pager diff + - uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "Bump app version [no ci]" - - name: Propagate master version bump to develop if: github.ref == 'refs/heads/master' run: git push --force-with-lease origin HEAD:develop From e88317d2ebf365a1a960fd8ee11a7f513432702b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Duarte?= Date: Thu, 28 Sep 2023 14:57:30 +0000 Subject: [PATCH 157/199] Remove debug deploy info --- .github/workflows/deploy.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 56b862eb1..cbd989070 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -32,9 +32,6 @@ jobs: - name: Copy app version to pubspec run: cat ${{ env.APP_VERSION_PATH }} | perl -i -pe 's/^(version:\s+)(\d+\.\d+\.\d+\+\d+)$/$1.()/e' ${{ env.PUBSPEC_PATH }} - - name: debug cansdo - run: git --no-pager diff - - uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "Bump app version [no ci]" From 46ab53bb5e5ac34181b35eaf153ce244db113c09 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Thu, 28 Sep 2023 15:16:10 +0000 Subject: [PATCH 158/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 3a04413b4..164763488 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.0+190 \ No newline at end of file +1.7.1+191 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 78292fb41..264610cfa 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.0+190 +version: 1.7.1+191 environment: sdk: '>=3.0.0 <4.0.0' From 172d85e03cf8edb8a820fe94485b311b4506fc0a Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 28 Sep 2023 19:57:32 +0100 Subject: [PATCH 159/199] Fix login callback --- .../providers/startup/session_provider.dart | 4 +-- .../providers/state_provider_notifier.dart | 1 - uni/lib/view/login/login.dart | 32 +++++++++---------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/uni/lib/model/providers/startup/session_provider.dart b/uni/lib/model/providers/startup/session_provider.dart index 823742d0e..cfd4276ad 100644 --- a/uni/lib/model/providers/startup/session_provider.dart +++ b/uni/lib/model/providers/startup/session_provider.dart @@ -81,7 +81,7 @@ class SessionProvider extends StateProviderNotifier { ); } catch (e) { throw InternetStatusException( - Provider.of(context).getLocale(), + Provider.of(context, listen: false).getLocale(), ); } @@ -93,7 +93,7 @@ class SessionProvider extends StateProviderNotifier { throw ExpiredCredentialsException(); } else { throw WrongCredentialsException( - Provider.of(context).getLocale(), + Provider.of(context, listen: false).getLocale(), ); } } diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 49431ed12..81543fd8b 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -48,7 +48,6 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromRemote = false; _status = _initialStatus; _lastUpdateTime = null; - notifyListeners(); } void _updateStatus(RequestStatus status) { diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index 8a0131a3e..a390331d3 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -8,7 +8,6 @@ import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.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'; import 'package:uni/view/common_widgets/toast_message.dart'; import 'package:uni/view/home/widgets/exit_app_dialog.dart'; @@ -40,16 +39,19 @@ class LoginPageViewState extends State { final GlobalKey _formKey = GlobalKey(); bool _keepSignedIn = true; bool _obscurePasswordInput = true; + bool _loggingIn = false; Future _login(BuildContext context) async { final stateProviders = StateProviders.fromContext(context); final sessionProvider = stateProviders.sessionProvider; - if (sessionProvider.status != RequestStatus.busy && - _formKey.currentState!.validate()) { + if (!_loggingIn && _formKey.currentState!.validate()) { final user = usernameController.text.trim(); final pass = passwordController.text.trim(); try { + setState(() { + _loggingIn = true; + }); await sessionProvider.postAuthentication( context, user, @@ -58,9 +60,18 @@ class LoginPageViewState extends State { persistentSession: _keepSignedIn, ); if (context.mounted) { - handleLogin(sessionProvider.status, context); + await Navigator.pushReplacementNamed( + context, + '/${DrawerItem.navPersonalArea.title}', + ); + setState(() { + _loggingIn = false; + }); } } catch (error) { + setState(() { + _loggingIn = false; + }); if (error is ExpiredCredentialsException) { updatePasswordDialog(); } else if (error is InternetStatusException) { @@ -250,7 +261,7 @@ class LoginPageViewState extends State { Widget createStatusWidget(BuildContext context) { return Consumer( builder: (context, sessionProvider, _) { - if (sessionProvider.status == RequestStatus.busy) { + if (_loggingIn) { return const SizedBox( height: 60, child: @@ -262,17 +273,6 @@ class LoginPageViewState extends State { ); } - void handleLogin(RequestStatus? status, BuildContext context) { - if (status == RequestStatus.successful) { - Navigator.pushReplacementNamed( - context, - '/${DrawerItem.navPersonalArea.title}', - ); - } else if (status == RequestStatus.failed) { - ToastMessage.error(context, S.of(context).failed_login); - } - } - void updatePasswordDialog() { showDialog( context: context, From 9d145da9bb3a404ed86843e1d9388ef8a06cdcd0 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 28 Sep 2023 20:39:33 +0100 Subject: [PATCH 160/199] Improve course units loading behavior --- .../pages_layouts/general/general.dart | 42 ++++++++++- .../course_unit_info/course_unit_info.dart | 73 ++++++++----------- uni/lib/view/lazy_consumer.dart | 4 +- 3 files changed, 70 insertions(+), 49 deletions(-) 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 ef5753178..116f830be 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -3,7 +3,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; +import 'package:sentry_flutter/sentry_flutter.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'; @@ -13,6 +15,8 @@ import 'package:uni/view/profile/profile.dart'; /// Page with a hamburger menu and the user profile picture abstract class GeneralPageViewState extends State { final double borderMargin = 18; + bool _loadedOnce = false; + bool _loading = true; Future onRefresh(BuildContext context); @@ -20,8 +24,42 @@ abstract class GeneralPageViewState extends State { @override Widget build(BuildContext context) { - WidgetsBinding.instance.addPostFrameCallback((_) => onLoad(context)); - return getScaffold(context, getBody(context)); + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (_loadedOnce) { + return; + } + _loadedOnce = true; + setState(() { + _loading = true; + }); + + try { + await onLoad(context); + } catch (e, stackTrace) { + Logger().e('Failed to load page info: $e\n$stackTrace'); + await Sentry.captureException(e, stackTrace: stackTrace); + } + + setState(() { + _loading = false; + }); + }); + + return getScaffold( + context, + _loading + ? const Flex( + direction: Axis.vertical, + children: [ + Expanded( + child: Center( + child: CircularProgressIndicator(), + ), + ) + ], + ) + : getBody(context), + ); } Widget getBody(BuildContext 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 ade00b29d..dd858d9dd 100644 --- a/uni/lib/view/course_unit_info/course_unit_info.dart +++ b/uni/lib/view/course_unit_info/course_unit_info.dart @@ -6,13 +6,12 @@ import 'package:uni/model/providers/lazy/course_units_info_provider.dart'; import 'package:uni/model/providers/startup/session_provider.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/common_widgets/request_dependent_widget_builder.dart'; import 'package:uni/view/course_unit_info/widgets/course_unit_classes.dart'; import 'package:uni/view/course_unit_info/widgets/course_unit_sheet.dart'; -import 'package:uni/view/lazy_consumer.dart'; class CourseUnitDetailPageView extends StatefulWidget { const CourseUnitDetailPageView(this.courseUnit, {super.key}); + final CourseUnit courseUnit; @override @@ -91,50 +90,36 @@ class CourseUnitDetailPageViewState } Widget _courseUnitSheetView(BuildContext context) { - return LazyConsumer( - builder: (context, courseUnitsInfoProvider) { - return RequestDependentWidgetBuilder( - onNullContent: Center( - child: Text( - S.of(context).no_info, - textAlign: TextAlign.center, - ), - ), - status: courseUnitsInfoProvider.status, - builder: () => CourseUnitSheetView( - courseUnitsInfoProvider.courseUnitsSheets[widget.courseUnit]!, - ), - hasContentPredicate: - courseUnitsInfoProvider.courseUnitsSheets[widget.courseUnit] != - null && - courseUnitsInfoProvider.courseUnitsSheets[widget.courseUnit]! - .sections.isNotEmpty, - ); - }, - ); + final sheet = context + .read() + .courseUnitsSheets[widget.courseUnit]; + + if (sheet == null || sheet.sections.isEmpty) { + return Center( + child: Text( + S.of(context).no_info, + textAlign: TextAlign.center, + ), + ); + } + + return CourseUnitSheetView(sheet); } Widget _courseUnitClassesView(BuildContext context) { - return LazyConsumer( - builder: (context, courseUnitsInfoProvider) { - return RequestDependentWidgetBuilder( - onNullContent: Center( - child: Text( - S.of(context).no_class, - textAlign: TextAlign.center, - ), - ), - status: courseUnitsInfoProvider.status, - builder: () => CourseUnitClassesView( - courseUnitsInfoProvider.courseUnitsClasses[widget.courseUnit]!, - ), - hasContentPredicate: - courseUnitsInfoProvider.courseUnitsClasses[widget.courseUnit] != - null && - courseUnitsInfoProvider - .courseUnitsClasses[widget.courseUnit]!.isNotEmpty, - ); - }, - ); + final classes = context + .read() + .courseUnitsClasses[widget.courseUnit]; + + if (classes == null || classes.isEmpty) { + return Center( + child: Text( + S.of(context).no_class, + textAlign: TextAlign.center, + ), + ); + } + + return CourseUnitClassesView(classes); } } diff --git a/uni/lib/view/lazy_consumer.dart b/uni/lib/view/lazy_consumer.dart index 49b19d748..ccb2b0305 100644 --- a/uni/lib/view/lazy_consumer.dart +++ b/uni/lib/view/lazy_consumer.dart @@ -69,9 +69,7 @@ class LazyConsumer extends StatelessWidget { // Finally, complete provider initialization if (context.mounted) { - // This will fail if the session initialization failed. - // That is the expected behavior. - await sessionFuture!.then((_) async { + await sessionFuture?.then((_) async { await provider!.ensureInitializedFromRemote(context); }); } From 36edab744f286ac77e51ad9d7ff02ab6d01b89cc Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Fri, 29 Sep 2023 09:45:21 +0000 Subject: [PATCH 161/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 164763488..ed41058f5 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.1+191 \ No newline at end of file +1.7.2+192 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 264610cfa..129b6171c 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.1+191 +version: 1.7.2+192 environment: sdk: '>=3.0.0 <4.0.0' From 68df5319dfc80a6c43c4624fde7b76d5db347f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 21:16:39 +0100 Subject: [PATCH 162/199] fix: parsing for half duration lectures --- uni/lib/controller/parsers/parser_schedule.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uni/lib/controller/parsers/parser_schedule.dart b/uni/lib/controller/parsers/parser_schedule.dart index 2a98c4853..80981e878 100644 --- a/uni/lib/controller/parsers/parser_schedule.dart +++ b/uni/lib/controller/parsers/parser_schedule.dart @@ -35,7 +35,11 @@ Future> parseSchedule(http.Response response) async { // TODO(luisd): this was marked as a double on the develop branch but the // tests' example api returns an integer. At the moment there are no // classes so I can't test this. - final blocks = (lecture['aula_duracao'] as int) * 2; + final lectureDuration = lecture['aula_duracao']; + final blocks = lectureDuration is double + ? (lectureDuration * 2).toInt() + : (lectureDuration as int) * 2; + final room = (lecture['sala_sigla'] as String).replaceAll(RegExp(r'\+'), '\n'); final teacher = lecture['doc_sigla'] as String; From 8f4465cf88968f798d0830ffd8180ca6a785b5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 21:18:25 +0100 Subject: [PATCH 163/199] docs: update comment on api parsing for lectures --- uni/lib/controller/parsers/parser_schedule.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/uni/lib/controller/parsers/parser_schedule.dart b/uni/lib/controller/parsers/parser_schedule.dart index 80981e878..34aacac79 100644 --- a/uni/lib/controller/parsers/parser_schedule.dart +++ b/uni/lib/controller/parsers/parser_schedule.dart @@ -32,9 +32,10 @@ Future> parseSchedule(http.Response response) async { final secBegin = lecture['hora_inicio'] as int; final subject = lecture['ucurr_sigla'] as String; final typeClass = lecture['tipo'] as String; - // TODO(luisd): this was marked as a double on the develop branch but the - // tests' example api returns an integer. At the moment there are no - // classes so I can't test this. + + // Note: aula_duracao returns an integer when the lecture is 1 hour long + // or 2 hours long and so on. When the lecture is 1.5 hours long, it + // returns a double, with the value 1.5. final lectureDuration = lecture['aula_duracao']; final blocks = lectureDuration is double ? (lectureDuration * 2).toInt() From ba664720dc7bc31921a9f779d691e8dd82e45e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 21:31:42 +0100 Subject: [PATCH 164/199] style: format files --- uni/lib/controller/parsers/parser_schedule.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/parsers/parser_schedule.dart b/uni/lib/controller/parsers/parser_schedule.dart index 34aacac79..0a950c7d0 100644 --- a/uni/lib/controller/parsers/parser_schedule.dart +++ b/uni/lib/controller/parsers/parser_schedule.dart @@ -32,14 +32,14 @@ Future> parseSchedule(http.Response response) async { final secBegin = lecture['hora_inicio'] as int; final subject = lecture['ucurr_sigla'] as String; final typeClass = lecture['tipo'] as String; - - // Note: aula_duracao returns an integer when the lecture is 1 hour long + + // Note: aula_duracao is an integer when the lecture is 1 hour long // or 2 hours long and so on. When the lecture is 1.5 hours long, it - // returns a double, with the value 1.5. + // returns a double, with the value 1.5. final lectureDuration = lecture['aula_duracao']; final blocks = lectureDuration is double - ? (lectureDuration * 2).toInt() - : (lectureDuration as int) * 2; + ? (lectureDuration * 2).toInt() + : (lectureDuration as int) * 2; final room = (lecture['sala_sigla'] as String).replaceAll(RegExp(r'\+'), '\n'); From 86b551a1b2558124c4a196b596d5434a9f04003a Mon Sep 17 00:00:00 2001 From: bdmendes Date: Fri, 29 Sep 2023 20:59:20 +0000 Subject: [PATCH 165/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index ed41058f5..88ad0f984 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.2+192 \ No newline at end of file +1.7.3+193 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 129b6171c..efb3c6d48 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.2+192 +version: 1.7.3+193 environment: sdk: '>=3.0.0 <4.0.0' From eb4a16739191a70022bac1468c28ba74504859bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 22:02:37 +0100 Subject: [PATCH 166/199] fix: schedule html parser not parsing all courses --- .../schedule_fetcher/schedule_fetcher_html.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 7fdf7ed16..6a3fc6d97 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -39,12 +39,15 @@ class ScheduleFetcherHtml extends ScheduleFetcher { } } + final baseUrls = NetworkRouter.getBaseUrlsFromSession(session); + final lectures = await Future.wait( - IterableZip( - [lectureResponses, NetworkRouter.getBaseUrlsFromSession(session)], - ).map( - (e) => getScheduleFromHtml(e[0] as Response, session, e[1] as String), - ), + lectureResponses + // FIXME: baseUrls[0] is a hack, because the course can be taught in more than one faculty + .map((e) => [e, baseUrls[0]]) + .map( + (e) => getScheduleFromHtml(e[0] as Response, session, e[1] as String), + ), ).then((schedules) => schedules.expand((schedule) => schedule).toList()); lectures.sort((l1, l2) => l1.compare(l2)); From 1a93d2ac550235a736edd9da7935f141fcdfbad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 22:08:53 +0100 Subject: [PATCH 167/199] style: format code --- .../schedule_fetcher/schedule_fetcher_html.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 6a3fc6d97..08d0ae96a 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -43,11 +43,12 @@ class ScheduleFetcherHtml extends ScheduleFetcher { final lectures = await Future.wait( lectureResponses - // FIXME: baseUrls[0] is a hack, because the course can be taught in more than one faculty - .map((e) => [e, baseUrls[0]]) - .map( - (e) => getScheduleFromHtml(e[0] as Response, session, e[1] as String), - ), + // FIXME: baseUrls[0] is a hack, because the course can be taught in more than one faculty + .map((e) => [e, baseUrls[0]]) + .map( + (e) => + getScheduleFromHtml(e[0] as Response, session, e[1] as String), + ), ).then((schedules) => schedules.expand((schedule) => schedule).toList()); lectures.sort((l1, l2) => l1.compare(l2)); From fa98979443db0eef8075f317e8be7c8e7363896b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 22:13:05 +0100 Subject: [PATCH 168/199] style: fix linting issues --- .../fetchers/schedule_fetcher/schedule_fetcher_html.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 08d0ae96a..5fa342b9c 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -1,4 +1,3 @@ -import 'package:collection/collection.dart'; import 'package:http/http.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; @@ -43,7 +42,8 @@ class ScheduleFetcherHtml extends ScheduleFetcher { final lectures = await Future.wait( lectureResponses - // FIXME: baseUrls[0] is a hack, because the course can be taught in more than one faculty + // FIXME: baseUrls[0] is a hack, because the course can be + // taught in more than one faculty .map((e) => [e, baseUrls[0]]) .map( (e) => From f65c7e46f9bc0d1a1b4bd17dd5f85a0c53aae8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 23:49:07 +0100 Subject: [PATCH 169/199] refactor: make code less hacky --- .../schedule_fetcher_html.dart | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 5fa342b9c..b2dbfa466 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -1,4 +1,5 @@ import 'package:http/http.dart'; +import 'package:tuple/tuple.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_schedule_html.dart'; @@ -21,7 +22,7 @@ class ScheduleFetcherHtml extends ScheduleFetcher { Future> getLectures(Session session, Profile profile) async { final dates = getDates(); final urls = getEndpoints(session); - final lectureResponses = []; + final lectureResponses = >[]; for (final course in profile.courses) { for (final url in urls) { final response = await NetworkRouter.getWithCookies( @@ -34,21 +35,14 @@ class ScheduleFetcherHtml extends ScheduleFetcher { }, session, ); - lectureResponses.add(response); + lectureResponses.add(Tuple2(response, url)); } } - final baseUrls = NetworkRouter.getBaseUrlsFromSession(session); - final lectures = await Future.wait( - lectureResponses - // FIXME: baseUrls[0] is a hack, because the course can be - // taught in more than one faculty - .map((e) => [e, baseUrls[0]]) - .map( - (e) => - getScheduleFromHtml(e[0] as Response, session, e[1] as String), - ), + lectureResponses.map( + (e) => getScheduleFromHtml(e.item1, session, e.item2), + ), ).then((schedules) => schedules.expand((schedule) => schedule).toList()); lectures.sort((l1, l2) => l1.compare(l2)); From 4699efba88adff7acf9d919b261c661d79d10fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 29 Sep 2023 23:54:06 +0100 Subject: [PATCH 170/199] fix: use base urls for getScheduleFromHtml --- .../schedule_fetcher/schedule_fetcher_html.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index b2dbfa466..e7e8ea77e 100644 --- a/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/uni/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -21,10 +21,13 @@ class ScheduleFetcherHtml extends ScheduleFetcher { @override Future> getLectures(Session session, Profile profile) async { final dates = getDates(); - final urls = getEndpoints(session); + final baseUrls = NetworkRouter.getBaseUrlsFromSession(session); + final lectureResponses = >[]; - for (final course in profile.courses) { - for (final url in urls) { + for (final baseUrl in baseUrls) { + final url = '${baseUrl}hor_geral.estudantes_view'; + + for (final course in profile.courses) { final response = await NetworkRouter.getWithCookies( url, { @@ -35,7 +38,7 @@ class ScheduleFetcherHtml extends ScheduleFetcher { }, session, ); - lectureResponses.add(Tuple2(response, url)); + lectureResponses.add(Tuple2(response, baseUrl)); } } From 3fa3de10e8db237eebfa8c65e00fbdadf880e787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Sat, 30 Sep 2023 15:10:21 +0100 Subject: [PATCH 171/199] fix: exams not showing up --- .../all_course_units_fetcher.dart | 17 ++++++++++++----- .../controller/parsers/parser_course_units.dart | 13 ++++++++++--- uni/lib/model/providers/lazy/exam_provider.dart | 2 +- .../providers/startup/profile_provider.dart | 8 ++++++-- uni/lib/view/home/widgets/exam_card.dart | 6 ++++-- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index c6dbdc8e2..f0d87293b 100644 --- a/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -8,8 +8,9 @@ import 'package:uni/model/entities/session.dart'; class AllCourseUnitsFetcher { Future?> getAllCourseUnitsAndCourseAverages( List courses, - Session session, - ) async { + Session session, { + List? currentCourseUnits, + }) async { final allCourseUnits = []; for (final course in courses) { @@ -17,6 +18,7 @@ class AllCourseUnitsFetcher { final courseUnits = await _getAllCourseUnitsAndCourseAveragesFromCourse( course, session, + currentCourseUnits: currentCourseUnits, ); allCourseUnits.addAll(courseUnits.where((c) => c.enrollmentIsValid())); } catch (e) { @@ -30,8 +32,9 @@ class AllCourseUnitsFetcher { Future> _getAllCourseUnitsAndCourseAveragesFromCourse( Course course, - Session session, - ) async { + Session session, { + List? currentCourseUnits, + }) async { final url = '${NetworkRouter.getBaseUrl(course.faculty!)}' 'fest_geral.curso_percurso_academico_view'; final response = await NetworkRouter.getWithCookies( @@ -41,6 +44,10 @@ class AllCourseUnitsFetcher { }, session, ); - return parseCourseUnitsAndCourseAverage(response, course); + return parseCourseUnitsAndCourseAverage( + response, + course, + currentCourseUnits: currentCourseUnits, + ); } } diff --git a/uni/lib/controller/parsers/parser_course_units.dart b/uni/lib/controller/parsers/parser_course_units.dart index 8131dc51b..c57764d2a 100644 --- a/uni/lib/controller/parsers/parser_course_units.dart +++ b/uni/lib/controller/parsers/parser_course_units.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:html/parser.dart'; import 'package:http/http.dart' as http; import 'package:uni/model/entities/course.dart'; @@ -6,8 +7,9 @@ import 'package:uni/utils/url_parser.dart'; List parseCourseUnitsAndCourseAverage( http.Response response, - Course course, -) { + Course course, { + List? currentCourseUnits, +}) { final document = parse(response.body); final table = document.getElementById('tabelapercurso'); if (table == null) { @@ -68,11 +70,16 @@ List parseCourseUnitsAndCourseAverage( continue; } + final matchingCurrentCourseUnit = currentCourseUnits + ?.firstWhereOrNull((element) => element.code == codeName); + final courseUnit = CourseUnit( schoolYear: '${firstSchoolYear + yearIncrement}/${firstSchoolYear + yearIncrement + 1}', occurrId: int.parse(occurId), - abbreviation: codeName, + code: codeName, + abbreviation: matchingCurrentCourseUnit?.abbreviation ?? + codeName, // FIXME: this is not the abbreviation status: status, grade: grade, ects: double.parse(ects), diff --git a/uni/lib/model/providers/lazy/exam_provider.dart b/uni/lib/model/providers/lazy/exam_provider.dart index 3b809372d..5f93c548a 100644 --- a/uni/lib/model/providers/lazy/exam_provider.dart +++ b/uni/lib/model/providers/lazy/exam_provider.dart @@ -74,7 +74,7 @@ class ExamProvider extends StateProviderNotifier { } Future setFilteredExams(Map newFilteredExams) async { - unawaited(AppSharedPreferences.saveFilteredExams(filteredExamsTypes)); + unawaited(AppSharedPreferences.saveFilteredExams(newFilteredExams)); _filteredExamsTypes = Map.from(newFilteredExams); notifyListeners(); } diff --git a/uni/lib/model/providers/startup/profile_provider.dart b/uni/lib/model/providers/startup/profile_provider.dart index c3e1bd9d0..8c85284fc 100644 --- a/uni/lib/model/providers/startup/profile_provider.dart +++ b/uni/lib/model/providers/startup/profile_provider.dart @@ -112,8 +112,12 @@ class ProfileProvider extends StateProviderNotifier { Future fetchCourseUnitsAndCourseAverages(Session session) async { final courses = profile.courses; - final allCourseUnits = await AllCourseUnitsFetcher() - .getAllCourseUnitsAndCourseAverages(profile.courses, session); + final allCourseUnits = + await AllCourseUnitsFetcher().getAllCourseUnitsAndCourseAverages( + profile.courses, + session, + currentCourseUnits: profile.courseUnits, + ); if (allCourseUnits != null) { _profile.courseUnits = allCourseUnits; diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index 3aeb60cf4..cac3f1014 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -112,11 +112,13 @@ class ExamCard extends GenericCard { children: [ if (locale == AppLocale.pt) ...[ DateRectangle( - date: '${exam.weekDay}, ${exam.begin.day} de ${exam.month}', + date: '''${exam.weekDay(locale)}, ''' + '''${exam.begin.day} de ${exam.month(locale)}''', ) ] else ...[ DateRectangle( - date: '${exam.weekDay}, ${exam.begin.day} ${exam.month}', + date: '''${exam.weekDay(locale)}, ''' + '''${exam.begin.day} ${exam.month(locale)}''', ) ], RowContainer( From 873446e70023dbd29f3b78c40589e2329cb00855 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Sat, 30 Sep 2023 15:16:57 +0000 Subject: [PATCH 172/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 88ad0f984..342bb1797 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.3+193 \ No newline at end of file +1.7.4+194 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index efb3c6d48..e6a99d2d4 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.3+193 +version: 1.7.4+194 environment: sdk: '>=3.0.0 <4.0.0' From 00f535d9e9b128ea828050a081f3f630f7d8aed3 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Sat, 30 Sep 2023 16:33:16 +0000 Subject: [PATCH 173/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 342bb1797..b99d37531 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.4+194 \ No newline at end of file +1.7.5+195 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index e6a99d2d4..722f37750 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.4+194 +version: 1.7.5+195 environment: sdk: '>=3.0.0 <4.0.0' From c49573cf7ef8402c1c721c833dd72fdb5a0ce6bc Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 29 Sep 2023 13:00:39 +0100 Subject: [PATCH 174/199] Refactor lecture card and show all upcoming classes from today --- uni/lib/view/home/widgets/schedule_card.dart | 92 +++++++++++--------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index edb0e3451..039db9c19 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -1,5 +1,6 @@ -import 'dart:collection'; +import 'dart:math'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:uni/generated/l10n.dart'; @@ -37,7 +38,10 @@ class ScheduleCard extends GenericCard { return LazyConsumer( builder: (context, lectureProvider) => RequestDependentWidgetBuilder( status: lectureProvider.status, - builder: () => generateSchedule(lectureProvider.lectures, context), + builder: () => Column( + mainAxisSize: MainAxisSize.min, + children: getScheduleRows(context, lectureProvider.lectures), + ), hasContentPredicate: lectureProvider.lectures.isNotEmpty, onNullContent: Center( child: Text( @@ -51,53 +55,55 @@ class ScheduleCard extends GenericCard { ); } - Widget generateSchedule( - UnmodifiableListView lectures, - BuildContext context, - ) { - final lectureList = List.of(lectures); - return Column( - mainAxisSize: MainAxisSize.min, - children: getScheduleRows(context, lectureList), - ); - } - List getScheduleRows(BuildContext context, List lectures) { final rows = []; - final now = DateTime.now(); - var added = 0; // Lectures added to widget - var lastAddedLectureDate = DateTime.now(); // Day of last added lecture - - for (var i = 0; added < 2 && i < lectures.length; i++) { - if (now.compareTo(lectures[i].endTime) < 0) { - if (lastAddedLectureDate.weekday != lectures[i].startTime.weekday && - lastAddedLectureDate.compareTo(lectures[i].startTime) <= 0) { - rows.add( - DateRectangle( - date: - Provider.of(context).getWeekdaysWithLocale()[ - (lectures[i].startTime.weekday - 1) % 7], - ), - ); - } - - rows.add(createRowFromLecture(context, lectures[i])); - lastAddedLectureDate = lectures[i].startTime; - added++; + final lecturesByDay = lectures + .groupListsBy( + (lecture) => lecture.startTime.weekday, + ) + .entries + .toList() + .sortedBy((element) { + // Sort by day of the week, but next days come first + final dayDiff = element.key - DateTime.now().weekday; + return dayDiff >= 0 ? dayDiff - 7 : dayDiff; + }).toList(); + + for (final dayLectures + in lecturesByDay.sublist(0, min(2, lecturesByDay.length))) { + final day = dayLectures.key; + final lectures = dayLectures.value + .where( + (element) => + // Hide finished lectures from today + element.startTime.weekday != DateTime.now().weekday || + element.endTime.isAfter(DateTime.now()), + ) + .toList(); + + if (lectures.isEmpty) { + continue; } - } - if (rows.isEmpty) { - rows - ..add( - DateRectangle( - date: Provider.of(context) - .getWeekdaysWithLocale()[lectures[0].startTime.weekday % 7], - ), - ) - ..add(createRowFromLecture(context, lectures[0])); + rows.add( + DateRectangle( + date: Provider.of(context) + .getWeekdaysWithLocale()[(day - 1) % 7], + ), + ); + + for (final lecture in lectures) { + rows.add(createRowFromLecture(context, lecture)); + } + + rows.add(const Padding(padding: EdgeInsets.only(bottom: 10))); + + if (lectures.length >= 2) { + break; + } } + return rows; } From e99778e9b87550551521fcd7509672b7e36e46b6 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Sun, 1 Oct 2023 15:18:28 +0000 Subject: [PATCH 175/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index b99d37531..edea5a341 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.5+195 \ No newline at end of file +1.7.6+196 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 722f37750..b9ac94fd3 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.5+195 +version: 1.7.6+196 environment: sdk: '>=3.0.0 <4.0.0' From e21a2730e7a481e9f40d105fb894cadb85a0a6ef Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Fri, 1 Sep 2023 15:11:28 +0100 Subject: [PATCH 176/199] Fix force push to develop on master hotfixes --- .github/workflows/deploy.yaml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index cbd989070..f32f1a4a2 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -1,9 +1,11 @@ on: push: - branches: [ master, develop ] + branches: [master, develop] jobs: bump_version: + permissions: + actions: "write" name: "Bump pubspec version" runs-on: ubuntu-latest env: @@ -35,9 +37,17 @@ jobs: - uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "Bump app version [no ci]" - - name: Propagate master version bump to develop + + - name: Propagate master version bump to develop if master version is aad if: github.ref == 'refs/heads/master' - run: git push --force-with-lease origin HEAD:develop + run: | + git fetch origin develop + if [[ $(git diff --quiet HEAD~1 origin/develop) ]]; then + echo "Master version does not match develop version" + else + echo "Master version matches develop version" + git push --force-with-lease origin HEAD:develop + fi build: name: "Build App Bundle" @@ -55,7 +65,7 @@ jobs: - uses: actions/setup-java@v3 with: java-version: ${{env.JAVA_VERSION}} - distribution: 'zulu' + distribution: "zulu" - uses: subosito/flutter-action@v2 with: flutter-version: ${{ env.FLUTTER_VERSION }} From c725cc237bef023d083b726382227f4a98d2cb80 Mon Sep 17 00:00:00 2001 From: bdmendes Date: Mon, 2 Oct 2023 12:02:43 +0000 Subject: [PATCH 177/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index edea5a341..01a3e014c 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.6+196 \ No newline at end of file +1.7.7+197 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index b9ac94fd3..3fbb098e2 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.6+196 +version: 1.7.7+197 environment: sdk: '>=3.0.0 <4.0.0' From 1295656581429058def66f7fc2e0e682be3537b3 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 2 Oct 2023 15:57:09 +0100 Subject: [PATCH 178/199] Bug fix --- uni/lib/view/home/widgets/exam_card.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uni/lib/view/home/widgets/exam_card.dart b/uni/lib/view/home/widgets/exam_card.dart index cac3f1014..2c24105f8 100644 --- a/uni/lib/view/home/widgets/exam_card.dart +++ b/uni/lib/view/home/widgets/exam_card.dart @@ -135,6 +135,7 @@ class ExamCard extends GenericCard { /// Creates a row for the exams which will be displayed under the closest /// date exam with a separator between them. Widget createSecondaryRowFromExam(BuildContext context, Exam exam) { + final locale = Provider.of(context).getLocale(); return Container( margin: const EdgeInsets.only(top: 8), child: RowContainer( @@ -145,7 +146,7 @@ class ExamCard extends GenericCard { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '${exam.begin.day} de ${exam.month}', + '${exam.begin.day} de ${exam.month(locale)}', style: Theme.of(context).textTheme.bodyLarge, ), ExamTitle( From 15ad001ebf1cc680a1ee26761cac506c10d59938 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Mon, 2 Oct 2023 15:03:49 +0000 Subject: [PATCH 179/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 01a3e014c..e9f77f982 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.7+197 \ No newline at end of file +1.7.8+198 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 3fbb098e2..3491c6fe4 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.7+197 +version: 1.7.8+198 environment: sdk: '>=3.0.0 <4.0.0' From 4cc432bb1ea5ac0b5828411c48f308cc7165227c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 2 Oct 2023 19:11:10 +0100 Subject: [PATCH 180/199] fix: set stcp certificate as trusted --- uni/assets/certificates/www.stcp.pt.crt | 35 +++++++++++++++++++ .../fetchers/departures_fetcher.dart | 29 ++++++++++++--- uni/pubspec.yaml | 1 + 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 uni/assets/certificates/www.stcp.pt.crt diff --git a/uni/assets/certificates/www.stcp.pt.crt b/uni/assets/certificates/www.stcp.pt.crt new file mode 100644 index 000000000..41a19edb5 --- /dev/null +++ b/uni/assets/certificates/www.stcp.pt.crt @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGFDCCBPygAwIBAgIQAe6h3RyHx1fCpxVViJmEjzANBgkqhkiG9w0BAQsFADBe +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMR0wGwYDVQQDExRUaGF3dGUgVExTIFJTQSBDQSBHMTAe +Fw0yMzA5MjEwMDAwMDBaFw0yNDA5MzAyMzU5NTlaMBYxFDASBgNVBAMTC3d3dy5z +dGNwLnB0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlVSRpvVSkBHk +AsDlP2iPOT3/tgHY2lWdzhMjkOPtNmRKLDooMPXwxm+SkDrXp6QB9TgwfraRCbA4 ++ChodbOs42J//DMAPm6l3MduB0gFbnT+v1R7h9wShjscXW/+Ort/UNAJrBWQzuGN +33T3ToPZAsK8k9UvwkCT0XvdXYT0WQNHY7R1iy9vz4hlbsCB3Ctx00upoulN7rBD +sje915+6prwZGLepvRMMGjRRexdy+YnrzTEmiUS3y236AReIMbCZTpde3+sLySZM +GAAMQt7WFgU5LwWllSixeHUloDRTqIk6NHI47rY0PX/xaWKqI8i80DdGV6WgrWIm +F4D0AensQwIDAQABo4IDFDCCAxAwHwYDVR0jBBgwFoAUpYz+MszrDyzUGcYIuAAk +iF3DxbcwHQYDVR0OBBYEFB+Xw0+CwbbTp2hB/6SGLmyIzsfuMB8GA1UdEQQYMBaC +C3d3dy5zdGNwLnB0ggdzdGNwLnB0MD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYI +KwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8E +BAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDsGA1UdHwQ0MDIw +MKAuoCyGKmh0dHA6Ly9jZHAudGhhd3RlLmNvbS9UaGF3dGVUTFNSU0FDQUcxLmNy +bDBwBggrBgEFBQcBAQRkMGIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9zdGF0dXMudGhh +d3RlLmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NhY2VydHMudGhhd3RlLmNvbS9U +aGF3dGVUTFNSU0FDQUcxLmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIE +AgSCAW8EggFrAWkAdwDuzdBk1dsazsVct520zROiModGfLzs3sNRSFlGcR+1mwAA +AYq3Oc9WAAAEAwBIMEYCIQCAjcEIo5eHyR8otfJ3ohYbV3nkP+MzT/wcsUn+/jmF +nwIhAIrlKEVpz/yUWHPM0xBiW6J8h1YsbBAr6ecuJK6HFYO4AHYASLDja9qmRzQP +5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGKtznPnQAABAMARzBFAiEAok21M0pd +fSfjfuEdtjuTemeeTfGVVmw1CRp7IDRbIIYCIHJa4IgpSKd6eJU06sbgJ01XQF8n +XOTXl0WzRmymNemEAHYA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sA +AAGKtznPuQAABAMARzBFAiBvijwpxIGn+SC+ZrgrcWF/xSNxWzUUQIHvblA90wdI +BgIhALSbLQn8aCQObutPApfT/1bXOSqbrZF2nSOQ+lPwnTsFMA0GCSqGSIb3DQEB +CwUAA4IBAQBlveKOAeFEV21Fd+/DqvNHjIPZdWp651t+cr1i8fxosAFXUJjfLHrh +mpHQrjMUdYnI1SgP6aWxWco7T99/orS4NUmtzb6gVc6MhE1gHLQyQDIY0Z5KJ1/R +D3hldNtiDegMzSir5YPJKQXe8kSp5uHFWmfKqBeB8++V1pCdfOG+yLWKrsAeRFGa +t1qg0++V4AZl91MdfnWGX5DC6dD/1H9c+zxTQqIBA+Ht9a9xk137xgRWJwFdq4Xh +o8cvIhsqqD+M+PY7sijGFLEY2G3MwtYtRBuYAfjQP65rZ1sJcZyip+4Ez4iePwE1 +146k97CUzEYZCHYiBkQaJSYC5FECqnDl +-----END CERTIFICATE----- diff --git a/uni/lib/controller/fetchers/departures_fetcher.dart b/uni/lib/controller/fetchers/departures_fetcher.dart index 921c42113..94234d6ad 100644 --- a/uni/lib/controller/fetchers/departures_fetcher.dart +++ b/uni/lib/controller/fetchers/departures_fetcher.dart @@ -1,24 +1,38 @@ import 'dart:convert'; +import 'dart:io'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; -import 'package:http/http.dart' as http; +import 'package:http/io_client.dart' as http; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/bus.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/entities/trip.dart'; +import 'package:flutter/services.dart' show rootBundle; class DeparturesFetcher { DeparturesFetcher(this._stopCode, this._stopData); final String _stopCode; final BusStopData _stopData; + static final _client = Future.microtask(() async { + final certificateBytes = await rootBundle.load('assets/certificates/www.stcp.pt.crt'); + final securityContext = SecurityContext(withTrustedRoots: true) + ..setTrustedCertificatesBytes(certificateBytes.buffer.asUint8List()); + + return http.IOClient( + HttpClient( + context: securityContext, + ), + ); + }); Future _getCSRFToken() async { final url = 'https://www.stcp.pt/en/travel/timetables/?paragem=$_stopCode&t=smsbus'; - final response = await http.get(url.toUri()); + final client = await _client; + final response = await client.get(url.toUri()); final htmlResponse = parse(response.body); final scriptText = htmlResponse @@ -50,7 +64,8 @@ class DeparturesFetcher { final url = 'https://www.stcp.pt/pt/itinerarium/soapclient.php?codigo=$_stopCode&hash123=$csrfToken'; - final response = await http.get(url.toUri()); + final client = await _client; + final response = await client.get(url.toUri()); final htmlResponse = parse(response.body); final tableEntries = @@ -111,7 +126,9 @@ class DeparturesFetcher { // Search by approximate name final url = 'https://www.stcp.pt/pt/itinerarium/callservice.php?action=srchstoplines&stopname=$stopCode'; - final response = await http.post(url.toUri()); + + final client = await _client; + final response = await client.post(url.toUri()); final json = jsonDecode(response.body) as List; for (final busKey in json) { final bus = busKey as Map; @@ -134,7 +151,9 @@ class DeparturesFetcher { static Future> getBusesStoppingAt(String stop) async { final url = 'https://www.stcp.pt/pt/itinerarium/callservice.php?action=srchstoplines&stopcode=$stop'; - final response = await http.post(url.toUri()); + + final client = await _client; + final response = await client.post(url.toUri()); final json = jsonDecode(response.body) as List; diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 3491c6fe4..2b5b3253b 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -79,6 +79,7 @@ flutter: - assets/text/ - assets/text/locations/ - assets/meal-icons/ + - assets/certificates/ fonts: - family: Raleway fonts: From 1c0061045eb25ab41142d9e588bc0874a73aa74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 2 Oct 2023 19:15:19 +0100 Subject: [PATCH 181/199] refactor: add fixme comment --- uni/lib/controller/fetchers/departures_fetcher.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/uni/lib/controller/fetchers/departures_fetcher.dart b/uni/lib/controller/fetchers/departures_fetcher.dart index 94234d6ad..1ea490b34 100644 --- a/uni/lib/controller/fetchers/departures_fetcher.dart +++ b/uni/lib/controller/fetchers/departures_fetcher.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:io'; +import 'package:flutter/services.dart' show rootBundle; import 'package:html/dom.dart'; import 'package:html/parser.dart'; @@ -8,7 +9,6 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/bus.dart'; import 'package:uni/model/entities/bus_stop.dart'; import 'package:uni/model/entities/trip.dart'; -import 'package:flutter/services.dart' show rootBundle; class DeparturesFetcher { DeparturesFetcher(this._stopCode, this._stopData); @@ -16,9 +16,12 @@ class DeparturesFetcher { final String _stopCode; final BusStopData _stopData; static final _client = Future.microtask(() async { - final certificateBytes = await rootBundle.load('assets/certificates/www.stcp.pt.crt'); + // FIXME(limwa): replace `rootBundle` with `DefaultAssetBundle.of(context)` + final certificateBytes = + await rootBundle.load('assets/certificates/www.stcp.pt.crt'); + final securityContext = SecurityContext(withTrustedRoots: true) - ..setTrustedCertificatesBytes(certificateBytes.buffer.asUint8List()); + ..setTrustedCertificatesBytes(certificateBytes.buffer.asUint8List()); return http.IOClient( HttpClient( From 10473454f295cf7edbc9363681987bd7b9b79e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 2 Oct 2023 20:25:57 +0100 Subject: [PATCH 182/199] fix: disable ssl verification for www.stcp.pt --- uni/assets/certificates/www.stcp.pt.crt | 35 ------------------- .../fetchers/departures_fetcher.dart | 32 +++++------------ uni/pubspec.yaml | 1 - 3 files changed, 9 insertions(+), 59 deletions(-) delete mode 100644 uni/assets/certificates/www.stcp.pt.crt diff --git a/uni/assets/certificates/www.stcp.pt.crt b/uni/assets/certificates/www.stcp.pt.crt deleted file mode 100644 index 41a19edb5..000000000 --- a/uni/assets/certificates/www.stcp.pt.crt +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGFDCCBPygAwIBAgIQAe6h3RyHx1fCpxVViJmEjzANBgkqhkiG9w0BAQsFADBe -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMR0wGwYDVQQDExRUaGF3dGUgVExTIFJTQSBDQSBHMTAe -Fw0yMzA5MjEwMDAwMDBaFw0yNDA5MzAyMzU5NTlaMBYxFDASBgNVBAMTC3d3dy5z -dGNwLnB0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlVSRpvVSkBHk -AsDlP2iPOT3/tgHY2lWdzhMjkOPtNmRKLDooMPXwxm+SkDrXp6QB9TgwfraRCbA4 -+ChodbOs42J//DMAPm6l3MduB0gFbnT+v1R7h9wShjscXW/+Ort/UNAJrBWQzuGN -33T3ToPZAsK8k9UvwkCT0XvdXYT0WQNHY7R1iy9vz4hlbsCB3Ctx00upoulN7rBD -sje915+6prwZGLepvRMMGjRRexdy+YnrzTEmiUS3y236AReIMbCZTpde3+sLySZM -GAAMQt7WFgU5LwWllSixeHUloDRTqIk6NHI47rY0PX/xaWKqI8i80DdGV6WgrWIm -F4D0AensQwIDAQABo4IDFDCCAxAwHwYDVR0jBBgwFoAUpYz+MszrDyzUGcYIuAAk -iF3DxbcwHQYDVR0OBBYEFB+Xw0+CwbbTp2hB/6SGLmyIzsfuMB8GA1UdEQQYMBaC -C3d3dy5zdGNwLnB0ggdzdGNwLnB0MD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYI -KwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8E -BAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDsGA1UdHwQ0MDIw -MKAuoCyGKmh0dHA6Ly9jZHAudGhhd3RlLmNvbS9UaGF3dGVUTFNSU0FDQUcxLmNy -bDBwBggrBgEFBQcBAQRkMGIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9zdGF0dXMudGhh -d3RlLmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NhY2VydHMudGhhd3RlLmNvbS9U -aGF3dGVUTFNSU0FDQUcxLmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIE -AgSCAW8EggFrAWkAdwDuzdBk1dsazsVct520zROiModGfLzs3sNRSFlGcR+1mwAA -AYq3Oc9WAAAEAwBIMEYCIQCAjcEIo5eHyR8otfJ3ohYbV3nkP+MzT/wcsUn+/jmF -nwIhAIrlKEVpz/yUWHPM0xBiW6J8h1YsbBAr6ecuJK6HFYO4AHYASLDja9qmRzQP -5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGKtznPnQAABAMARzBFAiEAok21M0pd -fSfjfuEdtjuTemeeTfGVVmw1CRp7IDRbIIYCIHJa4IgpSKd6eJU06sbgJ01XQF8n -XOTXl0WzRmymNemEAHYA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sA -AAGKtznPuQAABAMARzBFAiBvijwpxIGn+SC+ZrgrcWF/xSNxWzUUQIHvblA90wdI -BgIhALSbLQn8aCQObutPApfT/1bXOSqbrZF2nSOQ+lPwnTsFMA0GCSqGSIb3DQEB -CwUAA4IBAQBlveKOAeFEV21Fd+/DqvNHjIPZdWp651t+cr1i8fxosAFXUJjfLHrh -mpHQrjMUdYnI1SgP6aWxWco7T99/orS4NUmtzb6gVc6MhE1gHLQyQDIY0Z5KJ1/R -D3hldNtiDegMzSir5YPJKQXe8kSp5uHFWmfKqBeB8++V1pCdfOG+yLWKrsAeRFGa -t1qg0++V4AZl91MdfnWGX5DC6dD/1H9c+zxTQqIBA+Ht9a9xk137xgRWJwFdq4Xh -o8cvIhsqqD+M+PY7sijGFLEY2G3MwtYtRBuYAfjQP65rZ1sJcZyip+4Ez4iePwE1 -146k97CUzEYZCHYiBkQaJSYC5FECqnDl ------END CERTIFICATE----- diff --git a/uni/lib/controller/fetchers/departures_fetcher.dart b/uni/lib/controller/fetchers/departures_fetcher.dart index 1ea490b34..64e2d3585 100644 --- a/uni/lib/controller/fetchers/departures_fetcher.dart +++ b/uni/lib/controller/fetchers/departures_fetcher.dart @@ -1,6 +1,5 @@ import 'dart:convert'; import 'dart:io'; -import 'package:flutter/services.dart' show rootBundle; import 'package:html/dom.dart'; import 'package:html/parser.dart'; @@ -15,27 +14,17 @@ class DeparturesFetcher { final String _stopCode; final BusStopData _stopData; - static final _client = Future.microtask(() async { - // FIXME(limwa): replace `rootBundle` with `DefaultAssetBundle.of(context)` - final certificateBytes = - await rootBundle.load('assets/certificates/www.stcp.pt.crt'); - - final securityContext = SecurityContext(withTrustedRoots: true) - ..setTrustedCertificatesBytes(certificateBytes.buffer.asUint8List()); - - return http.IOClient( - HttpClient( - context: securityContext, - ), - ); - }); + static final _client = http.IOClient( + HttpClient(context: SecurityContext()) + ..badCertificateCallback = + (cert, host, port) => host == 'www.stcp.pt' && port == 443, + ); Future _getCSRFToken() async { final url = 'https://www.stcp.pt/en/travel/timetables/?paragem=$_stopCode&t=smsbus'; - final client = await _client; - final response = await client.get(url.toUri()); + final response = await _client.get(url.toUri()); final htmlResponse = parse(response.body); final scriptText = htmlResponse @@ -67,8 +56,7 @@ class DeparturesFetcher { final url = 'https://www.stcp.pt/pt/itinerarium/soapclient.php?codigo=$_stopCode&hash123=$csrfToken'; - final client = await _client; - final response = await client.get(url.toUri()); + final response = await _client.get(url.toUri()); final htmlResponse = parse(response.body); final tableEntries = @@ -130,8 +118,7 @@ class DeparturesFetcher { final url = 'https://www.stcp.pt/pt/itinerarium/callservice.php?action=srchstoplines&stopname=$stopCode'; - final client = await _client; - final response = await client.post(url.toUri()); + final response = await _client.post(url.toUri()); final json = jsonDecode(response.body) as List; for (final busKey in json) { final bus = busKey as Map; @@ -155,8 +142,7 @@ class DeparturesFetcher { final url = 'https://www.stcp.pt/pt/itinerarium/callservice.php?action=srchstoplines&stopcode=$stop'; - final client = await _client; - final response = await client.post(url.toUri()); + final response = await _client.post(url.toUri()); final json = jsonDecode(response.body) as List; diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 2b5b3253b..3491c6fe4 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -79,7 +79,6 @@ flutter: - assets/text/ - assets/text/locations/ - assets/meal-icons/ - - assets/certificates/ fonts: - family: Raleway fonts: From 7d54a9b93ae2a34c76fbad10a3b9820681411af7 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Mon, 2 Oct 2023 20:10:48 +0000 Subject: [PATCH 183/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index e9f77f982..b7cdb1a37 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.8+198 \ No newline at end of file +1.7.9+199 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 3491c6fe4..596254755 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.8+198 +version: 1.7.9+199 environment: sdk: '>=3.0.0 <4.0.0' From cd7ed30c715cbd6ad2a5ba994859e46bdb3e6c39 Mon Sep 17 00:00:00 2001 From: luis Date: Tue, 3 Oct 2023 22:27:55 +0100 Subject: [PATCH 184/199] Fixed library colors & max percentage --- uni/lib/model/entities/library_occupation.dart | 10 ++++++---- uni/lib/view/library/library.dart | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/uni/lib/model/entities/library_occupation.dart b/uni/lib/model/entities/library_occupation.dart index bb299bbda..79e739c77 100644 --- a/uni/lib/model/entities/library_occupation.dart +++ b/uni/lib/model/entities/library_occupation.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + /// Overall occupation of the library class LibraryOccupation { LibraryOccupation(this.occupation, this.capacity) { @@ -14,8 +16,8 @@ class LibraryOccupation { } int get percentage { - if (capacity == 0) return 0; - return (occupation * 100 / capacity).round(); + if (capacity <= 0) return 0; + return min(100, (occupation * 100 / capacity).round()); } FloorOccupation getFloor(int number) { @@ -32,8 +34,8 @@ class FloorOccupation { final int capacity; int get percentage { - if (capacity == 0) return 0; - return (occupation * 100 / capacity).round(); + if (capacity <= 0) return 0; + return min(100, (occupation * 100 / capacity).round()); } Map toMap() { diff --git a/uni/lib/view/library/library.dart b/uni/lib/view/library/library.dart index 17f9d0f7c..d34c9de99 100644 --- a/uni/lib/view/library/library.dart +++ b/uni/lib/view/library/library.dart @@ -113,7 +113,7 @@ class LibraryPage extends StatelessWidget { style: Theme.of(context) .textTheme .titleLarge - ?.copyWith(color: Theme.of(context).colorScheme.background), + ?.copyWith(color: Theme.of(context).colorScheme.secondary), ), LinearPercentIndicator( lineHeight: 7, From f5afe1090a46f4aea2bfccccbae521739ad28cb6 Mon Sep 17 00:00:00 2001 From: limwa Date: Wed, 4 Oct 2023 18:03:25 +0000 Subject: [PATCH 185/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index b7cdb1a37..5f7f9d3f3 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.9+199 \ No newline at end of file +1.7.10+200 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 596254755..356067f04 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.9+199 +version: 1.7.10+200 environment: sdk: '>=3.0.0 <4.0.0' From c100804c61700e9dd4c6330edbb54f63fe8ac391 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Sat, 23 Sep 2023 14:16:42 +0100 Subject: [PATCH 186/199] Stage pubspec lock file --- .gitignore | 1 - uni/.gitignore | 1 - uni/pubspec.lock | 1360 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1360 insertions(+), 2 deletions(-) create mode 100644 uni/pubspec.lock diff --git a/.gitignore b/.gitignore index aa2b7a871..04c23541d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ .pub/ build/ *.bin -uni/pubspec.lock .flutter-plugins* # IDE files diff --git a/uni/.gitignore b/uni/.gitignore index a0cabb6dc..a20521678 100644 --- a/uni/.gitignore +++ b/uni/.gitignore @@ -1,6 +1,5 @@ # Miscellaneous *.class -*.lock *.log *.pyc *.swp diff --git a/uni/pubspec.lock b/uni/pubspec.lock new file mode 100644 index 000000000..e336b67cc --- /dev/null +++ b/uni/pubspec.lock @@ -0,0 +1,1360 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + add_2_calendar: + dependency: "direct main" + description: + name: add_2_calendar + sha256: "01a5b15a9385eff803cd84da3d7cda71de7ad807b6c88e44a8ad4acbd80f3b7e" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + animated_stack_widget: + dependency: transitive + description: + name: animated_stack_widget + sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408 + url: "https://pub.dev" + source: hosted + version: "0.0.4" + archive: + dependency: transitive + description: + name: archive + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + url: "https://pub.dev" + source: hosted + version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 + url: "https://pub.dev" + source: hosted + version: "2.3.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" + url: "https://pub.dev" + source: hosted + version: "2.4.6" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + url: "https://pub.dev" + source: hosted + version: "7.2.10" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + url: "https://pub.dev" + source: hosted + version: "8.6.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 + url: "https://pub.dev" + source: hosted + version: "3.2.3" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + url: "https://pub.dev" + source: hosted + version: "4.5.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.dev" + source: hosted + version: "1.17.1" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" + source: hosted + version: "1.2.4" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" + url: "https://pub.dev" + source: hosted + version: "1.6.3" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.dev" + source: hosted + version: "1.0.5" + currency_text_input_formatter: + dependency: "direct main" + description: + name: currency_text_input_formatter + sha256: "5d8db755ccde76817f6f5fb33e65304d7b1db442e1ccff079fe235584c6b7d5a" + url: "https://pub.dev" + source: hosted + version: "2.1.10" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + dbus: + dependency: transitive + description: + name: dbus + sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" + url: "https://pub.dev" + source: hosted + version: "0.7.8" + email_validator: + dependency: "direct main" + description: + name: email_validator + sha256: e9a90f27ab2b915a27d7f9c2a7ddda5dd752d6942616ee83529b686fc086221b + url: "https://pub.dev" + source: hosted + version: "2.1.17" + encrypt: + dependency: "direct main" + description: + name: encrypt + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" + url: "https://pub.dev" + source: hosted + version: "5.0.3" + expansion_tile_card: + dependency: "direct main" + description: + name: expansion_tile_card + sha256: "27ce4cb518f00e21d0f2309aaa6462b26b148e93cee2029a73088cecf42b1eb0" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_blurhash: + dependency: transitive + description: + name: flutter_blurhash + sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + url: "https://pub.dev" + source: hosted + version: "3.3.1" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + url: "https://pub.dev" + source: hosted + version: "0.13.1" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: "3002092e5b8ce2f86c3361422e52e6db6776c23ee21e0b2f71b892bf4259ef04" + url: "https://pub.dev" + source: hosted + version: "15.1.1" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" + url: "https://pub.dev" + source: hosted + version: "4.0.0+1" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" + url: "https://pub.dev" + source: hosted + version: "7.0.0+1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: "52c65a977daae42f9aae6748418dd1535eaf27186e9bac9bf431843082bc75a3" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_map_marker_popup: + dependency: "direct main" + description: + name: flutter_map_marker_popup + sha256: d4e22a00dd46f95a6f54c60b92950bd6f41021ca36629b1cf3fa0bf4fd39f421 + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0 + url: "https://pub.dev" + source: hosted + version: "0.6.15" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: f991fdb1533c3caeee0cdc14b04f50f0c3916f0dbcbc05237ccbe4e3c6b93f3f + url: "https://pub.dev" + source: hosted + version: "2.0.5" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_widget_from_html_core: + dependency: "direct main" + description: + name: flutter_widget_from_html_core + sha256: "719da7fba82343efb9ad3be528a768dec4a4d8f3b37ebd9eef8d93e891a1d58f" + url: "https://pub.dev" + source: hosted + version: "0.10.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + html: + dependency: "direct main" + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: "direct main" + description: + name: image + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf + url: "https://pub.dev" + source: hosted + version: "4.0.17" + intl: + dependency: "direct main" + description: + name: intl + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + url: "https://pub.dev" + source: hosted + version: "0.18.0" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "08ef7282ba9f76e8495e49e2dc4d653015ac929dce5f92b375a415d30b407ea0" + url: "https://pub.dev" + source: hosted + version: "0.8.2" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + logger: + dependency: "direct main" + description: + name: logger + sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: acf35edccc0463a9d7384e437c015a3535772e09714cf60e07eeef3a15870dcd + url: "https://pub.dev" + source: hosted + version: "7.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.dev" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + material_design_icons_flutter: + dependency: "direct main" + description: + name: material_design_icons_flutter + sha256: "6f986b7a51f3ad4c00e33c5c84e8de1bdd140489bbcdc8b66fc1283dad4dea5a" + url: "https://pub.dev" + source: hosted + version: "7.0.7296" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" + mockito: + dependency: "direct dev" + description: + path: "." + ref: e54a006 + resolved-ref: e54a00667cbe9a27de08e4c0ea355bacbe8c98d0 + url: "https://github.com/dart-lang/mockito.git" + source: git + version: "5.4.3-wip" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + path: + dependency: "direct main" + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" + source: hosted + version: "1.8.3" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.dev" + source: hosted + version: "2.0.15" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.dev" + source: hosted + version: "2.0.27" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" + source: hosted + version: "2.1.11" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.dev" + source: hosted + version: "2.1.7" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + url: "https://pub.dev" + source: hosted + version: "4.2.3" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" + provider: + dependency: "direct main" + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" + sentry: + dependency: transitive + description: + name: sentry + sha256: "39c23342fc96105da449914f7774139a17a0ca8a4e70d9ad5200171f7e47d6ba" + url: "https://pub.dev" + source: hosted + version: "7.9.0" + sentry_flutter: + dependency: "direct main" + description: + name: sentry_flutter + sha256: ff68ab31918690da004a42e20204242a3ad9ad57da7e2712da8487060ac9767f + url: "https://pub.dev" + source: hosted + version: "7.9.0" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + shimmer: + dependency: "direct main" + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33" + url: "https://pub.dev" + source: hosted + version: "1.3.2" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" + source: hosted + version: "1.9.1" + sqflite: + dependency: "direct main" + description: + name: sqflite + sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 + url: "https://pub.dev" + source: hosted + version: "2.2.8+4" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f" + url: "https://pub.dev" + source: hosted + version: "2.4.5+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: "direct main" + description: + name: synchronized + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" + url: "https://pub.dev" + source: hosted + version: "1.24.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + timelines: + dependency: "direct main" + description: + name: timelines + sha256: "40214f5ab772ff45459cb8c15e5f60505a6828af0c0eb1eec6f29ed911a4c1c5" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + timezone: + dependency: transitive + description: + name: timezone + sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + tuple: + dependency: "direct main" + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + url: "https://pub.dev" + source: hosted + version: "6.1.11" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" + url: "https://pub.dev" + source: hosted + version: "6.0.36" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.dev" + source: hosted + version: "6.1.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + url: "https://pub.dev" + source: hosted + version: "2.1.3" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + url: "https://pub.dev" + source: hosted + version: "2.0.18" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: ea8d3fc7b2e0f35de38a7465063ecfcf03d8217f7962aa2a6717132cb5d43a79 + url: "https://pub.dev" + source: hosted + version: "1.1.5" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: a5eaa5d19e123ad4f61c3718ca1ed921c4e6254238d9145f82aa214955d9aced + url: "https://pub.dev" + source: hosted + version: "1.1.5" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "15edc42f7eaa478ce854eaf1fbb9062a899c0e4e56e775dd73b7f4709c97c4ca" + url: "https://pub.dev" + source: hosted + version: "1.1.5" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + very_good_analysis: + dependency: "direct dev" + description: + name: very_good_analysis + sha256: "9ae7f3a3bd5764fb021b335ca28a34f040cd0ab6eec00a1b213b445dae58a4b8" + url: "https://pub.dev" + source: hosted + version: "5.1.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + url: "https://pub.dev" + source: hosted + version: "9.4.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" + source: hosted + version: "2.4.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" + source: hosted + version: "4.1.4" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + workmanager: + dependency: "direct main" + description: + name: workmanager + sha256: e0be7e35d644643f164ee45d2ce14414f0e0fdde19456aa66065f35a0b1d2ea1 + url: "https://pub.dev" + source: hosted + version: "0.5.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + xml: + dependency: transitive + description: + name: xml + sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.6" From aeb926fc577264452a79dad1e2c959df02e63486 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Mon, 2 Oct 2023 12:11:08 +0100 Subject: [PATCH 187/199] Bump packages, bump courses db version, further remove try/catch, fix forced logout --- .../background_callback.dart | 8 +- .../all_course_units_fetcher.dart | 18 ++--- .../controller/fetchers/profile_fetcher.dart | 35 ++++----- .../load_static/terms_and_conditions.dart | 24 ++---- .../local_storage/app_courses_database.dart | 2 +- .../local_storage/app_database.dart | 28 ++++--- .../local_storage/app_exams_database.dart | 2 +- .../controller/networking/network_router.dart | 73 ++++++++++--------- .../parsers/parser_course_units.dart | 2 +- uni/lib/main.dart | 25 ++++--- uni/lib/model/entities/course.dart | 4 +- uni/lib/model/entities/exam.dart | 6 -- uni/lib/model/entities/trip.dart | 7 -- .../providers/state_provider_notifier.dart | 59 +++++++++------ uni/lib/view/bug_report/widgets/form.dart | 16 ++-- .../view/common_widgets/page_transition.dart | 2 +- .../view/locations/widgets/faculty_map.dart | 6 +- uni/lib/view/login/login.dart | 6 +- uni/lib/view/navigation_service.dart | 19 ++--- uni/pubspec.yaml | 8 +- 20 files changed, 178 insertions(+), 172 deletions(-) diff --git a/uni/lib/controller/background_workers/background_callback.dart b/uni/lib/controller/background_workers/background_callback.dart index 9c9f45536..bf89d1e07 100644 --- a/uni/lib/controller/background_workers/background_callback.dart +++ b/uni/lib/controller/background_workers/background_callback.dart @@ -35,8 +35,12 @@ Future workerStartCallback() async { //try to keep the usage of this function BELOW +-30 seconds //to not be punished by the scheduler in future runs. await taskMap[taskName]!.item1(); - } catch (err, stackstrace) { - Logger().e('Error while running $taskName job:', err, stackstrace); + } catch (err, stackTrace) { + Logger().e( + 'Error while running $taskName job:', + error: err, + stackTrace: stackTrace, + ); return false; } return true; diff --git a/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index f0d87293b..c84932de1 100644 --- a/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/uni/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -1,4 +1,3 @@ -import 'package:logger/logger.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_units.dart'; import 'package:uni/model/entities/course.dart'; @@ -14,17 +13,12 @@ class AllCourseUnitsFetcher { final allCourseUnits = []; for (final course in courses) { - try { - final courseUnits = await _getAllCourseUnitsAndCourseAveragesFromCourse( - course, - session, - currentCourseUnits: currentCourseUnits, - ); - allCourseUnits.addAll(courseUnits.where((c) => c.enrollmentIsValid())); - } catch (e) { - Logger().e('Failed to fetch course units for ${course.name}', e); - return null; - } + final courseUnits = await _getAllCourseUnitsAndCourseAveragesFromCourse( + course, + session, + currentCourseUnits: currentCourseUnits, + ); + allCourseUnits.addAll(courseUnits.where((c) => c.enrollmentIsValid())); } return allCourseUnits; diff --git a/uni/lib/controller/fetchers/profile_fetcher.dart b/uni/lib/controller/fetchers/profile_fetcher.dart index 56a239d64..17028f34c 100644 --- a/uni/lib/controller/fetchers/profile_fetcher.dart +++ b/uni/lib/controller/fetchers/profile_fetcher.dart @@ -1,4 +1,3 @@ -import 'package:logger/logger.dart'; import 'package:uni/controller/fetchers/courses_fetcher.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; @@ -30,27 +29,23 @@ class ProfileFetcher implements SessionDependantFetcher { } final profile = Profile.fromResponse(response); - try { - final coursesResponses = await Future.wait( - CoursesFetcher().getCoursesListResponses(session), - ); - final courses = parseMultipleCourses(coursesResponses); - for (final course in courses) { - if (profile.courses - .map((c) => c.festId) - .toList() - .contains(course.festId)) { - profile.courses - .where((c) => c.festId == course.festId) - .first - .state ??= course.state; - continue; - } - profile.courses.add(course); + final coursesResponses = await Future.wait( + CoursesFetcher().getCoursesListResponses(session), + ); + final courses = parseMultipleCourses(coursesResponses); + + for (final course in courses) { + if (profile.courses + .map((c) => c.festId) + .toList() + .contains(course.festId)) { + profile.courses.where((c) => c.festId == course.festId).first.state ??= + course.state; + continue; } - } catch (e) { - Logger().e('Failed to get user courses via scrapping: $e'); + profile.courses.add(course); } + return profile; } } diff --git a/uni/lib/controller/load_static/terms_and_conditions.dart b/uni/lib/controller/load_static/terms_and_conditions.dart index ba6945175..e5e5fc5da 100644 --- a/uni/lib/controller/load_static/terms_and_conditions.dart +++ b/uni/lib/controller/load_static/terms_and_conditions.dart @@ -4,7 +4,6 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:crypto/crypto.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:http/http.dart' as http; -import 'package:logger/logger.dart'; import 'package:uni/controller/local_storage/app_shared_preferences.dart'; /// Returns the content of the Terms and Conditions remote file, @@ -13,25 +12,14 @@ import 'package:uni/controller/local_storage/app_shared_preferences.dart'; /// If this operation is unsuccessful, an error message is returned. Future fetchTermsAndConditions() async { if (await Connectivity().checkConnectivity() != ConnectivityResult.none) { - try { - const url = - 'https://raw.githubusercontent.com/NIAEFEUP/project-schrodinger/develop/uni/assets/text/TermsAndConditions.md'; - final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - return response.body; - } - } catch (e) { - Logger().e('Failed to fetch Terms and Conditions: $e'); + const url = + 'https://raw.githubusercontent.com/NIAEFEUP/project-schrodinger/develop/uni/assets/text/TermsAndConditions.md'; + final response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + return response.body; } } - - try { - return await rootBundle.loadString('assets/text/TermsAndConditions.md'); - } catch (e) { - Logger().e('Failed to read Terms and Conditions: $e'); - return 'Não foi possível carregar os Termos e Condições. ' - 'Por favor tente mais tarde.'; - } + return rootBundle.loadString('assets/text/TermsAndConditions.md'); } /// Checks if the current Terms and Conditions have been accepted by the user, diff --git a/uni/lib/controller/local_storage/app_courses_database.dart b/uni/lib/controller/local_storage/app_courses_database.dart index f9130e050..db7d9ac6a 100644 --- a/uni/lib/controller/local_storage/app_courses_database.dart +++ b/uni/lib/controller/local_storage/app_courses_database.dart @@ -10,7 +10,7 @@ import 'package:uni/model/entities/course.dart'; /// See the [Course] class to see what data is stored in this database. class AppCoursesDatabase extends AppDatabase { AppCoursesDatabase() - : super('courses.db', [createScript], onUpgrade: migrate, version: 2); + : super('courses.db', [createScript], onUpgrade: migrate, version: 3); static const String createScript = '''CREATE TABLE courses(id INTEGER, fest_id INTEGER, name TEXT, ''' '''abbreviation TEXT, currYear TEXT, firstEnrollment INTEGER, state TEXT, ''' diff --git a/uni/lib/controller/local_storage/app_database.dart b/uni/lib/controller/local_storage/app_database.dart index c24800d5a..885cba9f3 100644 --- a/uni/lib/controller/local_storage/app_database.dart +++ b/uni/lib/controller/local_storage/app_database.dart @@ -20,7 +20,10 @@ class AppDatabase { /// A list of commands to be executed on database creation. List commands; - // A lock that synchronizes all database insertions. + /// The lock timeout for database operations. + static const Duration lockTimeout = Duration(seconds: 10); + + /// A lock that synchronizes all database insertions. static Lock lock = Lock(); /// A function that is called when the [version] changes. @@ -42,16 +45,19 @@ class AppDatabase { String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm, }) async { - await lock.synchronized(() async { - final db = await getDatabase(); - - await db.insert( - table, - values, - nullColumnHack: nullColumnHack, - conflictAlgorithm: conflictAlgorithm, - ); - }); + await lock.synchronized( + () async { + final db = await getDatabase(); + + await db.insert( + table, + values, + nullColumnHack: nullColumnHack, + conflictAlgorithm: conflictAlgorithm, + ); + }, + timeout: lockTimeout, + ); } /// Initializes this database. diff --git a/uni/lib/controller/local_storage/app_exams_database.dart b/uni/lib/controller/local_storage/app_exams_database.dart index f56ae0a0a..36264e347 100644 --- a/uni/lib/controller/local_storage/app_exams_database.dart +++ b/uni/lib/controller/local_storage/app_exams_database.dart @@ -10,7 +10,7 @@ import 'package:uni/model/entities/exam.dart'; /// See the [Exam] class to see what data is stored in this database. class AppExamsDatabase extends AppDatabase { AppExamsDatabase() - : super('exams.db', [_createScript], onUpgrade: migrate, version: 4); + : super('exams.db', [_createScript], onUpgrade: migrate, version: 5); Map months = { 'Janeiro': '01', 'Fevereiro': '02', diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index f05d88d54..d84ff6c95 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -44,44 +44,47 @@ class NetworkRouter { List faculties, { required bool persistentSession, }) async { - return _loginLock.synchronized(() async { - if (_lastLoginTime != null && - DateTime.now().difference(_lastLoginTime!) < - const Duration(minutes: 1) && - _cachedSession != null) { - Logger().d('Login request ignored due to recent login'); - return _cachedSession; - } + return _loginLock.synchronized( + () async { + if (_lastLoginTime != null && + DateTime.now().difference(_lastLoginTime!) < + const Duration(minutes: 1) && + _cachedSession != null) { + Logger().d('Login request ignored due to recent login'); + return _cachedSession; + } - final url = - '${NetworkRouter.getBaseUrls(faculties)[0]}mob_val_geral.autentica'; - final response = await http.post( - url.toUri(), - body: {'pv_login': username, 'pv_password': password}, - ).timeout(_requestTimeout); + final url = + '${NetworkRouter.getBaseUrls(faculties)[0]}mob_val_geral.autentica'; + final response = await http.post( + url.toUri(), + body: {'pv_login': username, 'pv_password': password}, + ).timeout(_requestTimeout); - if (response.statusCode != 200) { - Logger().e('Login failed with status code ${response.statusCode}'); - return null; - } + if (response.statusCode != 200) { + Logger().e('Login failed with status code ${response.statusCode}'); + return null; + } - final session = Session.fromLogin( - response, - faculties, - persistentSession: persistentSession, - ); + final session = Session.fromLogin( + response, + faculties, + persistentSession: persistentSession, + ); - if (session == null) { - Logger().e('Login failed: user not authenticated'); - return null; - } + if (session == null) { + Logger().e('Login failed: user not authenticated'); + return null; + } - Logger().i('Login successful'); - _lastLoginTime = DateTime.now(); - _cachedSession = session; + Logger().i('Login successful'); + _lastLoginTime = DateTime.now(); + _cachedSession = session; - return session; - }); + return session; + }, + timeout: _requestTimeout, + ); } /// Re-authenticates the user via the Sigarra API @@ -182,8 +185,10 @@ class NetworkRouter { final newSession = await reLoginFromSession(session); if (newSession == null) { - NavigationService.logoutAndPopHistory(null); - return Future.error('Login failed'); + NavigationService.logoutAndPopHistory(); + return Future.error( + 'Re-login failed; user might have changed password', + ); } session diff --git a/uni/lib/controller/parsers/parser_course_units.dart b/uni/lib/controller/parsers/parser_course_units.dart index c57764d2a..f9a1d7949 100644 --- a/uni/lib/controller/parsers/parser_course_units.dart +++ b/uni/lib/controller/parsers/parser_course_units.dart @@ -82,7 +82,7 @@ List parseCourseUnitsAndCourseAverage( codeName, // FIXME: this is not the abbreviation status: status, grade: grade, - ects: double.parse(ects), + ects: double.tryParse(ects), name: name, curricularYear: int.parse(year), semesterCode: semester, diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 407d18030..01fac7edd 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -89,7 +89,12 @@ Future main() async { await dotenv .load(fileName: 'assets/env/.env', isOptional: true) .onError((error, stackTrace) { - Logger().e('Error loading .env file: $error', error, stackTrace); + Sentry.captureException(error, stackTrace: stackTrace); + Logger().e( + 'Error loading .env file: $error', + error: error, + stackTrace: stackTrace, + ); }); final savedTheme = await AppSharedPreferences.getThemeMode(); @@ -148,28 +153,29 @@ Future main() async { create: (_) => ThemeNotifier(savedTheme), ), ], - child: MyApp(route), + child: Application(route), ), ); }, ); } -/// Manages the state of the app -/// +/// Manages the state of the app. /// This class is necessary to track the app's state for -/// the current execution -class MyApp extends StatefulWidget { - const MyApp(this.initialRoute, {super.key}); +/// the current execution. +class Application extends StatefulWidget { + const Application(this.initialRoute, {super.key}); final String initialRoute; + static GlobalKey navigatorKey = GlobalKey(); + @override - State createState() => MyAppState(); + State createState() => ApplicationState(); } /// Manages the app depending on its current state -class MyAppState extends State { +class ApplicationState extends State { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([ @@ -178,6 +184,7 @@ class MyAppState extends State { return Consumer2( builder: (context, themeNotifier, localeNotifier, _) => MaterialApp( title: 'uni', + navigatorKey: Application.navigatorKey, theme: applicationLightTheme, darkTheme: applicationDarkTheme, themeMode: themeNotifier.getTheme(), diff --git a/uni/lib/model/entities/course.dart b/uni/lib/model/entities/course.dart index 1c739fb42..645aa7cef 100644 --- a/uni/lib/model/entities/course.dart +++ b/uni/lib/model/entities/course.dart @@ -23,8 +23,8 @@ class Course { /// Creates a new instance from a JSON object. Course.fromJson(Map data) - : id = data['cur_id'] as int, - festId = data['fest_id'] as int, + : id = (data['cur_id'] ?? 0) as int, + festId = (data['fest_id'] ?? 0) as int, name = data['cur_nome'] as String?, currYear = data['ano_curricular'] as String?, firstEnrollment = data['fest_a_lect_1_insc'] as int, diff --git a/uni/lib/model/entities/exam.dart b/uni/lib/model/entities/exam.dart index fb29f704a..1bfe20d0f 100644 --- a/uni/lib/model/entities/exam.dart +++ b/uni/lib/model/entities/exam.dart @@ -1,5 +1,4 @@ import 'package:intl/intl.dart'; -import 'package:logger/logger.dart'; import 'package:uni/model/entities/app_locale.dart'; /// Manages a generic Exam. @@ -87,11 +86,6 @@ class Exam { return '''$id - $subject - ${begin.year} - $month - ${begin.day} - $beginTime-$endTime - $type - $rooms - $weekDay'''; } - /// Prints the data in this exam to the [Logger] with an INFO level. - void printExam() { - Logger().i(toString()); - } - @override bool operator ==(Object other) => identical(this, other) || other is Exam && id == other.id; diff --git a/uni/lib/model/entities/trip.dart b/uni/lib/model/entities/trip.dart index 73b4ce6b4..616ce1c62 100644 --- a/uni/lib/model/entities/trip.dart +++ b/uni/lib/model/entities/trip.dart @@ -1,5 +1,3 @@ -import 'package:logger/logger.dart'; - /// Stores information about a bus trip. class Trip { Trip({ @@ -20,11 +18,6 @@ class Trip { }; } - /// Prints the data in this trip to the [Logger] with an INFO level. - void printTrip() { - Logger().i('$line ($destination) - $timeRemaining'); - } - /// Compares the remaining time of two trips. int compare(Trip other) { return timeRemaining.compareTo(other.timeRemaining); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 81543fd8b..6f4bbd9a7 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -22,6 +22,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromStorage = !initialize, _initializedFromRemote = !initialize; + static const lockTimeout = Duration(seconds: 10); final Lock _lock = Lock(); final RequestStatus _initialStatus; RequestStatus _status; @@ -124,12 +125,18 @@ abstract class StateProviderNotifier extends ChangeNotifier { } Future forceRefresh(BuildContext context) async { - await _lock.synchronized(() async { - final session = context.read().session; - final profile = context.read().profile; - _updateStatus(RequestStatus.busy); - await _loadFromRemote(session, profile, force: true); - }); + await _lock.synchronized( + () async { + if (!context.mounted) { + return; + } + final session = context.read().session; + final profile = context.read().profile; + _updateStatus(RequestStatus.busy); + await _loadFromRemote(session, profile, force: true); + }, + timeout: lockTimeout, + ); } Future ensureInitialized(BuildContext context) async { @@ -141,32 +148,38 @@ abstract class StateProviderNotifier extends ChangeNotifier { } Future ensureInitializedFromRemote(BuildContext context) async { - await _lock.synchronized(() async { - if (_initializedFromRemote) { - return; - } + await _lock.synchronized( + () async { + if (_initializedFromRemote || !context.mounted) { + return; + } - _initializedFromRemote = true; + final session = context.read().session; + final profile = context.read().profile; - final session = context.read().session; - final profile = context.read().profile; + _initializedFromRemote = true; - await _loadFromRemote(session, profile); - }); + await _loadFromRemote(session, profile); + }, + timeout: lockTimeout, + ); } /// Loads data from storage into the provider. /// This will run once when the provider is first initialized. /// If the data is not available in storage, this method should do nothing. Future ensureInitializedFromStorage() async { - await _lock.synchronized(() async { - if (_initializedFromStorage) { - return; - } - - _initializedFromStorage = true; - await _loadFromStorage(); - }); + await _lock.synchronized( + () async { + if (_initializedFromStorage) { + return; + } + + _initializedFromStorage = true; + await _loadFromStorage(); + }, + timeout: lockTimeout, + ); } Future loadFromStorage(); diff --git a/uni/lib/view/bug_report/widgets/form.dart b/uni/lib/view/bug_report/widgets/form.dart index c94af32b6..1b8321ad8 100644 --- a/uni/lib/view/bug_report/widgets/form.dart +++ b/uni/lib/view/bug_report/widgets/form.dart @@ -246,7 +246,7 @@ class BugReportFormState extends State { child: Text( S.of(context).send, style: const TextStyle( - /*color: Colors.white*/ fontSize: 20, + fontSize: 20, ), ), ); @@ -276,7 +276,8 @@ class BugReportFormState extends State { Logger().i('Successfully submitted bug report.'); if (context.mounted) toastMsg = S.of(context).success; status = true; - } catch (e) { + } catch (e, stackTrace) { + await Sentry.captureException(e, stackTrace: stackTrace); Logger().e('Error while posting bug report:$e'); if (context.mounted) toastMsg = S.of(context).sent_error; status = false; @@ -284,14 +285,17 @@ class BugReportFormState extends State { clearForm(); - if (mounted) { + if (context.mounted) { FocusScope.of(context).requestFocus(FocusNode()); status ? await ToastMessage.success(context, toastMsg) : await ToastMessage.error(context, toastMsg); - setState(() { - _isButtonTapped = false; - }); + + if (context.mounted) { + setState(() { + _isButtonTapped = false; + }); + } } } diff --git a/uni/lib/view/common_widgets/page_transition.dart b/uni/lib/view/common_widgets/page_transition.dart index 2f3581a0d..da1273089 100644 --- a/uni/lib/view/common_widgets/page_transition.dart +++ b/uni/lib/view/common_widgets/page_transition.dart @@ -56,7 +56,7 @@ class PageTransition { case TermsAndConditionsState.accepted: return; case TermsAndConditionsState.rejected: - NavigationService.logoutAndPopHistory(null); + NavigationService.logoutAndPopHistory(); } } } diff --git a/uni/lib/view/locations/widgets/faculty_map.dart b/uni/lib/view/locations/widgets/faculty_map.dart index 6b3203302..1e2354e54 100644 --- a/uni/lib/view/locations/widgets/faculty_map.dart +++ b/uni/lib/view/locations/widgets/faculty_map.dart @@ -13,9 +13,9 @@ class FacultyMap extends StatelessWidget { switch (faculty) { case 'FEUP': return LocationsMap( - northEastBoundary: LatLng(41.17986, -8.59298), - southWestBoundary: LatLng(41.17670, -8.59991), - center: LatLng(41.17731, -8.59522), + northEastBoundary: const LatLng(41.17986, -8.59298), + southWestBoundary: const LatLng(41.17670, -8.59991), + center: const LatLng(41.17731, -8.59522), locations: locations, ); default: diff --git a/uni/lib/view/login/login.dart b/uni/lib/view/login/login.dart index a390331d3..476fa5af8 100644 --- a/uni/lib/view/login/login.dart +++ b/uni/lib/view/login/login.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; @@ -68,7 +69,7 @@ class LoginPageViewState extends State { _loggingIn = false; }); } - } catch (error) { + } catch (error, stackTrace) { setState(() { _loggingIn = false; }); @@ -79,7 +80,8 @@ class LoginPageViewState extends State { } else if (error is WrongCredentialsException) { unawaited(ToastMessage.error(context, error.message)); } else { - Logger().e(error); + Logger().e(error, stackTrace: stackTrace); + unawaited(Sentry.captureException(error, stackTrace: stackTrace)); unawaited(ToastMessage.error(context, S.of(context).failed_login)); } } diff --git a/uni/lib/view/navigation_service.dart b/uni/lib/view/navigation_service.dart index 9e8c336b6..903f5410e 100644 --- a/uni/lib/view/navigation_service.dart +++ b/uni/lib/view/navigation_service.dart @@ -1,21 +1,22 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:uni/controller/cleanup.dart'; +import 'package:uni/main.dart'; import 'package:uni/utils/drawer_items.dart'; import 'package:uni/view/login/login.dart'; /// Manages the navigation logic class NavigationService { - static final GlobalKey navigatorKey = - GlobalKey(); + static void logoutAndPopHistory() { + final context = Application.navigatorKey.currentContext!; - static void logoutAndPopHistory(BuildContext? dataContext) { - if (dataContext != null) { - cleanupStoredData(dataContext); - } + unawaited(cleanupStoredData(context)); - navigatorKey.currentState?.pushNamedAndRemoveUntil( - '/${DrawerItem.navLogOut.title}', - (_) => false, + Navigator.pushNamedAndRemoveUntil( + context, + '/${DrawerItem.navLogIn.title}', + (route) => false, ); } diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 356067f04..52cdb9fcd 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -30,17 +30,17 @@ dependencies: flutter_local_notifications: ^15.1.0+1 flutter_localizations: sdk: flutter - flutter_map: ^4.0.0 + flutter_map: ^5.0.0 flutter_map_marker_popup: ^5.0.0 flutter_markdown: ^0.6.0 flutter_svg: ^2.0.0+1 flutter_widget_from_html_core: ^0.10.3 html: ^0.15.0 - http: ^0.13.0 + http: ^1.1.0 image: ^4.0.13 intl: ^0.18.0 - latlong2: ^0.8.1 - logger: ^1.1.0 + latlong2: ^0.9.0 + logger: ^2.0.2+1 material_design_icons_flutter: ^7.0.7296 path: ^1.8.0 path_provider: ^2.0.0 From 09a505f21789a84289ce5fb05de1b5d814cf015d Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 17:32:24 +0100 Subject: [PATCH 188/199] Bump lock timeout durations --- .../local_storage/app_database.dart | 2 +- .../controller/networking/network_router.dart | 2 +- .../providers/state_provider_notifier.dart | 2 +- uni/pubspec.lock | 24 +++++++++---------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/uni/lib/controller/local_storage/app_database.dart b/uni/lib/controller/local_storage/app_database.dart index 885cba9f3..bcb3b56c5 100644 --- a/uni/lib/controller/local_storage/app_database.dart +++ b/uni/lib/controller/local_storage/app_database.dart @@ -21,7 +21,7 @@ class AppDatabase { List commands; /// The lock timeout for database operations. - static const Duration lockTimeout = Duration(seconds: 10); + static const Duration lockTimeout = Duration(seconds: 5); /// A lock that synchronizes all database insertions. static Lock lock = Lock(); diff --git a/uni/lib/controller/networking/network_router.dart b/uni/lib/controller/networking/network_router.dart index d84ff6c95..6b2ee56d3 100644 --- a/uni/lib/controller/networking/network_router.dart +++ b/uni/lib/controller/networking/network_router.dart @@ -22,7 +22,7 @@ class NetworkRouter { static http.Client? httpClient; /// The timeout for Sigarra login requests. - static const Duration _requestTimeout = Duration(seconds: 10); + static const Duration _requestTimeout = Duration(seconds: 30); /// The mutual exclusion primitive for login requests. static final Lock _loginLock = Lock(); diff --git a/uni/lib/model/providers/state_provider_notifier.dart b/uni/lib/model/providers/state_provider_notifier.dart index 6f4bbd9a7..cc248712e 100644 --- a/uni/lib/model/providers/state_provider_notifier.dart +++ b/uni/lib/model/providers/state_provider_notifier.dart @@ -22,7 +22,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { _initializedFromStorage = !initialize, _initializedFromRemote = !initialize; - static const lockTimeout = Duration(seconds: 10); + static const lockTimeout = Duration(seconds: 30); final Lock _lock = Lock(); final RequestStatus _initialStatus; RequestStatus _status; diff --git a/uni/pubspec.lock b/uni/pubspec.lock index e336b67cc..c2e1870fb 100644 --- a/uni/pubspec.lock +++ b/uni/pubspec.lock @@ -415,18 +415,18 @@ packages: dependency: "direct main" description: name: flutter_map - sha256: "52c65a977daae42f9aae6748418dd1535eaf27186e9bac9bf431843082bc75a3" + sha256: "5286f72f87deb132daa1489442d6cc46e986fc105cb727d9ae1b602b35b1d1f3" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_map_marker_popup: dependency: "direct main" description: name: flutter_map_marker_popup - sha256: d4e22a00dd46f95a6f54c60b92950bd6f41021ca36629b1cf3fa0bf4fd39f421 + sha256: be209c68b19d4c10d9a2f5911e45f7c579624c43a353adb9bf0f2fec0cf30b8c url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.2.0" flutter_markdown: dependency: "direct main" description: @@ -497,10 +497,10 @@ packages: dependency: "direct main" description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "1.1.0" http_multi_server: dependency: transitive description: @@ -561,10 +561,10 @@ packages: dependency: "direct main" description: name: latlong2 - sha256: "08ef7282ba9f76e8495e49e2dc4d653015ac929dce5f92b375a415d30b407ea0" + sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b" url: "https://pub.dev" source: hosted - version: "0.8.2" + version: "0.9.0" lists: dependency: transitive description: @@ -577,10 +577,10 @@ packages: dependency: "direct main" description: name: logger - sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "2.0.2+1" logging: dependency: transitive description: @@ -698,10 +698,10 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745" + sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "4.1.0" package_info_plus_platform_interface: dependency: transitive description: From d15ebc15def489b88546f2413201f8e8e84de763 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 17:44:30 +0100 Subject: [PATCH 189/199] Fix empty course parsing --- uni/lib/generated/intl/messages_en.dart | 2 +- uni/lib/generated/intl/messages_pt_PT.dart | 2 +- uni/lib/generated/l10n.dart | 4 +-- uni/lib/l10n/intl_en.arb | 2 +- uni/lib/l10n/intl_pt_PT.arb | 2 +- uni/lib/model/entities/course.dart | 26 ++++++++++++-------- uni/lib/model/entities/profile.dart | 5 +++- uni/lib/view/home/widgets/schedule_card.dart | 2 -- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index 7c9d65e6c..112516f05 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -107,7 +107,7 @@ class MessageLookup extends MessageLookupByLibrary { "D. Beatriz\'s stationery store"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Floor -1 of building B (B-142)"), - "ects": MessageLookupByLibrary.simpleMessage("ECTs performed: "), + "ects": MessageLookupByLibrary.simpleMessage("ECTS performed: "), "edit_off": MessageLookupByLibrary.simpleMessage("Edit"), "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "empty_text": diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index c86c90267..68a173ffe 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -106,7 +106,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), "dona_bia_building": MessageLookupByLibrary.simpleMessage( "Piso -1 do edifício B (B-142)"), - "ects": MessageLookupByLibrary.simpleMessage("ECTs realizados: "), + "ects": MessageLookupByLibrary.simpleMessage("ECTS realizados: "), "edit_off": MessageLookupByLibrary.simpleMessage("Editar\n"), "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index 804bd1400..936259b3e 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -480,10 +480,10 @@ class S { ); } - /// `ECTs performed: ` + /// `ECTS performed: ` String get ects { return Intl.message( - 'ECTs performed: ', + 'ECTS performed: ', name: 'ects', desc: '', args: [], diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index acc5d7b7c..b1d6be897 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -86,7 +86,7 @@ "@dona_bia": {}, "dona_bia_building": "Floor -1 of building B (B-142)", "@dona_bia_building": {}, - "ects": "ECTs performed: ", + "ects": "ECTS performed: ", "@ects": {}, "edit_off": "Edit", "@edit_off": {}, diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 7552ae5c3..4315ac0af 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -86,7 +86,7 @@ "@dona_bia": {}, "dona_bia_building": "Piso -1 do edifício B (B-142)", "@dona_bia_building": {}, - "ects": "ECTs realizados: ", + "ects": "ECTS realizados: ", "@ects": {}, "edit_off": "Editar\n", "@edit_off": {}, diff --git a/uni/lib/model/entities/course.dart b/uni/lib/model/entities/course.dart index 645aa7cef..ef861730f 100644 --- a/uni/lib/model/entities/course.dart +++ b/uni/lib/model/entities/course.dart @@ -10,7 +10,7 @@ class Course { Course({ required this.id, - this.festId = 0, + this.festId, this.name, this.abbreviation, this.currYear, @@ -21,15 +21,21 @@ class Course { this.currentAverage, }); - /// Creates a new instance from a JSON object. - Course.fromJson(Map data) - : id = (data['cur_id'] ?? 0) as int, - festId = (data['fest_id'] ?? 0) as int, - name = data['cur_nome'] as String?, - currYear = data['ano_curricular'] as String?, - firstEnrollment = data['fest_a_lect_1_insc'] as int, - abbreviation = data['abbreviation'] as String?, - faculty = data['inst_sigla']?.toString().toLowerCase(); + static Course? fromJson(Map data) { + if (data['cur_id'] == null || data['fest_id'] == 0) { + return null; + } + + return Course( + id: data['cur_id'] as int, + festId: data['fest_id'] as int, + name: data['cur_nome'] as String?, + currYear: data['ano_curricular'] as String?, + firstEnrollment: data['fest_a_lect_1_insc'] as int?, + abbreviation: data['abbreviation'] as String?, + faculty: data['inst_sigla']?.toString().toLowerCase(), + ); + } final int id; final int? festId; diff --git a/uni/lib/model/entities/profile.dart b/uni/lib/model/entities/profile.dart index 59fecf190..0085f0955 100644 --- a/uni/lib/model/entities/profile.dart +++ b/uni/lib/model/entities/profile.dart @@ -23,7 +23,10 @@ class Profile { responseBody = responseBody as Map; final courses = []; for (final c in responseBody['cursos'] as List) { - courses.add(Course.fromJson(c as Map)); + final course = Course.fromJson(c as Map); + if (course != null) { + courses.add(course); + } } return Profile( diff --git a/uni/lib/view/home/widgets/schedule_card.dart b/uni/lib/view/home/widgets/schedule_card.dart index 039db9c19..f70d40b61 100644 --- a/uni/lib/view/home/widgets/schedule_card.dart +++ b/uni/lib/view/home/widgets/schedule_card.dart @@ -97,8 +97,6 @@ class ScheduleCard extends GenericCard { rows.add(createRowFromLecture(context, lecture)); } - rows.add(const Padding(padding: EdgeInsets.only(bottom: 10))); - if (lectures.length >= 2) { break; } From d8ff27021a0450acd39396b8a8d12d569e3247df Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 17:46:30 +0100 Subject: [PATCH 190/199] Bump app lectures database version to force migration --- uni/lib/controller/local_storage/app_lectures_database.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/lib/controller/local_storage/app_lectures_database.dart b/uni/lib/controller/local_storage/app_lectures_database.dart index a4e6b55c5..7430020e5 100644 --- a/uni/lib/controller/local_storage/app_lectures_database.dart +++ b/uni/lib/controller/local_storage/app_lectures_database.dart @@ -16,7 +16,7 @@ class AppLecturesDatabase extends AppDatabase { createScript, ], onUpgrade: migrate, - version: 6, + version: 7, ); static const createScript = ''' CREATE TABLE lectures(subject TEXT, typeClass TEXT, From 6225e1900a6c27bcfbf4f774eac3b171f9cb5ee3 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 17:51:13 +0100 Subject: [PATCH 191/199] Do not set general page state if disposed --- .../common_widgets/pages_layouts/general/general.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 116f830be..dd8ad236d 100644 --- a/uni/lib/view/common_widgets/pages_layouts/general/general.dart +++ b/uni/lib/view/common_widgets/pages_layouts/general/general.dart @@ -25,7 +25,7 @@ abstract class GeneralPageViewState extends State { @override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) async { - if (_loadedOnce) { + if (_loadedOnce || !mounted) { return; } _loadedOnce = true; @@ -40,9 +40,11 @@ abstract class GeneralPageViewState extends State { await Sentry.captureException(e, stackTrace: stackTrace); } - setState(() { - _loading = false; - }); + if (mounted) { + setState(() { + _loading = false; + }); + } }); return getScaffold( From aabb1454d9b49feee6627f533d1f2f2b4b860b0a Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 18:01:50 +0100 Subject: [PATCH 192/199] Fix bus user stops page not updating after insertion --- uni/lib/model/providers/lazy/bus_stop_provider.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uni/lib/model/providers/lazy/bus_stop_provider.dart b/uni/lib/model/providers/lazy/bus_stop_provider.dart index b739dd8d0..2b9f7c36b 100644 --- a/uni/lib/model/providers/lazy/bus_stop_provider.dart +++ b/uni/lib/model/providers/lazy/bus_stop_provider.dart @@ -51,7 +51,9 @@ class BusStopProvider extends StateProviderNotifier { _configuredBusStops[stopCode] = stopData; } + notifyListeners(); await fetchUserBusTrips(); + notifyListeners(); final db = AppBusStopDatabase(); await db.setBusStops(configuredBusStops); @@ -61,9 +63,10 @@ class BusStopProvider extends StateProviderNotifier { String stopCode, ) async { _configuredBusStops.remove(stopCode); - notifyListeners(); + notifyListeners(); await fetchUserBusTrips(); + notifyListeners(); final db = AppBusStopDatabase(); await db.setBusStops(_configuredBusStops); @@ -75,9 +78,10 @@ class BusStopProvider extends StateProviderNotifier { ) async { _configuredBusStops[stopCode]!.favorited = !_configuredBusStops[stopCode]!.favorited; - notifyListeners(); + notifyListeners(); await fetchUserBusTrips(); + notifyListeners(); final db = AppBusStopDatabase(); await db.updateFavoriteBusStop(stopCode); From 59558fc1a4b0a1d65581055657c389f937225ad8 Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Wed, 4 Oct 2023 18:52:30 +0100 Subject: [PATCH 193/199] Do not wait for trips before dismissing bus dialog --- .../view/bus_stop_selection/widgets/bus_stop_search.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 be55fc3b8..5155dde2d 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 @@ -112,9 +112,11 @@ class BusStopSearch extends SearchDelegate { child: Text(S.of(context).confirm), onPressed: () async { if (stopData!.configuredBuses.isNotEmpty) { - await Provider.of(context, listen: false) - .addUserBusStop(stopCode!, stopData!); - if (context.mounted) Navigator.pop(context); + unawaited( + Provider.of(context, listen: false) + .addUserBusStop(stopCode!, stopData!), + ); + Navigator.pop(context); } }, ) From 65d0da1183ab09d74aa410b613cbeaf3baa84afc Mon Sep 17 00:00:00 2001 From: limwa Date: Wed, 4 Oct 2023 18:40:27 +0000 Subject: [PATCH 194/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 5f7f9d3f3..a55d8e5c0 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.10+200 \ No newline at end of file +1.7.11+201 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 52cdb9fcd..047465d2c 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.10+200 +version: 1.7.11+201 environment: sdk: '>=3.0.0 <4.0.0' From 42af53799e67a548ee113d725394da60b370e2ee Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 5 Oct 2023 16:51:51 +0100 Subject: [PATCH 195/199] Fixing ios build --- uni/.gitignore | 1 - uni/ios/Podfile | 15 ++ uni/ios/Runner.xcodeproj/project.pbxproj | 213 +++++++++++++++- .../xcshareddata/xcschemes/Runner.xcscheme | 13 +- uni/pubspec.lock | 240 ++++++++---------- uni/pubspec.yaml | 2 +- 6 files changed, 344 insertions(+), 140 deletions(-) create mode 100644 uni/ios/Podfile diff --git a/uni/.gitignore b/uni/.gitignore index a20521678..ef53d37aa 100644 --- a/uni/.gitignore +++ b/uni/.gitignore @@ -99,7 +99,6 @@ unlinked_spec.ds **/ios/Flutter/flutter_export_environment.sh **/ios/ServiceDefinitions.json **/ios/Runner/GeneratedPluginRegistrant.* -**/ios/Podfile # macOS **/Flutter/ephemeral/ diff --git a/uni/ios/Podfile b/uni/ios/Podfile new file mode 100644 index 000000000..205500540 --- /dev/null +++ b/uni/ios/Podfile @@ -0,0 +1,15 @@ +# Uncomment the next line to define a global platform for your project +# platform :ios, '11.0' + +target 'Runner' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for Runner + + target 'RunnerTests' do + inherit! :search_paths + # Pods for testing + end + +end diff --git a/uni/ios/Runner.xcodeproj/project.pbxproj b/uni/ios/Runner.xcodeproj/project.pbxproj index ef55cd3bd..a8c70480b 100644 --- a/uni/ios/Runner.xcodeproj/project.pbxproj +++ b/uni/ios/Runner.xcodeproj/project.pbxproj @@ -8,14 +8,26 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 378A17142ACF02E100B89C1C /* RunnerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 378A17132ACF02E100B89C1C /* RunnerTests.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 95F65346A056DDFB0CCCED79 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65A7FEFFF94135D00ABAE9B9 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B0BA8183595B62BB34BA7067 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D20E49018C2538464D8BC7C /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 378A17152ACF02E100B89C1C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -35,10 +47,16 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 1946AAAAFCF4B47B8541DAAE /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 34F7CD5BD9DE233CE39A0794 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 378A17112ACF02E100B89C1C /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 378A17132ACF02E100B89C1C /* RunnerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RunnerTests.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3ECCFBBCC80E695424F574D5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 65A7FEFFF94135D00ABAE9B9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6D20E49018C2538464D8BC7C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7216FEB85165776295251207 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 776405D2BD4EB55AD008BAE3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -50,6 +68,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 378A170E2ACF02E100B89C1C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B0BA8183595B62BB34BA7067 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -67,10 +93,21 @@ 116479123E23B6BA4733EC22 /* Pods-Runner.debug.xcconfig */, 1946AAAAFCF4B47B8541DAAE /* Pods-Runner.release.xcconfig */, 34F7CD5BD9DE233CE39A0794 /* Pods-Runner.profile.xcconfig */, + 776405D2BD4EB55AD008BAE3 /* Pods-RunnerTests.debug.xcconfig */, + 3ECCFBBCC80E695424F574D5 /* Pods-RunnerTests.release.xcconfig */, + 7216FEB85165776295251207 /* Pods-RunnerTests.profile.xcconfig */, ); path = Pods; sourceTree = ""; }; + 378A17122ACF02E100B89C1C /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 378A17132ACF02E100B89C1C /* RunnerTests.m */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -87,6 +124,7 @@ children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + 378A17122ACF02E100B89C1C /* RunnerTests */, 97C146EF1CF9000F007C117D /* Products */, 227A5121A8917F9CC04F8063 /* Pods */, DCEE3166979EF19DFB76E949 /* Frameworks */, @@ -97,6 +135,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 378A17112ACF02E100B89C1C /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -120,6 +159,7 @@ isa = PBXGroup; children = ( 65A7FEFFF94135D00ABAE9B9 /* Pods_Runner.framework */, + 6D20E49018C2538464D8BC7C /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -127,6 +167,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 378A17102ACF02E100B89C1C /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 378A171A2ACF02E100B89C1C /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + A202455463DBDFBE5F69F3CD /* [CP] Check Pods Manifest.lock */, + 378A170D2ACF02E100B89C1C /* Sources */, + 378A170E2ACF02E100B89C1C /* Frameworks */, + 378A170F2ACF02E100B89C1C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 378A17162ACF02E100B89C1C /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 378A17112ACF02E100B89C1C /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; @@ -138,7 +197,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - B72AED15C931F2FF135F33E9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -155,9 +213,13 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { + 378A17102ACF02E100B89C1C = { + CreatedOnToolsVersion = 15.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -178,11 +240,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 378A17102ACF02E100B89C1C /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 378A170F2ACF02E100B89C1C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -228,7 +298,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - AD47D7787757870A61A69CBD /* [CP] Check Pods Manifest.lock */ = { + A202455463DBDFBE5F69F3CD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -243,33 +313,46 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - B72AED15C931F2FF135F33E9 /* [CP] Embed Pods Frameworks */ = { + AD47D7787757870A61A69CBD /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 378A170D2ACF02E100B89C1C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 378A17142ACF02E100B89C1C /* RunnerTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -281,6 +364,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 378A17162ACF02E100B89C1C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 378A17152ACF02E100B89C1C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -374,6 +465,100 @@ }; name = Profile; }; + 378A17172ACF02E100B89C1C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 776405D2BD4EB55AD008BAE3 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ADS6V5HXNQ; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = pt.up.fe.ni.uni.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 378A17182ACF02E100B89C1C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3ECCFBBCC80E695424F574D5 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ADS6V5HXNQ; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = pt.up.fe.ni.uni.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 378A17192ACF02E100B89C1C /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7216FEB85165776295251207 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ADS6V5HXNQ; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = pt.up.fe.ni.uni.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -531,6 +716,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 378A171A2ACF02E100B89C1C /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 378A17172ACF02E100B89C1C /* Debug */, + 378A17182ACF02E100B89C1C /* Release */, + 378A17192ACF02E100B89C1C /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db2..d01be74c1 100644 --- a/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/uni/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + Date: Thu, 5 Oct 2023 16:54:46 +0100 Subject: [PATCH 196/199] Changing Podfile --- uni/ios/Podfile | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/uni/ios/Podfile b/uni/ios/Podfile index 205500540..45cb6dd31 100644 --- a/uni/ios/Podfile +++ b/uni/ios/Podfile @@ -1,15 +1,44 @@ -# Uncomment the next line to define a global platform for your project +# Uncomment this line to define a global platform for your project # platform :ios, '11.0' +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + target 'Runner' do - # Comment the next line if you don't want to use dynamic frameworks use_frameworks! + use_modular_headers! - # Pods for Runner - + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths - # Pods for testing end - end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end \ No newline at end of file From 90d2822f83b7af49e6e16b488a7d59f9ab0606fc Mon Sep 17 00:00:00 2001 From: bdmendes Date: Fri, 6 Oct 2023 13:26:40 +0000 Subject: [PATCH 197/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index a55d8e5c0..02a32b922 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.11+201 \ No newline at end of file +1.7.12+202 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index b66242e1a..31908f3da 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.11+201 +version: 1.7.12+202 environment: sdk: '>=3.0.0 <4.0.0' From c7ed168c44fb837e65928069dea67026e2527623 Mon Sep 17 00:00:00 2001 From: Bruno Mendes <61701401+bdmendes@users.noreply.github.com> Date: Fri, 6 Oct 2023 14:30:49 +0100 Subject: [PATCH 198/199] Allow null course unit year --- uni/lib/model/entities/course_units/course_unit.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uni/lib/model/entities/course_units/course_unit.dart b/uni/lib/model/entities/course_units/course_unit.dart index 25bf40338..cf8a0193d 100644 --- a/uni/lib/model/entities/course_units/course_unit.dart +++ b/uni/lib/model/entities/course_units/course_unit.dart @@ -45,7 +45,7 @@ class CourseUnit { code: data['ucurr_codigo'] as String, abbreviation: data['ucurr_sigla'] as String, name: data['ucurr_nome'] as String, - curricularYear: data['ano'] as int, + curricularYear: data['ano'] as int?, occurrId: data['ocorr_id'] as int, semesterCode: data['per_codigo'] as String?, semesterName: data['per_nome'] as String?, From 2d63a852cea2ed635e852a60d8178cfcf0701d83 Mon Sep 17 00:00:00 2001 From: LuisDuarte1 Date: Fri, 6 Oct 2023 17:22:39 +0000 Subject: [PATCH 199/199] Bump app version [no ci] --- uni/app_version.txt | 2 +- uni/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/uni/app_version.txt b/uni/app_version.txt index 02a32b922..a8e28fe3c 100644 --- a/uni/app_version.txt +++ b/uni/app_version.txt @@ -1 +1 @@ -1.7.12+202 \ No newline at end of file +1.7.13+203 \ No newline at end of file diff --git a/uni/pubspec.yaml b/uni/pubspec.yaml index 31908f3da..3206b1e6f 100644 --- a/uni/pubspec.yaml +++ b/uni/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' # We do not publish to pub.dev # To change it manually, override the value in app_version.txt. # The app version code is automatically also bumped by CI. # Do not change it manually. -version: 1.7.12+202 +version: 1.7.13+203 environment: sdk: '>=3.0.0 <4.0.0'