From afaec7bc3c283171ea12c2e67add3324c9f01884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:04:18 +0100 Subject: [PATCH 01/99] feat: add new schedule api --- .../schedule_fetcher_html.dart | 60 ------ .../schedule_fetcher_new_api.dart | 55 ++++++ .../parsers/parser_schedule_html.dart | 183 ------------------ .../generated/model/entities/lecture.g.dart | 2 - .../uni_app/lib/model/entities/lecture.dart | 27 +-- .../providers/lazy/lecture_provider.dart | 7 +- .../new_api/models/response_lecture.dart | 26 +++ .../models/response_lecture_class.dart | 14 ++ .../models/response_lecture_person.dart | 14 ++ .../new_api/models/response_lecture_room.dart | 14 ++ .../models/response_lecture_typology.dart | 14 ++ .../new_api/models/response_lecture_unit.dart | 16 ++ .../parsers/schedule/new_api/parser.dart | 47 +++++ .../new_api/models/response_lecture.g.dart | 38 ++++ .../models/response_lecture_class.g.dart | 19 ++ .../models/response_lecture_person.g.dart | 19 ++ .../models/response_lecture_room.g.dart | 18 ++ .../models/response_lecture_typology.g.dart | 19 ++ .../models/response_lecture_unit.g.dart | 20 ++ 19 files changed, 337 insertions(+), 275 deletions(-) delete mode 100644 packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart create mode 100644 packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart delete mode 100644 packages/uni_app/lib/controller/parsers/parser_schedule_html.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart create mode 100644 uni/lib/controller/parsers/schedule/new_api/parser.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart create mode 100644 uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart deleted file mode 100644 index 6ca596dd1..000000000 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:http/http.dart' as http; -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'; -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/utils/time/week.dart'; - -/// Class for fetching the user's lectures from the schedule's HTML page. -class ScheduleFetcherHtml extends ScheduleFetcher { - @override - List getEndpoints(Session session) { - final urls = NetworkRouter.getBaseUrlsFromSession(session) - .map((url) => '${url}hor_geral.estudantes_view') - .toList(); - return urls; - } - - /// Fetches the user's lectures from the schedule's HTML page. - @override - Future> getLectures(Session session, Profile profile) async { - final dates = getDates(); - final baseUrls = NetworkRouter.getBaseUrlsFromSession(session); - - final lectureResponses = >[]; - for (final baseUrl in baseUrls) { - final url = '${baseUrl}hor_geral.estudantes_view'; - - for (final course in profile.courses) { - final futures = dates.map( - (date) => NetworkRouter.getWithCookies( - url, - { - 'pv_fest_id': course.festId.toString(), - 'pv_ano_lectivo': date.lectiveYear.toString(), - 'p_semana_inicio': date.asSigarraWeekStart, - 'p_semana_fim': date.asSigarraWeekEnd, - }, - session, - ).then( - (response) => Tuple2((date.week, response), baseUrl), - ), - ); - - lectureResponses.addAll(await Future.wait(futures)); - } - } - - final lectures = await Future.wait( - lectureResponses.map( - (e) => getScheduleFromHtml(e.item1, session, e.item2), - ), - ).then((schedules) => schedules.expand((schedule) => schedule).toList()); - - lectures.sort((l1, l2) => l1.compare(l2)); - return lectures; - } -} diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart new file mode 100644 index 000000000..fb79f0004 --- /dev/null +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -0,0 +1,55 @@ +import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; +import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/parsers/schedule/new_api/parser.dart'; +import 'package:uni/model/entities/lecture.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/entities/session.dart'; + +/// Class for fetching the user's lectures from the schedule's HTML page. +class ScheduleFetcherNewApi extends ScheduleFetcher { + @override + List getEndpoints(Session session) { + final urls = NetworkRouter.getBaseUrlsFromSession(session) + .map((url) => '${url}hor_geral.estudantes_view') + .toList(); + return urls; + } + + /// Fetches the user's lectures from the schedule's HTML page. + @override + Future> getLectures(Session session, Profile profile) async { + final endpoints = getEndpoints(session); + final futures = >>[]; + + for (final baseUrl in endpoints) { + final future = Future(() async { + final scheduleRequest = await NetworkRouter.getWithCookies( + baseUrl, + { + 'pv_num_unico': session.username, + }, + session, + ); + + final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleRequest); + + final scheduleApiRequest = await NetworkRouter.getWithCookies( + scheduleApiUrl, + {}, + session, + ); + + return getLecturesFromApiResponse(scheduleApiRequest); + }); + + futures.add(future); + } + + final results = await Future.wait(futures); + + final lectures = results.expand((element) => element).toList() + ..sort((l1, l2) => l1.compare(l2)); + + return lectures; + } +} diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart deleted file mode 100644 index f406724da..000000000 --- a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'dart:async'; - -import 'package:html/dom.dart'; -import 'package:html/parser.dart' show parse; -import 'package:http/http.dart' as http; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/session.dart'; -import 'package:uni/model/utils/time/week.dart'; -import 'package:uni/model/utils/time/weekday_mapper.dart'; - -Future> getOverlappedClasses( - Session session, - Document document, - String faculty, - Week week, -) async { - final lecturesList = []; - - final overlappingClasses = document.querySelectorAll('.dados > tbody > .d'); - for (final element in overlappingClasses) { - final subject = element.querySelector('acronym > a')?.text; - final typeClass = element - .querySelector('td[headers=t1]') - ?.nodes[1] - .text - ?.trim() - .replaceAll(RegExp('[()]+'), ''); - final textDay = element.querySelector('td[headers=t2]')?.text; - final aDay = document - .querySelector('.horario > tbody > tr:first-child') - ?.children - .indexWhere((element) => element.text == textDay); - final day = week.getWeekday( - aDay != null - ? WeekdayMapper.fromSigarraToDart.map(aDay) - : DateTime.monday, - ); - final startTime = element.querySelector('td[headers=t3]')?.text; - final room = element.querySelector('td[headers=t4] > a')?.text; - final teacher = element.querySelector('td[headers=t5] > a')?.text; - 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 = day.add( - Duration( - hours: int.parse(startTimeList[0]), - minutes: int.parse(startTimeList[1]), - ), - ); - - final href = - element.querySelector('td[headers=t6] > a')?.attributes['href']; - - if (href == null) { - throw Exception(); - } - final response = await NetworkRouter.getWithCookies( - '$faculty$href', - {}, - session, - ); - - final classLectures = await getScheduleFromHtml( - (week, response), - session, - faculty, - ); - - lecturesList.add( - classLectures - .where( - (element) => - element.subject == subject && - element.startTime == fullStartTime, - ) - .first, - ); - } catch (_) { - final lect = Lecture.fromHtml( - subject!, - typeClass!, - day, - startTime!, - 0, - room!, - teacher!, - classNumber!, - -1, - ); - lecturesList.add(lect); - } - } - - return lecturesList; -} - -/// Extracts the user's lectures from a Week-HTTP pair in [responsePerWeek] and -/// sorts them by date. -/// -/// This function parses the schedule's HTML page. -Future> getScheduleFromHtml( - (Week, http.Response) responsePerWeek, - Session session, - String faculty, -) async { - final (week, response) = responsePerWeek; - final document = parse(response.body); - var semana = [0, 0, 0, 0, 0, 0]; - - final lecturesList = []; - - document.querySelectorAll('.horario > tbody > tr').forEach((element) { - if (element.getElementsByClassName('horas').isNotEmpty) { - var dayIndex = 0; - final children = element.children; - for (var i = 1; i < children.length; i++) { - for (var d = dayIndex; d < semana.length; d++) { - if (semana[d] == 0) { - break; - } - dayIndex++; - } - final clsName = children[i].className; - if (clsName == 'TE' || clsName == 'TP' || clsName == 'PL') { - final subject = children[i].querySelector('b > acronym > a')?.text; - if (subject == null) { - return; - } - String? classNumber; - - if (clsName == 'TP' || clsName == 'PL') { - classNumber = children[i].querySelector('span > a')?.text; - if (classNumber == null) { - return; - } - } - - final rowSmall = children[i].querySelector('table > tbody > tr'); - final room = rowSmall?.querySelector('td > a')?.text; - final teacher = rowSmall?.querySelector('td.textod a')?.text; - - final typeClass = clsName; - final blocks = int.parse(children[i].attributes['rowspan']!); - final startTime = children[0].text.substring(0, 5); - - semana[dayIndex] += blocks; - - final lect = Lecture.fromHtml( - subject, - typeClass, - week.getWeekday( - WeekdayMapper.fromDartToIndex.inverse.map(dayIndex), - ), - startTime, - blocks, - room ?? '', - teacher ?? '', - classNumber ?? '', - -1, - ); - lecturesList.add(lect); - } - dayIndex++; - } - semana = semana.expand((i) => [if ((i - 1) < 0) 0 else i - 1]).toList(); - } - }); - - lecturesList - ..addAll( - await getOverlappedClasses(session, document, faculty, week), - ) - ..sort((a, b) => a.compare(b)); - - return lecturesList; -} diff --git a/packages/uni_app/lib/generated/model/entities/lecture.g.dart b/packages/uni_app/lib/generated/model/entities/lecture.g.dart index f83de3bdd..66a4c44aa 100644 --- a/packages/uni_app/lib/generated/model/entities/lecture.g.dart +++ b/packages/uni_app/lib/generated/model/entities/lecture.g.dart @@ -11,7 +11,6 @@ Lecture _$LectureFromJson(Map json) => Lecture( json['typeClass'] as String, const DateTimeConverter().fromJson(json['startTime'] as String), const DateTimeConverter().fromJson(json['endTime'] as String), - json['blocks'] as int, json['room'] as String, json['teacher'] as String, json['classNumber'] as String, @@ -26,6 +25,5 @@ Map _$LectureToJson(Lecture instance) => { 'classNumber': instance.classNumber, 'startTime': const DateTimeConverter().toJson(instance.startTime), 'endTime': const DateTimeConverter().toJson(instance.endTime), - 'blocks': instance.blocks, 'occurrId': instance.occurrId, }; diff --git a/packages/uni_app/lib/model/entities/lecture.dart b/packages/uni_app/lib/model/entities/lecture.dart index df0b8566c..17540451d 100644 --- a/packages/uni_app/lib/model/entities/lecture.dart +++ b/packages/uni_app/lib/model/entities/lecture.dart @@ -13,7 +13,6 @@ class Lecture { this.typeClass, this.startTime, this.endTime, - this.blocks, this.room, this.teacher, this.classNumber, @@ -39,7 +38,6 @@ class Lecture { typeClass, startTime, endTime, - blocks, room, teacher, classNumber, @@ -72,7 +70,6 @@ class Lecture { typeClass, startTime, endTime, - blocks, room, teacher, classNumber, @@ -80,25 +77,6 @@ class Lecture { ); } - /// Clones a lecture from the api. - factory Lecture.clone(Lecture lec) { - return Lecture.fromApi( - lec.subject, - lec.typeClass, - lec.startTime, - lec.blocks, - lec.room, - lec.teacher, - lec.classNumber, - lec.occurrId, - ); - } - - /// Clones a lecture from the html. - factory Lecture.cloneHtml(Lecture lec) { - return Lecture.clone(lec); - } - String subject; String typeClass; String room; @@ -106,13 +84,12 @@ class Lecture { String classNumber; DateTime startTime; DateTime endTime; - int blocks; int occurrId; Map toJson() => _$LectureToJson(this); @override String toString() { - return '$subject $typeClass\n$startTime $endTime $blocks blocos\n $room ' + return '$subject $typeClass\n$startTime $endTime\n $room ' '$teacher\n'; } @@ -130,7 +107,6 @@ class Lecture { room, teacher, startTime, - blocks, occurrId, ); @@ -143,6 +119,5 @@ class Lecture { typeClass == other.typeClass && room == other.room && teacher == other.teacher && - blocks == other.blocks && occurrId == other.occurrId; } diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index 2dc1264a0..160f57f93 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; -import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; +import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart'; import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; @@ -49,8 +49,7 @@ class LectureProvider extends StateProviderNotifier> { fetcher?.getLectures(session, profile) ?? getLectures(session, profile); Future> getLectures(Session session, Profile profile) { - return ScheduleFetcherApi() - .getLectures(session, profile) - .catchError((e) => ScheduleFetcherHtml().getLectures(session, profile)); + return ScheduleFetcherApi().getLectures(session, profile).catchError( + (e) => ScheduleFetcherNewApi().getLectures(session, profile)); } } diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart new file mode 100644 index 000000000..5a7e60ce1 --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture_class.dart'; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture_person.dart'; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture_room.dart'; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture_typology.dart'; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture_unit.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLecture { + ResponseLecture(this.start, this.end, this.units, this.classes, this.persons, + this.rooms, this.typology); + factory ResponseLecture.fromJson(Map json) => + _$ResponseLectureFromJson(json); + + DateTime start; + DateTime end; + List units; + List classes; + List persons; + List rooms; + ResponseLectureTypology typology; + + Map toJson() => _$ResponseLectureToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart new file mode 100644 index 000000000..766d43f7a --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLectureClass { + ResponseLectureClass(this.acronym); + factory ResponseLectureClass.fromJson(Map json) => + _$ResponseLectureClassFromJson(json); + + String acronym; + + Map toJson() => _$ResponseLectureClassToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart new file mode 100644 index 000000000..fbbb491ea --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLecturePerson { + ResponseLecturePerson(this.acronym); + factory ResponseLecturePerson.fromJson(Map json) => + _$ResponseLecturePersonFromJson(json); + + String acronym; + + Map toJson() => _$ResponseLecturePersonToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart new file mode 100644 index 000000000..270c58c94 --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLectureRoom { + ResponseLectureRoom(this.name); + factory ResponseLectureRoom.fromJson(Map json) => + _$ResponseLectureRoomFromJson(json); + + String name; + + Map toJson() => _$ResponseLectureRoomToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart new file mode 100644 index 000000000..cda9498d9 --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart @@ -0,0 +1,14 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLectureTypology { + ResponseLectureTypology(this.acronym); + factory ResponseLectureTypology.fromJson(Map json) => + _$ResponseLectureTypologyFromJson(json); + + String acronym; + + Map toJson() => _$ResponseLectureTypologyToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart new file mode 100644 index 000000000..8f83e1e2b --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart @@ -0,0 +1,16 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ResponseLectureUnit { + ResponseLectureUnit(this.acronym, this.sigarraId); + factory ResponseLectureUnit.fromJson(Map json) => + _$ResponseLectureUnitFromJson(json); + + String acronym; + @JsonKey(name: 'sigarra_id') + int sigarraId; + + Map toJson() => _$ResponseLectureUnitToJson(this); +} diff --git a/uni/lib/controller/parsers/schedule/new_api/parser.dart b/uni/lib/controller/parsers/schedule/new_api/parser.dart new file mode 100644 index 000000000..0d97b9f78 --- /dev/null +++ b/uni/lib/controller/parsers/schedule/new_api/parser.dart @@ -0,0 +1,47 @@ +import 'dart:convert'; + +import 'package:html/parser.dart' show parse; +import 'package:http/http.dart' as http; +import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture.dart'; +import 'package:uni/model/entities/lecture.dart'; + +/// Extracts the user's lecture API URL. +/// +/// This function parses the schedule's HTML page. +String getScheduleApiUrlFromHtml( + http.Response response, +) { + final document = parse(response.body); + + final scheduleElement = document.querySelector('#cal-shadow-container'); + final apiUrl = scheduleElement?.attributes['data-evt-source-url']; + + if (apiUrl == null) { + throw Exception('Could not find schedule API URL in schedule page'); + } + + return apiUrl; +} + +List getLecturesFromApiResponse( + http.Response response, +) { + final json = jsonDecode(response.body) as Map; + final data = json['data'] as List>; + + return data + .map(ResponseLecture.fromJson) + .map( + (lecture) => Lecture( + lecture.units.first.acronym, + lecture.typology.acronym, + lecture.start, + lecture.end, + lecture.rooms.first.name, + lecture.persons.map((person) => person.acronym).join('+'), + lecture.classes.first.acronym, + lecture.units.first.sigarraId, + ), + ) + .toList(); +} diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart new file mode 100644 index 000000000..2f1037c0e --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart @@ -0,0 +1,38 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLecture _$ResponseLectureFromJson(Map json) => + ResponseLecture( + DateTime.parse(json['start'] as String), + DateTime.parse(json['end'] as String), + (json['units'] as List) + .map((e) => ResponseLectureUnit.fromJson(e as Map)) + .toList(), + (json['classes'] as List) + .map((e) => ResponseLectureClass.fromJson(e as Map)) + .toList(), + (json['persons'] as List) + .map((e) => ResponseLecturePerson.fromJson(e as Map)) + .toList(), + (json['rooms'] as List) + .map((e) => ResponseLectureRoom.fromJson(e as Map)) + .toList(), + ResponseLectureTypology.fromJson( + json['typology'] as Map), + ); + +Map _$ResponseLectureToJson(ResponseLecture instance) => + { + 'start': instance.start.toIso8601String(), + 'end': instance.end.toIso8601String(), + 'units': instance.units.map((e) => e.toJson()).toList(), + 'classes': instance.classes.map((e) => e.toJson()).toList(), + 'persons': instance.persons.map((e) => e.toJson()).toList(), + 'rooms': instance.rooms.map((e) => e.toJson()).toList(), + 'typology': instance.typology.toJson(), + }; diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart new file mode 100644 index 000000000..61e2c57e2 --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture_class.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLectureClass _$ResponseLectureClassFromJson( + Map json) => + ResponseLectureClass( + json['acronym'] as String, + ); + +Map _$ResponseLectureClassToJson( + ResponseLectureClass instance) => + { + 'acronym': instance.acronym, + }; diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart new file mode 100644 index 000000000..c26b41182 --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture_person.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLecturePerson _$ResponseLecturePersonFromJson( + Map json) => + ResponseLecturePerson( + json['acronym'] as String, + ); + +Map _$ResponseLecturePersonToJson( + ResponseLecturePerson instance) => + { + 'acronym': instance.acronym, + }; diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart new file mode 100644 index 000000000..685016c8a --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture_room.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLectureRoom _$ResponseLectureRoomFromJson(Map json) => + ResponseLectureRoom( + json['name'] as String, + ); + +Map _$ResponseLectureRoomToJson( + ResponseLectureRoom instance) => + { + 'name': instance.name, + }; diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart new file mode 100644 index 000000000..25e41a617 --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture_typology.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLectureTypology _$ResponseLectureTypologyFromJson( + Map json) => + ResponseLectureTypology( + json['acronym'] as String, + ); + +Map _$ResponseLectureTypologyToJson( + ResponseLectureTypology instance) => + { + 'acronym': instance.acronym, + }; diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart new file mode 100644 index 000000000..1d1ba95b8 --- /dev/null +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../controller/parsers/schedule/new_api/models/response_lecture_unit.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ResponseLectureUnit _$ResponseLectureUnitFromJson(Map json) => + ResponseLectureUnit( + json['acronym'] as String, + json['sigarra_id'] as int, + ); + +Map _$ResponseLectureUnitToJson( + ResponseLectureUnit instance) => + { + 'acronym': instance.acronym, + 'sigarra_id': instance.sigarraId, + }; From 4524f52d899a7048950324d45ada803d07aed599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:09:36 +0100 Subject: [PATCH 02/99] style: add trailing commas --- .../lib/model/providers/lazy/lecture_provider.dart | 3 ++- .../schedule/new_api/models/response_lecture.dart | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index 160f57f93..ae0d9d60b 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -50,6 +50,7 @@ class LectureProvider extends StateProviderNotifier> { Future> getLectures(Session session, Profile profile) { return ScheduleFetcherApi().getLectures(session, profile).catchError( - (e) => ScheduleFetcherNewApi().getLectures(session, profile)); + (e) => ScheduleFetcherNewApi().getLectures(session, profile), + ); } } diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart index 5a7e60ce1..b74449f58 100644 --- a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart @@ -9,8 +9,16 @@ part '../../../../../generated/controller/parsers/schedule/new_api/models/respon @JsonSerializable(explicitToJson: true) class ResponseLecture { - ResponseLecture(this.start, this.end, this.units, this.classes, this.persons, - this.rooms, this.typology); + ResponseLecture( + this.start, + this.end, + this.units, + this.classes, + this.persons, + this.rooms, + this.typology, + ); + factory ResponseLecture.fromJson(Map json) => _$ResponseLectureFromJson(json); From 3b1ed7d5204fe3ecd1917cc6fe1837250517ffbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:42:35 +0100 Subject: [PATCH 03/99] fix: handle weird sigarra non-redirect redirect --- .../fetchers/schedule_fetcher/schedule_fetcher.dart | 6 +++++- .../schedule_fetcher/schedule_fetcher_new_api.dart | 4 ++++ .../unit/providers/lecture_provider_test.mocks.dart | 10 ++++++++++ .../schedule/new_api/models/response_lecture.dart | 1 + .../controller/parsers/schedule/new_api/parser.dart | 8 +++++++- .../schedule/new_api/models/response_lecture.g.dart | 4 ++-- 6 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index b34d8a0fd..332a6d569 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -23,12 +23,16 @@ abstract class ScheduleFetcher extends SessionDependantFetcher { return thisWeek == nextWeek ? [thisWeek] : [thisWeek, nextWeek]; } + int getLectiveYear(DateTime date) { + return date.month < 8 ? date.year - 1 : date.year; + } + /// Returns [Dates]. List getDates() { final date = DateTime.now(); final weeks = getWeeks(date); - final lectiveYear = date.month < 8 ? date.year - 1 : date.year; + final lectiveYear = getLectiveYear(date); return weeks.map((week) => Dates(week, lectiveYear)).toList(); } diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index fb79f0004..a843550e4 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -19,6 +19,8 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { @override Future> getLectures(Session session, Profile profile) async { final endpoints = getEndpoints(session); + final lectiveYear = getLectiveYear(DateTime.now()); + final futures = >>[]; for (final baseUrl in endpoints) { @@ -27,6 +29,8 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { baseUrl, { 'pv_num_unico': session.username, + 'pv_ano_lectivo': lectiveYear.toString(), + 'pv_periodos': '1', }, session, ); diff --git a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart index 80287bc39..7c806537d 100644 --- a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart +++ b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart @@ -83,6 +83,16 @@ class MockScheduleFetcher extends _i1.Mock implements _i3.ScheduleFetcher { returnValueForMissingStub: <_i8.Week>[], ) as List<_i8.Week>); + @override + int getLectiveYear(DateTime? date) => (super.noSuchMethod( + Invocation.method( + #getLectiveYear, + [date], + ), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + @override List<_i3.Dates> getDates() => (super.noSuchMethod( Invocation.method( diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart index b74449f58..26f066808 100644 --- a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart +++ b/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart @@ -24,6 +24,7 @@ class ResponseLecture { DateTime start; DateTime end; + @JsonKey(name: 'ucs') List units; List classes; List persons; diff --git a/uni/lib/controller/parsers/schedule/new_api/parser.dart b/uni/lib/controller/parsers/schedule/new_api/parser.dart index 0d97b9f78..5f39d19a8 100644 --- a/uni/lib/controller/parsers/schedule/new_api/parser.dart +++ b/uni/lib/controller/parsers/schedule/new_api/parser.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; +import 'package:logger/logger.dart'; import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture.dart'; import 'package:uni/model/entities/lecture.dart'; @@ -26,11 +27,16 @@ String getScheduleApiUrlFromHtml( List getLecturesFromApiResponse( http.Response response, ) { + Logger().d(response.body); final json = jsonDecode(response.body) as Map; - final data = json['data'] as List>; + final data = json['data'] as List; + + final now = DateTime.now(); return data + .cast>() .map(ResponseLecture.fromJson) + .where((lecture) => lecture.end.isAfter(now)) .map( (lecture) => Lecture( lecture.units.first.acronym, diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart index 2f1037c0e..beabc82b1 100644 --- a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart +++ b/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart @@ -10,7 +10,7 @@ ResponseLecture _$ResponseLectureFromJson(Map json) => ResponseLecture( DateTime.parse(json['start'] as String), DateTime.parse(json['end'] as String), - (json['units'] as List) + (json['ucs'] as List) .map((e) => ResponseLectureUnit.fromJson(e as Map)) .toList(), (json['classes'] as List) @@ -30,7 +30,7 @@ Map _$ResponseLectureToJson(ResponseLecture instance) => { 'start': instance.start.toIso8601String(), 'end': instance.end.toIso8601String(), - 'units': instance.units.map((e) => e.toJson()).toList(), + 'ucs': instance.units.map((e) => e.toJson()).toList(), 'classes': instance.classes.map((e) => e.toJson()).toList(), 'persons': instance.persons.map((e) => e.toJson()).toList(), 'rooms': instance.rooms.map((e) => e.toJson()).toList(), From e3861c5dbc22f187b24ec053cfb7488a928264c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:43:06 +0100 Subject: [PATCH 04/99] refactor: properly name response variables --- .../schedule_fetcher/schedule_fetcher_new_api.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index a843550e4..a16127040 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -25,7 +25,7 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { for (final baseUrl in endpoints) { final future = Future(() async { - final scheduleRequest = await NetworkRouter.getWithCookies( + final scheduleResponse = await NetworkRouter.getWithCookies( baseUrl, { 'pv_num_unico': session.username, @@ -35,15 +35,15 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { session, ); - final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleRequest); + final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleResponse); - final scheduleApiRequest = await NetworkRouter.getWithCookies( + final scheduleApiResponse = await NetworkRouter.getWithCookies( scheduleApiUrl, {}, session, ); - return getLecturesFromApiResponse(scheduleApiRequest); + return getLecturesFromApiResponse(scheduleApiResponse); }); futures.add(future); From 6103f3446a18e117e8cd22d500da218f0aea06a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:46:34 +0100 Subject: [PATCH 05/99] test: remove test --- .../resources/schedule_example.html | 709 ------------------ .../integration/src/schedule_page_test.dart | 22 - 2 files changed, 731 deletions(-) delete mode 100644 packages/uni_app/test/integration/resources/schedule_example.html diff --git a/packages/uni_app/test/integration/resources/schedule_example.html b/packages/uni_app/test/integration/resources/schedule_example.html deleted file mode 100644 index 7026f0365..000000000 --- a/packages/uni_app/test/integration/resources/schedule_example.html +++ /dev/null @@ -1,709 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -FEUP - Horário de André Filipe Magalhães Rocha - - - - - - - - - - - -
-
-Logótipo -
-
-This page is not available in english -Ajuda - -Terminar sessão André Filipe Magalhães Rocha -
-
-Formação Online da Biblioteca
Hoje é domingo
-
-
Você está em: Início > André Filipe Magalhães Rocha > Horário de André Filipe Magalhães Rocha
-
-
- -
-
- - -
Autenticação
-
-Utilizador:
André Filipe Magalhães Rocha
- -
-
-
-Mapa das Instalações -
-
-
-Edifício A (Administração) -Edifício B (Aulas) - Bloco I -Edifício B (Aulas) - Bloco II -Edifício B (Aulas) - Bloco III -Edifício B (Aulas) - Bloco IV -Edifício C (Biblioteca) -Edifício D (CICA) -Edifício E (Química) -Edifício F (Minas e Metalurgia) -Edifício F (Minas e Metalurgia) -Edifício G (Civil) -Edifício H (Civil) -Edifício I (Electrotecnia) -Edifício J (Electrotecnia) -Edifício K (Pavilhão FCNAUP) -Edifício L (Mecânica) -Edifício M (Mecânica) -Edifício N (Garagem) -Edifício O (Cafetaria) -Edifício P (Cantina) -Edifício Q (Central de Gases) -Edifício R (Laboratório de Engenharia do Ambiente) -Edifício S (INESC) -Edifício T (Torre do INEGI) -Edifício U (Nave do INEGI) -Edifício X (Associação de Estudantes) - -
-
-
- -
-
-
-
Atalhos
-
- - - -
- -
-
Opções
-
- -
-
-
-
-

- -

Horário de André Filipe Magalhães Rocha

-

Legenda

- - - - - - - - - - - - - - - - - - - -
 Aula Teórica Aula Teórico-Prática Aula Prática Aula de Laboratório Aula de Orientação Tutorial Aula Prática Laboratorial Período de Almoço
-
- - - - - - - - - - -
Ano Letivo: - -
Período: - -
-
- -
-
-

2020 - A 1S 2S 1T 2T 3T 4T SP

-

Semanas de 21-02-2021 a 03-04-2021

- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Blocos
20-09 a 10-10
11-10 a 19-12
20-12 a 27-12
27-12 a 03-01
03-01 a 10-01
10-01 a 17-01
17-01 a 24-01
24-01 a 31-01
31-01 a 07-02
07-02 a 20-02
21-02 a 03-04
04-04 a 29-05
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HorasSegundaTerçaQuartaQuintaSextaSábado
08:00 - 08:30   LAPD (TP)
-4MIEIC01 -
- - - - - -
EaD  LSF
  
08:30 - 09:00     
09:00 - 09:30     
09:30 - 10:00     
10:00 - 10:30ASSO (TP)
-COMP_622 -
- - - - - -
EaD  AMA
    
10:30 - 11:00IOPE (TP)
-4MIEIC02 -
- - - - - -
B033  JFS
   
11:00 - 11:30ASSO (TP)
-4MIEIC03 -
- - - - - -
EaD  DRP
    
11:30 - 12:00    
12:00 - 12:30    
12:30 - 13:00     
13:00 - 13:30      
13:30 - 14:00      
14:00 - 14:30   IOPE (T)
-COMP_1 -
- - - - - -
EaD  MTD
LGPR (T)
-COMP_1 -
- - - - - -
B002  GMG
 
14:30 - 15:00    
15:00 - 15:30    
15:30 - 16:00    
16:00 - 16:30    LGPR (PL)
-4MIEIC04 -
- - - - - -
B331  RMA
 
16:30 - 17:00     
17:00 - 17:30   MSSI (TP)
-4MIEIC01 -
- - - - - -
EaD  RR
 
17:30 - 18:00    
18:00 - 18:30    
18:30 - 19:00    
19:00 - 19:30     
19:30 - 20:00     
20:00 - 20:30      
20:30 - 21:00      
21:00 - 21:30      
21:30 - 22:00      
22:00 - 22:30      
-
-
-
-
-
-
- -Recomendar Página - - -Voltar ao Topo
- -
- - - - - - - diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart index f163d8dfb..2f461beae 100644 --- a/packages/uni_app/test/integration/src/schedule_page_test.dart +++ b/packages/uni_app/test/integration/src/schedule_page_test.dart @@ -124,27 +124,5 @@ void main() async { await testSchedule(tester); }); - - testWidgets('Schedule with HTML Fetcher', (tester) async { - final mockHtml = File('test/integration/resources/schedule_example.html') - .readAsStringSync(encoding: const Latin1Codec()); - when(mockResponse.body).thenReturn(mockHtml); - when(mockResponse.statusCode).thenReturn(200); - when( - mockClient.get( - argThat(UriMatcher(contains(htmlFetcherIdentifier))), - headers: anyNamed('headers'), - ), - ).thenAnswer((_) async => mockResponse); - - when( - mockClient.get( - argThat(UriMatcher(contains(jsonFetcherIdentifier))), - headers: anyNamed('headers'), - ), - ).thenAnswer((_) async => badMockResponse); - - await testSchedule(tester); - }); }); } From 025f34a96d3c3a45776ee9911fa0d855367a6291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 22 Jul 2024 11:56:26 +0100 Subject: [PATCH 06/99] feat: handle multiple classes better --- uni/lib/controller/parsers/schedule/new_api/parser.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uni/lib/controller/parsers/schedule/new_api/parser.dart b/uni/lib/controller/parsers/schedule/new_api/parser.dart index 5f39d19a8..aaca33f16 100644 --- a/uni/lib/controller/parsers/schedule/new_api/parser.dart +++ b/uni/lib/controller/parsers/schedule/new_api/parser.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; -import 'package:logger/logger.dart'; import 'package:uni/controller/parsers/schedule/new_api/models/response_lecture.dart'; import 'package:uni/model/entities/lecture.dart'; @@ -27,7 +26,6 @@ String getScheduleApiUrlFromHtml( List getLecturesFromApiResponse( http.Response response, ) { - Logger().d(response.body); final json = jsonDecode(response.body) as Map; final data = json['data'] as List; @@ -45,7 +43,9 @@ List getLecturesFromApiResponse( lecture.end, lecture.rooms.first.name, lecture.persons.map((person) => person.acronym).join('+'), - lecture.classes.first.acronym, + lecture.classes.length > 1 + ? '${lecture.classes.first.acronym} + ${lecture.classes.length - 1}' + : lecture.classes.first.acronym, lecture.units.first.sigarraId, ), ) From 5de8cea34a268f17c327580f637440a0d222cafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 21 Aug 2024 16:54:27 +0100 Subject: [PATCH 07/99] refactor: use functional programming --- .../schedule_fetcher_new_api.dart | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index a16127040..55b678836 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -21,36 +21,31 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { final endpoints = getEndpoints(session); final lectiveYear = getLectiveYear(DateTime.now()); - final futures = >>[]; - - for (final baseUrl in endpoints) { - final future = Future(() async { - final scheduleResponse = await NetworkRouter.getWithCookies( - baseUrl, - { - 'pv_num_unico': session.username, - 'pv_ano_lectivo': lectiveYear.toString(), - 'pv_periodos': '1', - }, - session, - ); - - final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleResponse); - - final scheduleApiResponse = await NetworkRouter.getWithCookies( - scheduleApiUrl, - {}, - session, - ); - - return getLecturesFromApiResponse(scheduleApiResponse); - }); - - futures.add(future); - } + final futures = endpoints.map((baseUrl) async { + final scheduleResponse = await NetworkRouter.getWithCookies( + baseUrl, + { + 'pv_num_unico': session.username, + 'pv_ano_lectivo': lectiveYear.toString(), + 'pv_periodos': '1', + }, + session, + ); + + final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleResponse); + + final scheduleApiResponse = await NetworkRouter.getWithCookies( + scheduleApiUrl, + {}, + session, + ); + + return getLecturesFromApiResponse(scheduleApiResponse); + }); final results = await Future.wait(futures); + // TODO(limwa,#1281): Check if handling of lectures in both faculties is correct. final lectures = results.expand((element) => element).toList() ..sort((l1, l2) => l1.compare(l2)); From 8a776cfdaf326e8e0a788d692415d3dfa6e5ab60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 21 Aug 2024 17:07:50 +0100 Subject: [PATCH 08/99] chore: use new package layout --- .../fetchers/schedule_fetcher/schedule_fetcher_api.dart | 2 +- .../parsers/{parser_schedule.dart => schedule/api/parser.dart} | 0 .../parsers/schedule/new_api/models/response_lecture.dart | 0 .../parsers/schedule/new_api/models/response_lecture_class.dart | 0 .../schedule/new_api/models/response_lecture_person.dart | 0 .../parsers/schedule/new_api/models/response_lecture_room.dart | 0 .../schedule/new_api/models/response_lecture_typology.dart | 0 .../parsers/schedule/new_api/models/response_lecture_unit.dart | 0 .../lib/controller/parsers/schedule/new_api/parser.dart | 0 .../parsers/schedule/new_api/models/response_lecture.g.dart | 0 .../schedule/new_api/models/response_lecture_class.g.dart | 0 .../schedule/new_api/models/response_lecture_person.g.dart | 0 .../schedule/new_api/models/response_lecture_room.g.dart | 0 .../schedule/new_api/models/response_lecture_typology.g.dart | 0 .../schedule/new_api/models/response_lecture_unit.g.dart | 0 15 files changed, 1 insertion(+), 1 deletion(-) rename packages/uni_app/lib/controller/parsers/{parser_schedule.dart => schedule/api/parser.dart} (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart (100%) rename {uni => packages/uni_app}/lib/controller/parsers/schedule/new_api/parser.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart (100%) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index e0892fcce..cfc0d630b 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; 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.dart'; +import 'package:uni/controller/parsers/schedule/api/parser.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/entities/session.dart'; diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule.dart b/packages/uni_app/lib/controller/parsers/schedule/api/parser.dart similarity index 100% rename from packages/uni_app/lib/controller/parsers/parser_schedule.dart rename to packages/uni_app/lib/controller/parsers/schedule/api/parser.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_class.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_person.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_room.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_typology.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/models/response_lecture_unit.dart diff --git a/uni/lib/controller/parsers/schedule/new_api/parser.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart similarity index 100% rename from uni/lib/controller/parsers/schedule/new_api/parser.dart rename to packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture.g.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_class.g.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_person.g.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_room.g.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_typology.g.dart diff --git a/uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart b/packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart similarity index 100% rename from uni/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart rename to packages/uni_app/lib/generated/controller/parsers/schedule/new_api/models/response_lecture_unit.g.dart From ad8808f3d9ce5608c7e018196478549536823a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Tue, 23 Jul 2024 22:50:32 +0100 Subject: [PATCH 09/99] refactor: create FederatedSession and CredentialsSession --- .../background_workers/notifications.dart | 1 + .../controller/fetchers/print_fetcher.dart | 2 +- .../local_storage/database/app_database.dart | 3 +- .../controller/networking/network_router.dart | 58 ++++++++----------- .../uni_app/lib/model/entities/session.dart | 3 +- .../providers/startup/session_provider.dart | 4 +- .../session/credentials/request.dart | 51 ++++++++++++++++ .../session/credentials/session.dart | 34 +++++++++++ .../controller/session/federated/request.dart | 55 ++++++++++++++++++ .../controller/session/federated/session.dart | 36 ++++++++++++ uni/lib/controller/session/request.dart | 5 ++ uni/lib/controller/session/session.dart | 54 +++++++++++++++++ .../session/credentials/session.g.dart | 26 +++++++++ .../session/federated/session.g.dart | 27 +++++++++ 14 files changed, 320 insertions(+), 39 deletions(-) create mode 100644 uni/lib/controller/session/credentials/request.dart create mode 100644 uni/lib/controller/session/credentials/session.dart create mode 100644 uni/lib/controller/session/federated/request.dart create mode 100644 uni/lib/controller/session/federated/session.dart create mode 100644 uni/lib/controller/session/request.dart create mode 100644 uni/lib/controller/session/session.dart create mode 100644 uni/lib/generated/controller/session/credentials/session.g.dart create mode 100644 uni/lib/generated/controller/session/federated/session.g.dart diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index ecbb449bc..4975650c7 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:logger/logger.dart'; +import 'package:openid_client/openid_client.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart index fd66f556b..5a890fcbf 100644 --- a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart @@ -36,7 +36,7 @@ class PrintFetcher implements SessionDependantFetcher { }; final headers = {}; - headers['cookie'] = session.cookies; + headers['cookie'] = session.cookies.join('; '); headers['content-type'] = 'application/x-www-form-urlencoded'; final response = await http.post(url.toUri(), headers: headers, body: data); diff --git a/packages/uni_app/lib/controller/local_storage/database/app_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_database.dart index b2d1b30be..fbcfe3e92 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_database.dart @@ -42,7 +42,8 @@ abstract class AppDatabase { /// Getter to determine if the session is persistent. Future get persistentSession async { _persistentSession ??= - await PreferencesController.getPersistentUserInfo() != null; + await PreferencesController.getPersistentUserInfo() != null || + await PreferencesController.getSessionRefreshToken() != null; return _persistentSession!; } diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 80328207a..e0b2939ed 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -120,22 +120,14 @@ class NetworkRouter { throw Exception('Failed to get token from SIGARRA'); } - final setCookies = response.headers['set-cookie']; - if (setCookies == null) { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - final splitedCookies = setCookies.split(',').join('; ').split(';'); - final cookiesMap = {}; - for (final cookie in splitedCookies) { - final parts = cookie.split('='); - if (parts.length >= 2) { - final key = parts[0].replaceAll(' ', ''); - final value = parts[1].replaceAll(' ', ''); - cookiesMap[key] = value; - } - } + final cookies = NetworkRouter.extractCookies(response.headers); + final cookiesMap = cookies.fold>( + {}, + (previousValue, element) { + previousValue[element.name] = element.value; + return previousValue; + }, + ); if (!cookiesMap.containsKey('SI_SESSION') || !cookiesMap.containsKey('SI_SECURITY')) { @@ -143,12 +135,9 @@ class NetworkRouter { throw Exception('Failed to get token from SIGARRA'); } - final cookies = - 'SI_SESSION=${cookiesMap['SI_SESSION']}; SI_SECURITY=${cookiesMap['SI_SECURITY']}'; - return Session( username: studentNumber, - cookies: cookies, + cookies: NetworkRouter.extractCookies(response.headers), faculties: faculties, persistentSession: persistentSession, federatedSession: true, @@ -241,18 +230,19 @@ class NetworkRouter { } /// Extracts the cookies present in [headers]. - static String extractCookies(Map headers) { - final cookieList = []; - final cookies = headers['set-cookie']; - - if (cookies != null && cookies != '') { - final rawCookies = cookies.split(','); - for (final c in rawCookies) { - cookieList.add(Cookie.fromSetCookieValue(c).toString()); - } + static List extractCookies(Map headers) { + final setCookieHeader = headers[HttpHeaders.setCookieHeader]; + if (setCookieHeader == null) { + return []; + } + + final cookies = []; + final values = setCookieHeader.split(RegExp(r'\s*,\s*')); + for (final value in values) { + cookies.add(Cookie.fromSetCookieValue(value)); } - return cookieList.join(';'); + return cookies; } /// Makes an authenticated GET request with the given [session] to the @@ -277,7 +267,7 @@ class NetworkRouter { } final headers = {}; - headers['cookie'] = session.cookies; + headers['cookie'] = session.cookies.join('; '); final response = await (httpClient != null ? httpClient!.get(url.toUri(), headers: headers).timeout(timeout) @@ -308,7 +298,7 @@ class NetworkRouter { session ..username = newSession.username // (thePeras): Why is this necessary? ..cookies = newSession.cookies; - headers['cookie'] = session.cookies; + headers['cookie'] = session.cookies.join('; '); return http.get(url.toUri(), headers: headers).timeout(timeout); } else { // If the user is logged in but still got a 403, they are @@ -316,7 +306,7 @@ class NetworkRouter { // at the time of the request, // but other thread re-authenticated. // Since we do not know which one is the case, we try again. - headers['cookie'] = session.cookies; + headers['cookie'] = session.cookies.join('; '); final response = await http.get(url.toUri(), headers: headers).timeout(timeout); return response.statusCode == 200 @@ -336,7 +326,7 @@ class NetworkRouter { final url = '${getBaseUrl(session.faculties[0])}' 'fest_geral.cursos_list?pv_num_unico=${session.username}'; final headers = {}; - headers['cookie'] = session.cookies; + headers['cookie'] = session.cookies.join('; '); final response = await (httpClient != null ? httpClient!.get(url.toUri(), headers: headers) diff --git a/packages/uni_app/lib/model/entities/session.dart b/packages/uni_app/lib/model/entities/session.dart index 8e2ddf920..a55a88d10 100644 --- a/packages/uni_app/lib/model/entities/session.dart +++ b/packages/uni_app/lib/model/entities/session.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:http/http.dart' as http; import 'package:uni/controller/networking/network_router.dart'; @@ -14,7 +15,7 @@ class Session { }) : assert(faculties.isNotEmpty, 'session must have faculties'); String username; - String cookies; + List cookies; List faculties; bool persistentSession; bool federatedSession; diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 3c95aa844..631db3996 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -31,13 +31,13 @@ class SessionProvider extends StateProviderNotifier { final faculties = PreferencesController.getUserFaculties(); if (userPersistentInfo == null) { - return Session(username: '', cookies: '', faculties: faculties); + return Session(username: '', cookies: [], faculties: faculties); } return Session( faculties: faculties, username: userPersistentInfo.item1, - cookies: '', + cookies: [], persistentSession: true, ); } diff --git a/uni/lib/controller/session/credentials/request.dart b/uni/lib/controller/session/credentials/request.dart new file mode 100644 index 000000000..483967c1f --- /dev/null +++ b/uni/lib/controller/session/credentials/request.dart @@ -0,0 +1,51 @@ +import 'package:uni/controller/fetchers/faculties_fetcher.dart'; +import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/parsers/parser_session.dart'; +import 'package:uni/controller/session/credentials/session.dart'; +import 'package:uni/controller/session/request.dart'; +import 'package:uni/model/entities/login_exceptions.dart'; + +class CredentialsSessionRequest extends SessionRequest { + CredentialsSessionRequest({ + required this.username, + required this.password, + }); + + final String username; + final String password; + + @override + Future perform() async { + // We need to login to fetch the faculties, so perform a temporary login. + final tempSession = await NetworkRouter.login( + username, + password, + ['feup'], + persistentSession: false, + ignoreCached: true, + ); + + if (tempSession == null) { + // Get the fail reason. + final responseHtml = + await NetworkRouter.loginInSigarra(username, password, ['feup']); + + if (isPasswordExpired(responseHtml)) { + throw ExpiredCredentialsException(); + } else { + throw WrongCredentialsException(); + } + } + + final faculties = await getStudentFaculties(tempSession); + + final session = CredentialsSession( + username: tempSession.username, + cookies: tempSession.cookies, + faculties: faculties, + password: password, + ); + + return session; + } +} diff --git a/uni/lib/controller/session/credentials/session.dart b/uni/lib/controller/session/credentials/session.dart new file mode 100644 index 000000000..e964e3a9f --- /dev/null +++ b/uni/lib/controller/session/credentials/session.dart @@ -0,0 +1,34 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/controller/session/credentials/request.dart'; +import 'package:uni/controller/session/request.dart'; +import 'package:uni/controller/session/session.dart'; + +part '../../../generated/controller/session/credentials/session.g.dart'; + +@JsonSerializable() +class CredentialsSession extends Session { + CredentialsSession({ + required super.username, + required super.cookies, + required super.faculties, + required this.password, + }); + + // Serialization logic + + factory CredentialsSession.fromJson(Map json) => + _$CredentialsSessionFromJson(json); + + @override + Map toJson() => _$CredentialsSessionToJson(this); + + // Session implementation + + final String password; + + @override + SessionRequest createRefreshRequest() => CredentialsSessionRequest( + username: username, + password: password, + ); +} diff --git a/uni/lib/controller/session/federated/request.dart b/uni/lib/controller/session/federated/request.dart new file mode 100644 index 000000000..4c24500b3 --- /dev/null +++ b/uni/lib/controller/session/federated/request.dart @@ -0,0 +1,55 @@ +import 'dart:convert'; + +import 'package:logger/logger.dart'; +import 'package:openid_client/openid_client.dart'; +import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/federated/session.dart'; +import 'package:uni/controller/session/request.dart'; + +class FederatedSessionRequest extends SessionRequest { + FederatedSessionRequest({ + required this.username, + required this.faculties, + required this.credential, + }); + + final String username; + final List faculties; + final Credential credential; + + @override + Future perform() async { + final authorizedClient = credential.createHttpClient(); + + final sigarraTokenEndpoint = + Uri.parse('https://sigarra.up.pt/auth/oidc/token'); + + final response = await authorizedClient.get( + sigarraTokenEndpoint, + headers: { + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode != 200) { + Logger().e('Failed to get token from SIGARRA'); + throw Exception('Failed to get token from SIGARRA'); + } + + // TODO (limwa): Is checking the result necessary? + final body = jsonDecode(response.body) as Map; + if (body['result'] != 'OK') { + Logger().e('Failed to get token from SIGARRA'); + throw Exception('Failed to get token from SIGARRA'); + } + + final cookies = NetworkRouter.extractCookies(response.headers); + + return FederatedSession( + username: username, + faculties: faculties, + cookies: cookies, + credential: credential, + ); + } +} diff --git a/uni/lib/controller/session/federated/session.dart b/uni/lib/controller/session/federated/session.dart new file mode 100644 index 000000000..bd1e18915 --- /dev/null +++ b/uni/lib/controller/session/federated/session.dart @@ -0,0 +1,36 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:openid_client/openid_client.dart'; +import 'package:uni/controller/session/federated/request.dart'; +import 'package:uni/controller/session/request.dart'; +import 'package:uni/controller/session/session.dart'; + +part '../../../generated/controller/session/federated/session.g.dart'; + +@JsonSerializable() +class FederatedSession extends Session { + FederatedSession({ + required super.username, + required super.cookies, + required super.faculties, + required this.credential, + }); + + // Serialization logic + + factory FederatedSession.fromJson(Map json) => + _$FederatedSessionFromJson(json); + + @override + Map toJson() => _$FederatedSessionToJson(this); + + // Session implementation + + final Credential credential; + + @override + SessionRequest createRefreshRequest() => FederatedSessionRequest( + username: username, + faculties: faculties, + credential: credential, + ); +} diff --git a/uni/lib/controller/session/request.dart b/uni/lib/controller/session/request.dart new file mode 100644 index 000000000..b94012197 --- /dev/null +++ b/uni/lib/controller/session/request.dart @@ -0,0 +1,5 @@ +import 'package:uni/controller/session/session.dart'; + +abstract class SessionRequest { + Future perform(); +} diff --git a/uni/lib/controller/session/session.dart b/uni/lib/controller/session/session.dart new file mode 100644 index 000000000..7c5b241b7 --- /dev/null +++ b/uni/lib/controller/session/session.dart @@ -0,0 +1,54 @@ +import 'dart:io'; + +import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/controller/session/credentials/session.dart'; +import 'package:uni/controller/session/federated/session.dart'; +import 'package:uni/controller/session/request.dart'; + +const _authenticatedSessions = [ + FederatedSession.fromJson, + CredentialsSession.fromJson, +]; + +abstract class Session { + Session({ + required this.username, + required this.cookies, + required this.faculties, + }) : assert(faculties.isNotEmpty, 'session must have faculties'); + + // Serialization logic + + factory Session.fromJson(Map json) { + for (final fromJson in _authenticatedSessions) { + try { + return fromJson(json); + } catch (err) { + // ignore + } + } + + throw Exception('Unknown session type'); + } + + Map toJson(); + + // Session implementation + + final String username; + final List faculties; + @CookieConverter() + final List cookies; // TODO(limwa): use a CookieJar + + SessionRequest createRefreshRequest(); +} + +class CookieConverter implements JsonConverter { + const CookieConverter(); + + @override + Cookie fromJson(String json) => Cookie.fromSetCookieValue(json); + + @override + String toJson(Cookie object) => object.toString(); +} diff --git a/uni/lib/generated/controller/session/credentials/session.g.dart b/uni/lib/generated/controller/session/credentials/session.g.dart new file mode 100644 index 000000000..d45b963a8 --- /dev/null +++ b/uni/lib/generated/controller/session/credentials/session.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/credentials/session.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CredentialsSession _$CredentialsSessionFromJson(Map json) => + CredentialsSession( + username: json['username'] as String, + cookies: (json['cookies'] as List) + .map((e) => const CookieConverter().fromJson(e as String)) + .toList(), + faculties: + (json['faculties'] as List).map((e) => e as String).toList(), + password: json['password'] as String, + ); + +Map _$CredentialsSessionToJson(CredentialsSession instance) => + { + 'username': instance.username, + 'faculties': instance.faculties, + 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), + 'password': instance.password, + }; diff --git a/uni/lib/generated/controller/session/federated/session.g.dart b/uni/lib/generated/controller/session/federated/session.g.dart new file mode 100644 index 000000000..3e05ce68f --- /dev/null +++ b/uni/lib/generated/controller/session/federated/session.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/federated/session.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FederatedSession _$FederatedSessionFromJson(Map json) => + FederatedSession( + username: json['username'] as String, + cookies: (json['cookies'] as List) + .map((e) => const CookieConverter().fromJson(e as String)) + .toList(), + faculties: + (json['faculties'] as List).map((e) => e as String).toList(), + credential: + Credential.fromJson(json['credential'] as Map), + ); + +Map _$FederatedSessionToJson(FederatedSession instance) => + { + 'username': instance.username, + 'faculties': instance.faculties, + 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), + 'credential': instance.credential, + }; From ad1c8983a704285c8ec5277522ab17888561954e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 24 Jul 2024 14:54:49 +0100 Subject: [PATCH 10/99] refactor: serialize session requests instead --- .../background_workers/notifications.dart | 1 - .../controller/networking/network_router.dart | 16 +++--- .../uni_app/lib/model/entities/session.dart | 2 +- .../providers/startup/session_provider.dart | 53 +++++++------------ .../session/credentials/request.dart | 16 +++++- .../session/credentials/session.dart | 17 +----- .../controller/session/federated/request.dart | 42 ++++++++++++--- .../controller/session/federated/session.dart | 19 +------ uni/lib/controller/session/request.dart | 29 +++++++++- uni/lib/controller/session/session.dart | 39 +------------- .../session/credentials/request.g.dart | 21 ++++++++ .../session/credentials/session.g.dart | 26 --------- .../session/federated/request.g.dart | 20 +++++++ .../session/federated/session.g.dart | 27 ---------- 14 files changed, 147 insertions(+), 181 deletions(-) create mode 100644 uni/lib/generated/controller/session/credentials/request.g.dart delete mode 100644 uni/lib/generated/controller/session/credentials/session.g.dart create mode 100644 uni/lib/generated/controller/session/federated/request.g.dart delete mode 100644 uni/lib/generated/controller/session/federated/session.g.dart diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index 4975650c7..ecbb449bc 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:logger/logger.dart'; -import 'package:openid_client/openid_client.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index e0b2939ed..2f39aa800 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -120,7 +120,7 @@ class NetworkRouter { throw Exception('Failed to get token from SIGARRA'); } - final cookies = NetworkRouter.extractCookies(response.headers); + final cookies = NetworkRouter.extractCookies(response); final cookiesMap = cookies.fold>( {}, (previousValue, element) { @@ -137,7 +137,7 @@ class NetworkRouter { return Session( username: studentNumber, - cookies: NetworkRouter.extractCookies(response.headers), + cookies: NetworkRouter.extractCookies(response), faculties: faculties, persistentSession: persistentSession, federatedSession: true, @@ -229,16 +229,16 @@ class NetworkRouter { return response.body; } - /// Extracts the cookies present in [headers]. - static List extractCookies(Map headers) { - final setCookieHeader = headers[HttpHeaders.setCookieHeader]; - if (setCookieHeader == null) { + /// Extracts the cookies present in [response]. + static List extractCookies(http.Response response) { + final setCookieHeaders = + response.headersSplitValues[HttpHeaders.setCookieHeader]; + if (setCookieHeaders == null) { return []; } final cookies = []; - final values = setCookieHeader.split(RegExp(r'\s*,\s*')); - for (final value in values) { + for (final value in setCookieHeaders) { cookies.add(Cookie.fromSetCookieValue(value)); } diff --git a/packages/uni_app/lib/model/entities/session.dart b/packages/uni_app/lib/model/entities/session.dart index a55a88d10..27a51ddd3 100644 --- a/packages/uni_app/lib/model/entities/session.dart +++ b/packages/uni_app/lib/model/entities/session.dart @@ -36,7 +36,7 @@ class Session { return Session( faculties: faculties, username: responseBody['codigo'] as String, - cookies: NetworkRouter.extractCookies(response.headers), + cookies: NetworkRouter.extractCookies(response), ); } } diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 631db3996..649fedfb7 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -8,6 +8,7 @@ import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; +import 'package:uni/controller/session/federated/request.dart'; import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; @@ -144,46 +145,28 @@ class SessionProvider extends StateProviderNotifier { Future finishFederatedAuthentication(Uri uri) async { final credential = await _flow!.callback(uri.queryParameters); - final userInfo = (await credential.getUserInfo()).toJson(); - final token = (await credential.getTokenResponse()).accessToken; - if (token == null) { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - final studentNumber = userInfo['nmec'] as String; - final faculties = List.from(userInfo['ous'] as List) - .map((element) => element.toLowerCase()) - .toList(); - - final session = await NetworkRouter.loginWithToken( - token, - studentNumber, - faculties, - persistentSession: _persistentSession, - ); + final request = FederatedSessionRequest(credential: credential); + final session = await request.perform(); - if (session == null) { - throw Exception('Failed to login with token'); - } + Logger().d('Session refresh: ${session.createRefreshRequest().toJson()}'); - setState(session); + // setState(session); - if (_persistentSession && credential.refreshToken != null) { - await PreferencesController.saveSessionRefreshToken( - credential.refreshToken!, - studentNumber, - faculties, - ); - _persistentSession = false; - } + // if (_persistentSession && credential.refreshToken != null) { + // await PreferencesController.saveSessionRefreshToken( + // credential.refreshToken!, + // studentNumber, + // faculties, + // ); + // _persistentSession = false; + // } - Future.delayed( - const Duration(seconds: 20), - () => {NotificationManager().initializeNotifications()}, - ); + // Future.delayed( + // const Duration(seconds: 20), + // () => {NotificationManager().initializeNotifications()}, + // ); - await acceptTermsAndConditions(); + // await acceptTermsAndConditions(); } } diff --git a/uni/lib/controller/session/credentials/request.dart b/uni/lib/controller/session/credentials/request.dart index 483967c1f..bcbc63f48 100644 --- a/uni/lib/controller/session/credentials/request.dart +++ b/uni/lib/controller/session/credentials/request.dart @@ -1,3 +1,4 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; @@ -5,12 +6,25 @@ import 'package:uni/controller/session/credentials/session.dart'; import 'package:uni/controller/session/request.dart'; import 'package:uni/model/entities/login_exceptions.dart'; -class CredentialsSessionRequest extends SessionRequest { +part '../../../generated/controller/session/credentials/request.g.dart'; + +@JsonSerializable(explicitToJson: true) +class CredentialsSessionRequest extends SessionRequest { CredentialsSessionRequest({ required this.username, required this.password, }); + // Serialization logic + + factory CredentialsSessionRequest.fromJson(Map json) => + _$CredentialsSessionRequestFromJson(json); + + @override + Map toJson() => _$CredentialsSessionRequestToJson(this); + + // Request implementation + final String username; final String password; diff --git a/uni/lib/controller/session/credentials/session.dart b/uni/lib/controller/session/credentials/session.dart index e964e3a9f..22d898b11 100644 --- a/uni/lib/controller/session/credentials/session.dart +++ b/uni/lib/controller/session/credentials/session.dart @@ -1,11 +1,6 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:uni/controller/session/credentials/request.dart'; -import 'package:uni/controller/session/request.dart'; import 'package:uni/controller/session/session.dart'; -part '../../../generated/controller/session/credentials/session.g.dart'; - -@JsonSerializable() class CredentialsSession extends Session { CredentialsSession({ required super.username, @@ -14,20 +9,10 @@ class CredentialsSession extends Session { required this.password, }); - // Serialization logic - - factory CredentialsSession.fromJson(Map json) => - _$CredentialsSessionFromJson(json); - - @override - Map toJson() => _$CredentialsSessionToJson(this); - - // Session implementation - final String password; @override - SessionRequest createRefreshRequest() => CredentialsSessionRequest( + CredentialsSessionRequest createRefreshRequest() => CredentialsSessionRequest( username: username, password: password, ); diff --git a/uni/lib/controller/session/federated/request.dart b/uni/lib/controller/session/federated/request.dart index 4c24500b3..e5b4d695d 100644 --- a/uni/lib/controller/session/federated/request.dart +++ b/uni/lib/controller/session/federated/request.dart @@ -1,22 +1,48 @@ import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; import 'package:logger/logger.dart'; import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/session/federated/session.dart'; import 'package:uni/controller/session/request.dart'; -class FederatedSessionRequest extends SessionRequest { +part '../../../generated/controller/session/federated/request.g.dart'; + +@JsonSerializable(explicitToJson: true) +class FederatedSessionRequest extends SessionRequest { FederatedSessionRequest({ - required this.username, - required this.faculties, required this.credential, }); - final String username; - final List faculties; + // Serialization logic + + factory FederatedSessionRequest.fromJson(Map json) => + _$FederatedSessionRequestFromJson(json); + + @override + Map toJson() => _$FederatedSessionRequestToJson(this); + + // Request implementation + final Credential credential; + Future _getUsername() async { + final userInfo = await credential.getUserInfo(); + return userInfo.getTyped('nmec')!; + } + + Future> _getFaculties() async { + final userInfo = await credential.getUserInfo(); + final faculties = userInfo + .getTyped>('ous')! + .cast() + .map((element) => element.toLowerCase()) + .toList(); + + return faculties; + } + @override Future perform() async { final authorizedClient = credential.createHttpClient(); @@ -43,11 +69,11 @@ class FederatedSessionRequest extends SessionRequest { throw Exception('Failed to get token from SIGARRA'); } - final cookies = NetworkRouter.extractCookies(response.headers); + final cookies = NetworkRouter.extractCookies(response); return FederatedSession( - username: username, - faculties: faculties, + username: await _getUsername(), + faculties: await _getFaculties(), cookies: cookies, credential: credential, ); diff --git a/uni/lib/controller/session/federated/session.dart b/uni/lib/controller/session/federated/session.dart index bd1e18915..e98802f8f 100644 --- a/uni/lib/controller/session/federated/session.dart +++ b/uni/lib/controller/session/federated/session.dart @@ -1,12 +1,7 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/session/federated/request.dart'; -import 'package:uni/controller/session/request.dart'; import 'package:uni/controller/session/session.dart'; -part '../../../generated/controller/session/federated/session.g.dart'; - -@JsonSerializable() class FederatedSession extends Session { FederatedSession({ required super.username, @@ -15,22 +10,10 @@ class FederatedSession extends Session { required this.credential, }); - // Serialization logic - - factory FederatedSession.fromJson(Map json) => - _$FederatedSessionFromJson(json); - - @override - Map toJson() => _$FederatedSessionToJson(this); - - // Session implementation - final Credential credential; @override - SessionRequest createRefreshRequest() => FederatedSessionRequest( - username: username, - faculties: faculties, + FederatedSessionRequest createRefreshRequest() => FederatedSessionRequest( credential: credential, ); } diff --git a/uni/lib/controller/session/request.dart b/uni/lib/controller/session/request.dart index b94012197..f3a8c4be9 100644 --- a/uni/lib/controller/session/request.dart +++ b/uni/lib/controller/session/request.dart @@ -1,5 +1,30 @@ +import 'package:uni/controller/session/credentials/request.dart'; +import 'package:uni/controller/session/federated/request.dart'; import 'package:uni/controller/session/session.dart'; -abstract class SessionRequest { - Future perform(); +const _requestsFromJson = [ + FederatedSessionRequest.fromJson, + CredentialsSessionRequest.fromJson, +]; + +abstract class SessionRequest { + // Serialization logic + + static SessionRequest fromJson(Map json) { + for (final fromJson in _requestsFromJson) { + try { + return fromJson(json); + } catch (err) { + // ignore + } + } + + throw Exception('Unknown session request type'); + } + + Map toJson(); + + // Request implementation + + Future perform(); } diff --git a/uni/lib/controller/session/session.dart b/uni/lib/controller/session/session.dart index 7c5b241b7..8fa974452 100644 --- a/uni/lib/controller/session/session.dart +++ b/uni/lib/controller/session/session.dart @@ -1,15 +1,7 @@ import 'dart:io'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:uni/controller/session/credentials/session.dart'; -import 'package:uni/controller/session/federated/session.dart'; import 'package:uni/controller/session/request.dart'; -const _authenticatedSessions = [ - FederatedSession.fromJson, - CredentialsSession.fromJson, -]; - abstract class Session { Session({ required this.username, @@ -17,38 +9,9 @@ abstract class Session { required this.faculties, }) : assert(faculties.isNotEmpty, 'session must have faculties'); - // Serialization logic - - factory Session.fromJson(Map json) { - for (final fromJson in _authenticatedSessions) { - try { - return fromJson(json); - } catch (err) { - // ignore - } - } - - throw Exception('Unknown session type'); - } - - Map toJson(); - - // Session implementation - final String username; final List faculties; - @CookieConverter() final List cookies; // TODO(limwa): use a CookieJar - SessionRequest createRefreshRequest(); -} - -class CookieConverter implements JsonConverter { - const CookieConverter(); - - @override - Cookie fromJson(String json) => Cookie.fromSetCookieValue(json); - - @override - String toJson(Cookie object) => object.toString(); + SessionRequest createRefreshRequest(); } diff --git a/uni/lib/generated/controller/session/credentials/request.g.dart b/uni/lib/generated/controller/session/credentials/request.g.dart new file mode 100644 index 000000000..c7bfabdb3 --- /dev/null +++ b/uni/lib/generated/controller/session/credentials/request.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/credentials/request.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CredentialsSessionRequest _$CredentialsSessionRequestFromJson( + Map json) => + CredentialsSessionRequest( + username: json['username'] as String, + password: json['password'] as String, + ); + +Map _$CredentialsSessionRequestToJson( + CredentialsSessionRequest instance) => + { + 'username': instance.username, + 'password': instance.password, + }; diff --git a/uni/lib/generated/controller/session/credentials/session.g.dart b/uni/lib/generated/controller/session/credentials/session.g.dart deleted file mode 100644 index d45b963a8..000000000 --- a/uni/lib/generated/controller/session/credentials/session.g.dart +++ /dev/null @@ -1,26 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../../../../controller/session/credentials/session.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -CredentialsSession _$CredentialsSessionFromJson(Map json) => - CredentialsSession( - username: json['username'] as String, - cookies: (json['cookies'] as List) - .map((e) => const CookieConverter().fromJson(e as String)) - .toList(), - faculties: - (json['faculties'] as List).map((e) => e as String).toList(), - password: json['password'] as String, - ); - -Map _$CredentialsSessionToJson(CredentialsSession instance) => - { - 'username': instance.username, - 'faculties': instance.faculties, - 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), - 'password': instance.password, - }; diff --git a/uni/lib/generated/controller/session/federated/request.g.dart b/uni/lib/generated/controller/session/federated/request.g.dart new file mode 100644 index 000000000..200fcc1e8 --- /dev/null +++ b/uni/lib/generated/controller/session/federated/request.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/federated/request.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FederatedSessionRequest _$FederatedSessionRequestFromJson( + Map json) => + FederatedSessionRequest( + credential: + Credential.fromJson(json['credential'] as Map), + ); + +Map _$FederatedSessionRequestToJson( + FederatedSessionRequest instance) => + { + 'credential': instance.credential.toJson(), + }; diff --git a/uni/lib/generated/controller/session/federated/session.g.dart b/uni/lib/generated/controller/session/federated/session.g.dart deleted file mode 100644 index 3e05ce68f..000000000 --- a/uni/lib/generated/controller/session/federated/session.g.dart +++ /dev/null @@ -1,27 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../../../../controller/session/federated/session.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -FederatedSession _$FederatedSessionFromJson(Map json) => - FederatedSession( - username: json['username'] as String, - cookies: (json['cookies'] as List) - .map((e) => const CookieConverter().fromJson(e as String)) - .toList(), - faculties: - (json['faculties'] as List).map((e) => e as String).toList(), - credential: - Credential.fromJson(json['credential'] as Map), - ); - -Map _$FederatedSessionToJson(FederatedSession instance) => - { - 'username': instance.username, - 'faculties': instance.faculties, - 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), - 'credential': instance.credential, - }; From 6043220adbd0ae5b72c86f7988751292d8e1ab24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Tue, 30 Jul 2024 18:32:08 +0100 Subject: [PATCH 11/99] refactor: change logic to use new sessions --- .../background_workers/notifications.dart | 41 +-- .../notifications/tuition_notification.dart | 2 +- packages/uni_app/lib/controller/cleanup.dart | 15 +- .../fetchers/calendar_fetcher_html.dart | 2 +- .../all_course_units_fetcher.dart | 2 +- .../course_units_info_fetcher.dart | 2 +- .../current_course_units_fetcher.dart | 2 +- .../controller/fetchers/courses_fetcher.dart | 2 +- .../lib/controller/fetchers/exam_fetcher.dart | 2 +- .../fetchers/faculties_fetcher.dart | 2 +- .../lib/controller/fetchers/fees_fetcher.dart | 2 +- .../fetchers/library_occupation_fetcher.dart | 2 +- .../controller/fetchers/print_fetcher.dart | 2 +- .../controller/fetchers/profile_fetcher.dart | 2 +- .../fetchers/reference_fetcher.dart | 2 +- .../fetchers/restaurant_fetcher.dart | 2 +- .../schedule_fetcher/schedule_fetcher.dart | 2 +- .../schedule_fetcher_api.dart | 2 +- .../schedule_fetcher_html.dart | 2 +- .../fetchers/session_dependant_fetcher.dart | 2 +- .../local_storage/database/app_database.dart | 3 +- .../local_storage/file_offline_storage.dart | 2 +- .../local_storage/preferences_controller.dart | 108 ++------ .../controller/networking/network_router.dart | 182 +------------ .../parsers/parser_course_unit_info.dart | 2 +- .../parsers/parser_schedule_html.dart | 2 +- packages/uni_app/lib/main.dart | 5 +- .../lazy/course_units_info_provider.dart | 2 +- .../model/providers/lazy/exam_provider.dart | 2 +- .../providers/lazy/lecture_provider.dart | 2 +- .../providers/startup/profile_provider.dart | 2 +- .../providers/startup/session_provider.dart | 121 ++------- packages/uni_app/lib/utils/lazy.dart | 17 ++ .../view/common_widgets/faculty_filter.dart | 7 +- .../widgets/course_unit_student_row.dart | 2 +- packages/uni_app/lib/view/login/login.dart | 74 +++--- .../integration/src/exams2_page_test.dart | 2 +- .../test/integration/src/exams_page_test.dart | 2 +- .../integration/src/schedule_page_test.dart | 2 +- .../src/schedule_page_test.mocks.dart | 240 ++++++++---------- .../lecture_provider_test.mocks.dart | 2 +- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- .../session/credentials/request.dart | 11 +- .../session/credentials/session.dart | 14 + .../controller/session/federated/request.dart | 14 - .../controller/session/federated/session.dart | 28 ++ uni/lib/controller/session/request.dart | 25 -- uni/lib/controller/session/session.dart | 41 +++ .../session/credentials/session.g.dart | 26 ++ .../session/federated/request.g.dart | 20 -- .../session/federated/session.g.dart | 27 ++ 52 files changed, 395 insertions(+), 688 deletions(-) create mode 100644 packages/uni_app/lib/utils/lazy.dart create mode 100644 uni/lib/generated/controller/session/credentials/session.g.dart delete mode 100644 uni/lib/generated/controller/session/federated/request.g.dart create mode 100644 uni/lib/generated/controller/session/federated/session.g.dart diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index ecbb449bc..6bc40b4f2 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -10,8 +10,7 @@ import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; import 'package:uni/controller/local_storage/notification_timeout_storage.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:workmanager/workmanager.dart'; /// @@ -143,44 +142,14 @@ class NotificationManager { static Future updateAndTriggerNotifications() async { PreferencesController.prefs = await SharedPreferences.getInstance(); - final userInfo = await PreferencesController.getPersistentUserInfo(); - final faculties = PreferencesController.getUserFaculties(); - final refreshToken = await PreferencesController.getSessionRefreshToken(); + final savedSession = await PreferencesController.getSavedSession(); - if (faculties.isEmpty) { + if (savedSession == null) { return; } - if (userInfo == null && refreshToken == null) { - return; // Session not persistent - } - - Session? session; - if (userInfo != null) { - session = await NetworkRouter.login( - userInfo.item1, - userInfo.item2, - faculties, - persistentSession: false, - ); - } - - if (refreshToken != null) { - final token = await NetworkRouter.getAccessToken(refreshToken); - final studentNumber = await PreferencesController.getUserNumber(); - if (token == null || studentNumber == null) { - return; - } - session = await NetworkRouter.loginWithToken( - token, - studentNumber, - faculties, - persistentSession: false, - ); - } - if (session == null) { - return; - } + final request = savedSession.createRefreshRequest(); + final session = await request.perform(); // Get the .json file that contains the last time that the // notification has ran diff --git a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart index 5370b270f..6785b2fb4 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/fees_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/utils/duration_string_formatter.dart'; class TuitionNotification extends Notification { diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index 223f55741..fe968b7f7 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -17,10 +17,15 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_providers.dart'; Future cleanupStoredData(BuildContext context) async { - StateProviders.fromContext(context).invalidate(); + final providers = StateProviders.fromContext(context); + final session = providers.sessionProvider.state; + if (session != null) { + unawaited(session.onClose()); + } + + providers.invalidate(); final prefs = await SharedPreferences.getInstance(); - final faculties = PreferencesController.getUserFaculties(); await prefs.clear(); await Future.wait([ @@ -31,9 +36,9 @@ Future cleanupStoredData(BuildContext context) async { AppLastUserInfoUpdateDatabase().deleteLastUpdate(), AppBusStopDatabase().deleteBusStops(), AppCourseUnitsDatabase().deleteCourseUnits(), - NetworkRouter.killSigarraAuthentication(faculties), - PreferencesController.removePersistentUserInfo(), - PreferencesController.removeSessionRefreshToken(), + if (session != null) + NetworkRouter.killSigarraAuthentication(session.faculties), + PreferencesController.removeSavedSession(), ]); final toCleanDirectory = await getApplicationDocumentsDirectory(); diff --git a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart index e835a5de5..853f1ff1a 100644 --- a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_calendar.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/calendar_event.dart'; -import 'package:uni/model/entities/session.dart'; /// Fetch the school calendar from HTML class CalendarFetcherHtml implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index ef762fc80..e59d72f14 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_units.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/model/entities/session.dart'; class AllCourseUnitsFetcher { Future?> getAllCourseUnitsAndCourseAverages( diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart index 4bf08d56a..3b3232b51 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart @@ -2,11 +2,11 @@ import 'package:html/parser.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_unit_info.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; -import 'package:uni/model/entities/session.dart'; class CourseUnitsInfoFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart index bd291765b..ee69589ac 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart @@ -2,8 +2,8 @@ import 'dart:convert'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/model/entities/session.dart'; class CurrentCourseUnitsFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart index 776e042e1..65a13ada3 100644 --- a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart @@ -1,8 +1,8 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/model/entities/session.dart'; /// Returns the user's current list of [CourseUnit]. class CoursesFetcher implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart index a48b97c6e..c8fb12efd 100644 --- a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart @@ -1,10 +1,10 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; +import 'package:uni/controller/session/session.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'; -import 'package:uni/model/entities/session.dart'; class ExamFetcher implements SessionDependantFetcher { ExamFetcher(this.courses, this.userUcs); diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index f27c896bb..febcd1844 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -1,6 +1,6 @@ import 'package:html/parser.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; Future> getStudentFaculties(Session session) async { final response = await NetworkRouter.getWithCookies( diff --git a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart index c08a35164..a14436c7e 100644 --- a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; class FeesFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 1c7efae69..01ecf8019 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_library_occupation.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/library_occupation.dart'; -import 'package:uni/model/entities/session.dart'; /// Fetch the library occupation from Google Sheets class LibraryOccupationFetcherSheets implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart index 5a890fcbf..47c26b067 100644 --- a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; class PrintFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart index 17028f34c..8438285e9 100644 --- a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart @@ -2,8 +2,8 @@ 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'; import 'package:uni/controller/parsers/parser_courses.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; class ProfileFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart index 3179bff82..0d7a89ad3 100644 --- a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; class ReferenceFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart index bd0277acf..8c427265f 100644 --- a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_restaurants.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/restaurant.dart'; -import 'package:uni/model/entities/session.dart'; /// Class for fetching the menu class RestaurantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index b34d8a0fd..7c4428d16 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/utils/time/week.dart'; /// Class for fetching the user's schedule. diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index e0892fcce..270762fd4 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -2,9 +2,9 @@ import 'package:http/http.dart' as http; 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.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/utils/time/week.dart'; /// Class for fetching the user's lectures from the faculties' API. diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 6ca596dd1..b72389558 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -3,9 +3,9 @@ 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'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/utils/time/week.dart'; /// Class for fetching the user's lectures from the schedule's HTML page. diff --git a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart index 3cef2bd57..9dfddb261 100644 --- a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart @@ -1,4 +1,4 @@ -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; abstract class SessionDependantFetcher { List getEndpoints(Session session); diff --git a/packages/uni_app/lib/controller/local_storage/database/app_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_database.dart index fbcfe3e92..ab0916ea2 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_database.dart @@ -42,8 +42,7 @@ abstract class AppDatabase { /// Getter to determine if the session is persistent. Future get persistentSession async { _persistentSession ??= - await PreferencesController.getPersistentUserInfo() != null || - await PreferencesController.getSessionRefreshToken() != null; + await PreferencesController.getSavedSession() != null; return _persistentSession!; } diff --git a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart index dca50a64a..602177675 100644 --- a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart +++ b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart @@ -6,7 +6,7 @@ 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'; +import 'package:uni/controller/session/session.dart'; /// The offline image storage location on the device. Future get _localPath async { diff --git a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart index 2f1d8a172..d5d3e4b59 100644 --- a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart +++ b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart @@ -1,10 +1,11 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tuple/tuple.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/utils/favorite_widget_type.dart'; @@ -17,10 +18,7 @@ class PreferencesController { static late SharedPreferences prefs; static const _lastUpdateTimeKeySuffix = '_last_update_time'; - static const String _userNumber = 'user_number'; - static const String _userPw = 'user_password'; - static const String _userFaculties = 'user_faculties'; - static const String _refreshToken = 'refresh_token'; + static const String _userSession = 'user_session'; static const String _termsAndConditions = 'terms_and_conditions'; static const String _areTermsAndConditionsAcceptedKey = 'is_t&c_accepted'; static const String _tuitionNotificationsToggleKey = @@ -69,31 +67,21 @@ class PreferencesController { /// Saves the user's student number, password and faculties. static const FlutterSecureStorage _secureStorage = FlutterSecureStorage(); - static Future savePersistentUserInfo( - String user, - String pass, - List faculties, + static Future saveSession( + Session session, ) async { - await _secureStorage.write(key: _userNumber, value: user); - await _secureStorage.write(key: _userPw, value: pass); - await prefs.setStringList( - _userFaculties, - faculties, - ); // Could be multiple faculties; + await _secureStorage.write( + key: _userSession, value: jsonEncode(session.toJson())); } - /// Saves the user's session refresh token, student number and faculties. - static Future saveSessionRefreshToken( - String refreshToken, - String userNumber, - List faculties, - ) async { - await _secureStorage.write(key: _userNumber, value: userNumber); - await _secureStorage.write(key: _refreshToken, value: refreshToken); - await prefs.setStringList( - _userFaculties, - faculties, - ); + static Future getSavedSession() async { + final value = await _secureStorage.read(key: _userSession); + if (value == null) { + return null; + } + + final json = jsonDecode(value) as Map; + return Session.fromJson(json); } /// Sets whether or not the Terms and Conditions have been accepted. @@ -170,70 +158,8 @@ class PreferencesController { return DateTime.parse(date); } - /// Deletes the user's student number and password. - static Future removePersistentUserInfo() async { - await _secureStorage.delete(key: _userNumber); - await _secureStorage.delete(key: _userPw); - await prefs.remove(_userFaculties); - } - - /// Deletes the user's session refresh token. - static Future removeSessionRefreshToken() async { - await _secureStorage.delete(key: _userNumber); - await _secureStorage.delete(key: _refreshToken); - await prefs.remove(_userFaculties); - } - - /// Returns a tuple containing the user's student number and password. - /// - /// *Note:* - /// * 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 { - final userNum = await getUserNumber(); - final userPass = await getUserPassword(); - - if (userNum == null || userPass == null) { - return null; - } - return Tuple2(userNum, userPass); - } - - /// Returns the user's session refresh token. - static Future getSessionRefreshToken() { - return _secureStorage.read(key: _refreshToken); - } - - /// Returns the user's faculties - static List getUserFaculties() { - final storedFaculties = prefs.getStringList(_userFaculties); - return storedFaculties ?? ['feup']; - // TODO(bdmendes): Store dropdown choices in the db for later storage; - } - - /// Returns the user's student number. - static Future getUserNumber() async { - try { - if (await _secureStorage.containsKey(key: _userNumber)) { - return await _secureStorage.read(key: _userNumber); - } - return null; - } catch (err) { - return null; - } - } - - /// Returns the user's password, in plain text format. - static Future getUserPassword() async { - try { - if (await _secureStorage.containsKey(key: _userPw)) { - return await _secureStorage.read(key: _userPw); - } - return null; - } catch (err) { - return null; - } + static Future removeSavedSession() async { + await _secureStorage.delete(key: _userSession); } /// Replaces the user's favorite widgets with [newFavorites]. diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 2f39aa800..f5ab48145 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -7,8 +7,7 @@ import 'package:http/http.dart'; import 'package:logger/logger.dart'; import 'package:openid_client/openid_client.dart'; import 'package:synchronized/synchronized.dart'; -import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/utils/constants.dart'; import 'package:uni/view/navigation_service.dart'; @@ -38,179 +37,17 @@ class NetworkRouter { /// Returned on repeated concurrent login requests. static Session? _cachedSession; - /// Performs a login using the Sigarra API, - /// returning an authenticated [Session] with the - /// given username [username] and password [password] if successful. - static Future login( - String username, - String password, - List faculties, { - required bool persistentSession, - bool ignoreCached = false, - }) async { - return _loginLock.synchronized( - () async { - if (_lastLoginTime != null && - DateTime.now().difference(_lastLoginTime!) < - const Duration(minutes: 1) && - _cachedSession != null && - !ignoreCached) { - 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); - - if (response.statusCode != 200) { - Logger().e('Login failed with status code ${response.statusCode}'); - return null; - } - - final session = Session.fromLogin( - response, - faculties, - persistentSession: persistentSession, - ); - - if (session == null) { - Logger().e('Login failed: user not authenticated'); - return null; - } - - Logger().i('Login successful'); - _lastLoginTime = DateTime.now(); - _cachedSession = session; - - return session; - }, - timeout: _requestTimeout, - ); - } - - static Future loginWithToken( - String token, - String studentNumber, - List faculties, { - required bool persistentSession, - }) async { - // Get the cookie from SIGARRA - const sigarraTokenEndpoint = 'https://sigarra.up.pt/auth/oidc/token'; - final response = await http.get( - Uri.parse(sigarraTokenEndpoint), - headers: { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }, - ); - - if (response.statusCode != 200) { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - final body = jsonDecode(response.body) as Map; - - if (body['result'] != 'OK') { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - final cookies = NetworkRouter.extractCookies(response); - final cookiesMap = cookies.fold>( - {}, - (previousValue, element) { - previousValue[element.name] = element.value; - return previousValue; - }, - ); - - if (!cookiesMap.containsKey('SI_SESSION') || - !cookiesMap.containsKey('SI_SECURITY')) { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - return Session( - username: studentNumber, - cookies: NetworkRouter.extractCookies(response), - faculties: faculties, - persistentSession: persistentSession, - federatedSession: true, - ); - } - /// Re-authenticates the user via the Sigarra API /// using data stored in [session], /// returning an updated Session if successful. static Future reLoginFromSession(Session session) async { - if (!session.federatedSession) { - final password = await PreferencesController.getUserPassword(); - - if (password == null) { - Logger().e('Re-login failed: password not found'); - return null; - } - return login( - session.username, - password, - session.faculties, - persistentSession: session.persistentSession, - ); - } - - final refreshToken = await PreferencesController.getSessionRefreshToken(); - final faculties = PreferencesController.getUserFaculties(); - final studentNumber = await PreferencesController.getUserNumber(); - if (refreshToken == null || studentNumber == null || faculties.isEmpty) { - Logger().e('Re-login failed: refresh token not found'); + final request = session.createRefreshRequest(); + try { + return request.perform(); + } catch (err, st) { + Logger().e(err, stackTrace: st); return null; } - - final accessToken = await getAccessToken(refreshToken); - if (accessToken == null) { - Logger().e('Re-login failed: access token not retrived'); - return null; - } - - return loginWithToken( - accessToken, - studentNumber, - faculties, - persistentSession: session.persistentSession, - ); - } - - /// Get a new accessing Refresh with the refresh token - static Future getAccessToken(String refreshToken) async { - final issuer = await Issuer.discover(Uri.parse(realm)); - if (issuer.metadata.tokenEndpoint == null) { - Logger().e('Re-login failed: token endpoint not found'); - return null; - } - - final response = await http.post( - issuer.metadata.tokenEndpoint!, - body: { - 'grant_type': 'refresh_token', - 'refresh_token': refreshToken, - 'client_id': clientId, - }, - ); - - final body = json.decode(response.body) as Map; - final accessToken = body['access_token'] as String; - - if (response.statusCode != 200) { - Logger().e('Re-login failed: status code ${response.statusCode}'); - return null; - } - - return accessToken; } /// Returns the response body of the login in Sigarra @@ -297,7 +134,9 @@ class NetworkRouter { session ..username = newSession.username // (thePeras): Why is this necessary? - ..cookies = newSession.cookies; + ..cookies = + newSession.cookies; // TODO(limwa): because it is very bad code xD + headers['cookie'] = session.cookies.join('; '); return http.get(url.toUri(), headers: headers).timeout(timeout); } else { @@ -352,8 +191,7 @@ class NetworkRouter { /// Makes an HTTP request to terminate the session in Sigarra. static Future killSigarraAuthentication( - List faculties, - ) async { + List faculties) async { final url = '${NetworkRouter.getBaseUrl(faculties[0])}vld_validacao.sair'; final response = await http.get(url.toUri()).timeout(_requestTimeout); diff --git a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart index 51025c96b..aceb39afc 100644 --- a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart +++ b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart @@ -3,12 +3,12 @@ import 'dart:convert'; import 'package:html/parser.dart'; import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_file.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; -import 'package:uni/model/entities/session.dart'; Future> parseFiles( http.Response response, diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart index f406724da..70c7967f0 100644 --- a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart +++ b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart @@ -4,8 +4,8 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/model/utils/time/weekday_mapper.dart'; diff --git a/packages/uni_app/lib/main.dart b/packages/uni_app/lib/main.dart index ba6387f69..9956d5e50 100644 --- a/packages/uni_app/lib/main.dart +++ b/packages/uni_app/lib/main.dart @@ -57,10 +57,9 @@ SentryEvent? beforeSend(SentryEvent event) { } Future firstRoute() async { - final userPersistentInfo = - await PreferencesController.getPersistentUserInfo(); + final savedSession = await PreferencesController.getSavedSession(); - if (userPersistentInfo != null) { + if (savedSession != null) { return '/${NavigationItem.navPersonalArea.route}'; } diff --git a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart index 19ace085d..53d3e3de2 100644 --- a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart @@ -2,11 +2,11 @@ import 'dart:collection'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; diff --git a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart index e8d6d3209..2b2074a34 100644 --- a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart @@ -3,10 +3,10 @@ import 'dart:async'; import 'package:uni/controller/fetchers/exam_fetcher.dart'; import 'package:uni/controller/local_storage/database/app_exams_database.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index 2dc1264a0..78eeca70c 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -4,9 +4,9 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; diff --git a/packages/uni_app/lib/model/providers/startup/profile_provider.dart b/packages/uni_app/lib/model/providers/startup/profile_provider.dart index 629499aeb..0d6d6bbe6 100644 --- a/packages/uni_app/lib/model/providers/startup/profile_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/profile_provider.dart @@ -13,10 +13,10 @@ import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 649fedfb7..3c7926e55 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -3,21 +3,18 @@ import 'dart:async'; import 'package:logger/logger.dart'; import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/background_workers/notifications.dart'; -import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/controller/session/federated/request.dart'; -import 'package:uni/model/entities/login_exceptions.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/controller/session/request.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; import 'package:uni/utils/constants.dart'; import 'package:url_launcher/url_launcher.dart'; -class SessionProvider extends StateProviderNotifier { +class SessionProvider extends StateProviderNotifier { SessionProvider() : super( cacheDuration: null, @@ -26,26 +23,19 @@ class SessionProvider extends StateProviderNotifier { ); @override - Future loadFromStorage(StateProviders stateProviders) async { - final userPersistentInfo = - await PreferencesController.getPersistentUserInfo(); - final faculties = PreferencesController.getUserFaculties(); - - if (userPersistentInfo == null) { - return Session(username: '', cookies: [], faculties: faculties); - } - - return Session( - faculties: faculties, - username: userPersistentInfo.item1, - cookies: [], - persistentSession: true, - ); + Future loadFromStorage(StateProviders stateProviders) async { + final session = await PreferencesController.getSavedSession(); + return session; } @override - Future loadFromRemote(StateProviders stateProviders) async { - return state!; + Future loadFromRemote(StateProviders stateProviders) async { + if (state == null) { + return null; + } + + final request = state!.createRefreshRequest(); + return request.perform(); } static Future _invoke(Uri uri) async { @@ -56,53 +46,16 @@ class SessionProvider extends StateProviderNotifier { } } - Future postAuthentication( - String username, - String password, { + Future login( + SessionRequest request, { required bool persistentSession, }) async { - Session? session; - List faculties; - - // We need to login to fetch the faculties, so perform a temporary login. - final tempSession = await NetworkRouter.login( - username, - password, - ['feup'], - persistentSession: false, - ignoreCached: true, - ); - faculties = await getStudentFaculties(tempSession!); - - // Now get the session with the correct faculties. - session = await NetworkRouter.login( - username, - password, - faculties, - persistentSession: persistentSession, - ignoreCached: true, - ); - - if (session == null) { - // Get the fail reason. - final responseHtml = - await NetworkRouter.loginInSigarra(username, password, ['feup']); - - if (isPasswordExpired(responseHtml)) { - throw ExpiredCredentialsException(); - } else { - throw WrongCredentialsException(); - } - } + final session = await request.perform(); setState(session); if (persistentSession) { - await PreferencesController.savePersistentUserInfo( - session.username, - password, - faculties, - ); + await PreferencesController.saveSession(session); } Future.delayed( @@ -113,21 +66,17 @@ class SessionProvider extends StateProviderNotifier { await acceptTermsAndConditions(); } - late Flow? _flow; - bool _persistentSession = false; - Future federatedAuthentication({ + required Future onAuthentication, required bool persistentSession, }) async { - _persistentSession = persistentSession; - final issuer = await Issuer.discover(Uri.parse(realm)); final client = Client( issuer, clientId, ); - _flow = Flow.authorizationCodeWithPKCE( + final flow = Flow.authorizationCodeWithPKCE( client, scopes: [ 'openid', @@ -137,36 +86,14 @@ class SessionProvider extends StateProviderNotifier { 'audience', 'uporto_data', ], - ); - _flow?.redirectUri = Uri.parse('pt.up.fe.ni.uni://auth'); + )..redirectUri = Uri.parse('pt.up.fe.ni.uni://auth'); - await _invoke(_flow!.authenticationUri); - } + await _invoke(flow.authenticationUri); + final uri = await onAuthentication; - Future finishFederatedAuthentication(Uri uri) async { - final credential = await _flow!.callback(uri.queryParameters); + final credential = await flow.callback(uri.queryParameters); final request = FederatedSessionRequest(credential: credential); - final session = await request.perform(); - - Logger().d('Session refresh: ${session.createRefreshRequest().toJson()}'); - - // setState(session); - - // if (_persistentSession && credential.refreshToken != null) { - // await PreferencesController.saveSessionRefreshToken( - // credential.refreshToken!, - // studentNumber, - // faculties, - // ); - // _persistentSession = false; - // } - - // Future.delayed( - // const Duration(seconds: 20), - // () => {NotificationManager().initializeNotifications()}, - // ); - - // await acceptTermsAndConditions(); + await login(request, persistentSession: persistentSession); } } diff --git a/packages/uni_app/lib/utils/lazy.dart b/packages/uni_app/lib/utils/lazy.dart new file mode 100644 index 000000000..77493a3a2 --- /dev/null +++ b/packages/uni_app/lib/utils/lazy.dart @@ -0,0 +1,17 @@ +class Lazy { + Lazy(this._builder); + + final T Function() _builder; + + bool _isInitialized = false; + late T _value; + + T get value { + if (!_isInitialized) { + _isInitialized = true; + _value = _builder(); + } + + return _value; + } +} diff --git a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart index caa9055a7..6b01b1bce 100644 --- a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart +++ b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:uni/controller/local_storage/preferences_controller.dart'; +import 'package:provider/provider.dart'; +import 'package:uni/controller/session/session.dart'; class FacultyFilter extends StatelessWidget { const FacultyFilter({ @@ -14,7 +15,9 @@ class FacultyFilter extends StatelessWidget { @override Widget build(BuildContext context) { - final authorizedFaculties = PreferencesController.getUserFaculties() + final session = Provider.of(context); + + final authorizedFaculties = session.faculties .where( faculties.contains, ) diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart index 4bc3663b9..635cfdc79 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; class CourseUnitStudentRow extends StatelessWidget { diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index d58f5ba1b..56f0d25a2 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.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/networking/url_launcher.dart'; +import 'package:uni/controller/session/credentials/request.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; @@ -55,39 +56,6 @@ class LoginPageViewState extends State super.initState(); WidgetsBinding.instance.addObserver(this); - - final appLinks = AppLinks(); - appLinks.uriLinkStream.listen((uri) async { - Logger().d('AppLinks intercepted: $uri'); - await closeInAppWebView(); - setState(() { - _intercepting = true; - _loggingIn = true; - }); - - if (uri.host == 'auth') { - WidgetsBinding.instance.addPostFrameCallback((_) async { - final sessionProvider = - Provider.of(context, listen: false); - try { - await sessionProvider.finishFederatedAuthentication(uri); - if (mounted) { - await Navigator.pushReplacementNamed( - context, - '/${NavigationItem.navPersonalArea.route}', - ); - } - } catch (err) { - Logger().e('Failed to login with FederatedLogin: $err'); - } - }); - } - - setState(() { - _loggingIn = true; - _intercepting = false; - }); - }); } @override @@ -99,6 +67,15 @@ class LoginPageViewState extends State super.dispose(); } + Future getInterceptedUri() async { + final appLinks = AppLinks(); + final uri = + await appLinks.uriLinkStream.firstWhere((uri) => uri.host == 'auth'); + + Logger().d('AppLinks intercepted: $uri'); + return uri; + } + Future _login() async { final sessionProvider = Provider.of(context, listen: false); @@ -111,11 +88,10 @@ class LoginPageViewState extends State setState(() { _loggingIn = true; }); - await sessionProvider.postAuthentication( - user, - pass, - persistentSession: _keepSignedIn, - ); + + final request = + CredentialsSessionRequest(username: user, password: pass); + await sessionProvider.login(request, persistentSession: _keepSignedIn); usernameController.clear(); passwordController.clear(); @@ -174,9 +150,31 @@ class LoginPageViewState extends State setState(() { _loggingIn = true; }); + + final uri = getInterceptedUri(); await sessionProvider.federatedAuthentication( + onAuthentication: uri, persistentSession: _keepSignedIn, ); + + await closeInAppWebView(); + + setState(() { + _intercepting = true; + _loggingIn = true; + }); + + if (mounted) { + await Navigator.pushReplacementNamed( + context, + '/${NavigationItem.navPersonalArea.route}', + ); + } + + setState(() { + _loggingIn = true; + _intercepting = false; + }); } catch (err, st) { await Sentry.captureException(err, stackTrace: st); await closeInAppWebView(); diff --git a/packages/uni_app/test/integration/src/exams2_page_test.dart b/packages/uni_app/test/integration/src/exams2_page_test.dart index a61a8b962..b0497620a 100644 --- a/packages/uni_app/test/integration/src/exams2_page_test.dart +++ b/packages/uni_app/test/integration/src/exams2_page_test.dart @@ -9,11 +9,11 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; +import 'package:uni/controller/session/session.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'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/exams.dart'; diff --git a/packages/uni_app/test/integration/src/exams_page_test.dart b/packages/uni_app/test/integration/src/exams_page_test.dart index c265460d4..cf97b24cc 100644 --- a/packages/uni_app/test/integration/src/exams_page_test.dart +++ b/packages/uni_app/test/integration/src/exams_page_test.dart @@ -8,11 +8,11 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; +import 'package:uni/controller/session/session.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'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/view/exams/exams.dart'; diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart index f163d8dfb..bc39d1ee0 100644 --- a/packages/uni_app/test/integration/src/schedule_page_test.dart +++ b/packages/uni_app/test/integration/src/schedule_page_test.dart @@ -8,9 +8,9 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/view/schedule/schedule.dart'; diff --git a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart index 19aa3c3c2..7512f7751 100644 --- a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart +++ b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -3,19 +3,20 @@ // 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 _i7; -import 'dart:ui' as _i12; +import 'dart:async' as _i3; +import 'dart:convert' as _i4; +import 'dart:typed_data' as _i6; +import 'dart:ui' as _i13; -import 'package:flutter/material.dart' as _i11; +import 'package:flutter/material.dart' as _i12; import 'package:http/http.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i6; -import 'package:uni/model/entities/session.dart' as _i3; -import 'package:uni/model/providers/startup/session_provider.dart' as _i8; +import 'package:mockito/src/dummies.dart' as _i5; +import 'package:uni/controller/session/request.dart' as _i11; +import 'package:uni/controller/session/session.dart' as _i9; +import 'package:uni/model/providers/startup/session_provider.dart' as _i7; import 'package:uni/model/providers/state_providers.dart' as _i10; -import 'package:uni/model/request_status.dart' as _i9; +import 'package:uni/model/request_status.dart' as _i8; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -51,22 +52,12 @@ class _FakeStreamedResponse_1 extends _i1.SmartFake ); } -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( + _i3.Future<_i2.Response> head( Uri? url, { Map? headers, }) => @@ -76,7 +67,7 @@ class MockClient extends _i1.Mock implements _i2.Client { [url], {#headers: headers}, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #head, @@ -85,7 +76,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #head, @@ -93,10 +84,10 @@ class MockClient extends _i1.Mock implements _i2.Client { {#headers: headers}, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future<_i2.Response> get( + _i3.Future<_i2.Response> get( Uri? url, { Map? headers, }) => @@ -106,7 +97,7 @@ class MockClient extends _i1.Mock implements _i2.Client { [url], {#headers: headers}, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #get, @@ -115,7 +106,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #get, @@ -123,14 +114,14 @@ class MockClient extends _i1.Mock implements _i2.Client { {#headers: headers}, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future<_i2.Response> post( + _i3.Future<_i2.Response> post( Uri? url, { Map? headers, Object? body, - _i5.Encoding? encoding, + _i4.Encoding? encoding, }) => (super.noSuchMethod( Invocation.method( @@ -142,7 +133,7 @@ class MockClient extends _i1.Mock implements _i2.Client { #encoding: encoding, }, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #post, @@ -155,7 +146,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #post, @@ -167,14 +158,14 @@ class MockClient extends _i1.Mock implements _i2.Client { }, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future<_i2.Response> put( + _i3.Future<_i2.Response> put( Uri? url, { Map? headers, Object? body, - _i5.Encoding? encoding, + _i4.Encoding? encoding, }) => (super.noSuchMethod( Invocation.method( @@ -186,7 +177,7 @@ class MockClient extends _i1.Mock implements _i2.Client { #encoding: encoding, }, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #put, @@ -199,7 +190,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #put, @@ -211,14 +202,14 @@ class MockClient extends _i1.Mock implements _i2.Client { }, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future<_i2.Response> patch( + _i3.Future<_i2.Response> patch( Uri? url, { Map? headers, Object? body, - _i5.Encoding? encoding, + _i4.Encoding? encoding, }) => (super.noSuchMethod( Invocation.method( @@ -230,7 +221,7 @@ class MockClient extends _i1.Mock implements _i2.Client { #encoding: encoding, }, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #patch, @@ -243,7 +234,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #patch, @@ -255,14 +246,14 @@ class MockClient extends _i1.Mock implements _i2.Client { }, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future<_i2.Response> delete( + _i3.Future<_i2.Response> delete( Uri? url, { Map? headers, Object? body, - _i5.Encoding? encoding, + _i4.Encoding? encoding, }) => (super.noSuchMethod( Invocation.method( @@ -274,7 +265,7 @@ class MockClient extends _i1.Mock implements _i2.Client { #encoding: encoding, }, ), - returnValue: _i4.Future<_i2.Response>.value(_FakeResponse_0( + returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #delete, @@ -287,7 +278,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.Response>.value(_FakeResponse_0( + _i3.Future<_i2.Response>.value(_FakeResponse_0( this, Invocation.method( #delete, @@ -299,10 +290,10 @@ class MockClient extends _i1.Mock implements _i2.Client { }, ), )), - ) as _i4.Future<_i2.Response>); + ) as _i3.Future<_i2.Response>); @override - _i4.Future read( + _i3.Future read( Uri? url, { Map? headers, }) => @@ -312,7 +303,7 @@ class MockClient extends _i1.Mock implements _i2.Client { [url], {#headers: headers}, ), - returnValue: _i4.Future.value(_i6.dummyValue( + returnValue: _i3.Future.value(_i5.dummyValue( this, Invocation.method( #read, @@ -321,7 +312,7 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future.value(_i6.dummyValue( + _i3.Future.value(_i5.dummyValue( this, Invocation.method( #read, @@ -329,10 +320,10 @@ class MockClient extends _i1.Mock implements _i2.Client { {#headers: headers}, ), )), - ) as _i4.Future); + ) as _i3.Future); @override - _i4.Future<_i7.Uint8List> readBytes( + _i3.Future<_i6.Uint8List> readBytes( Uri? url, { Map? headers, }) => @@ -342,20 +333,20 @@ class MockClient extends _i1.Mock implements _i2.Client { [url], {#headers: headers}, ), - returnValue: _i4.Future<_i7.Uint8List>.value(_i7.Uint8List(0)), + returnValue: _i3.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), returnValueForMissingStub: - _i4.Future<_i7.Uint8List>.value(_i7.Uint8List(0)), - ) as _i4.Future<_i7.Uint8List>); + _i3.Future<_i6.Uint8List>.value(_i6.Uint8List(0)), + ) as _i3.Future<_i6.Uint8List>); @override - _i4.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) => + _i3.Future<_i2.StreamedResponse> send(_i2.BaseRequest? request) => (super.noSuchMethod( Invocation.method( #send, [request], ), returnValue: - _i4.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( this, Invocation.method( #send, @@ -363,14 +354,14 @@ class MockClient extends _i1.Mock implements _i2.Client { ), )), returnValueForMissingStub: - _i4.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( + _i3.Future<_i2.StreamedResponse>.value(_FakeStreamedResponse_1( this, Invocation.method( #send, [request], ), )), - ) as _i4.Future<_i2.StreamedResponse>); + ) as _i3.Future<_i2.StreamedResponse>); @override void close() => super.noSuchMethod( @@ -387,20 +378,20 @@ class MockClient extends _i1.Mock implements _i2.Client { /// See the documentation for Mockito's code generation for more information. class MockResponse extends _i1.Mock implements _i2.Response { @override - _i7.Uint8List get bodyBytes => (super.noSuchMethod( + _i6.Uint8List get bodyBytes => (super.noSuchMethod( Invocation.getter(#bodyBytes), - returnValue: _i7.Uint8List(0), - returnValueForMissingStub: _i7.Uint8List(0), - ) as _i7.Uint8List); + returnValue: _i6.Uint8List(0), + returnValueForMissingStub: _i6.Uint8List(0), + ) as _i6.Uint8List); @override String get body => (super.noSuchMethod( Invocation.getter(#body), - returnValue: _i6.dummyValue( + returnValue: _i5.dummyValue( this, Invocation.getter(#body), ), - returnValueForMissingStub: _i6.dummyValue( + returnValueForMissingStub: _i5.dummyValue( this, Invocation.getter(#body), ), @@ -438,7 +429,7 @@ class MockResponse extends _i1.Mock implements _i2.Response { /// A class which mocks [SessionProvider]. /// /// See the documentation for Mockito's code generation for more information. -class MockSessionProvider extends _i1.Mock implements _i8.SessionProvider { +class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { @override bool get dependsOnSession => (super.noSuchMethod( Invocation.getter(#dependsOnSession), @@ -465,11 +456,11 @@ class MockSessionProvider extends _i1.Mock implements _i8.SessionProvider { ); @override - _i9.RequestStatus get requestStatus => (super.noSuchMethod( + _i8.RequestStatus get requestStatus => (super.noSuchMethod( Invocation.getter(#requestStatus), - returnValue: _i9.RequestStatus.none, - returnValueForMissingStub: _i9.RequestStatus.none, - ) as _i9.RequestStatus); + returnValue: _i8.RequestStatus.none, + returnValueForMissingStub: _i8.RequestStatus.none, + ) as _i8.RequestStatus); @override bool get hasListeners => (super.noSuchMethod( @@ -479,97 +470,64 @@ class MockSessionProvider extends _i1.Mock implements _i8.SessionProvider { ) as bool); @override - _i4.Future<_i3.Session> loadFromStorage( + _i3.Future<_i9.Session?> loadFromStorage( _i10.StateProviders? stateProviders) => (super.noSuchMethod( Invocation.method( #loadFromStorage, [stateProviders], ), - returnValue: _i4.Future<_i3.Session>.value(_FakeSession_2( - this, - Invocation.method( - #loadFromStorage, - [stateProviders], - ), - )), - returnValueForMissingStub: _i4.Future<_i3.Session>.value(_FakeSession_2( - this, - Invocation.method( - #loadFromStorage, - [stateProviders], - ), - )), - ) as _i4.Future<_i3.Session>); + returnValue: _i3.Future<_i9.Session?>.value(), + returnValueForMissingStub: _i3.Future<_i9.Session?>.value(), + ) as _i3.Future<_i9.Session?>); @override - _i4.Future<_i3.Session> loadFromRemote(_i10.StateProviders? stateProviders) => + _i3.Future<_i9.Session?> loadFromRemote( + _i10.StateProviders? stateProviders) => (super.noSuchMethod( Invocation.method( #loadFromRemote, [stateProviders], ), - returnValue: _i4.Future<_i3.Session>.value(_FakeSession_2( - this, - Invocation.method( - #loadFromRemote, - [stateProviders], - ), - )), - returnValueForMissingStub: _i4.Future<_i3.Session>.value(_FakeSession_2( - this, - Invocation.method( - #loadFromRemote, - [stateProviders], - ), - )), - ) as _i4.Future<_i3.Session>); + returnValue: _i3.Future<_i9.Session?>.value(), + returnValueForMissingStub: _i3.Future<_i9.Session?>.value(), + ) as _i3.Future<_i9.Session?>); @override - _i4.Future postAuthentication( - String? username, - String? password, { + _i3.Future login( + _i11.SessionRequest? request, { required bool? persistentSession, }) => (super.noSuchMethod( Invocation.method( - #postAuthentication, - [ - username, - password, - ], + #login, + [request], {#persistentSession: persistentSession}, ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); @override - _i4.Future federatedAuthentication( - {required bool? persistentSession}) => + _i3.Future federatedAuthentication({ + required _i3.Future? onAuthentication, + required bool? persistentSession, + }) => (super.noSuchMethod( Invocation.method( #federatedAuthentication, [], - {#persistentSession: persistentSession}, - ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); - - @override - _i4.Future finishFederatedAuthentication(Uri? uri) => - (super.noSuchMethod( - Invocation.method( - #finishFederatedAuthentication, - [uri], + { + #onAuthentication: onAuthentication, + #persistentSession: persistentSession, + }, ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); @override - void setState(_i3.Session? newState) => super.noSuchMethod( + void setState(_i9.Session? newState) => super.noSuchMethod( Invocation.method( #setState, [newState], @@ -587,29 +545,29 @@ class MockSessionProvider extends _i1.Mock implements _i8.SessionProvider { ); @override - _i4.Future forceRefresh(_i11.BuildContext? context) => + _i3.Future forceRefresh(_i12.BuildContext? context) => (super.noSuchMethod( Invocation.method( #forceRefresh, [context], ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); @override - _i4.Future ensureInitialized(_i11.BuildContext? context) => + _i3.Future ensureInitialized(_i12.BuildContext? context) => (super.noSuchMethod( Invocation.method( #ensureInitialized, [context], ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); @override - void addListener(_i12.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i13.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -618,7 +576,7 @@ class MockSessionProvider extends _i1.Mock implements _i8.SessionProvider { ); @override - void removeListener(_i12.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i13.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], diff --git a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart index 80287bc39..704a44fa9 100644 --- a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart +++ b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart @@ -14,7 +14,7 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart' as _i3; 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; +import 'package:uni/controller/session/session.dart' as _i6; import 'package:uni/model/utils/time/week.dart' as _i8; // ignore_for_file: type=lint diff --git a/packages/uni_app/test/unit/providers/exams_provider_test.dart b/packages/uni_app/test/unit/providers/exams_provider_test.dart index cd4ebf8e3..b4146f36e 100644 --- a/packages/uni_app/test/unit/providers/exams_provider_test.dart +++ b/packages/uni_app/test/unit/providers/exams_provider_test.dart @@ -4,11 +4,11 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; +import 'package:uni/controller/session/session.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'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/request_status.dart'; diff --git a/packages/uni_app/test/unit/providers/lecture_provider_test.dart b/packages/uni_app/test/unit/providers/lecture_provider_test.dart index b01445938..f0fc74e15 100644 --- a/packages/uni_app/test/unit/providers/lecture_provider_test.dart +++ b/packages/uni_app/test/unit/providers/lecture_provider_test.dart @@ -4,10 +4,10 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; diff --git a/uni/lib/controller/session/credentials/request.dart b/uni/lib/controller/session/credentials/request.dart index bcbc63f48..f3b9595a1 100644 --- a/uni/lib/controller/session/credentials/request.dart +++ b/uni/lib/controller/session/credentials/request.dart @@ -15,22 +15,13 @@ class CredentialsSessionRequest extends SessionRequest { required this.password, }); - // Serialization logic - - factory CredentialsSessionRequest.fromJson(Map json) => - _$CredentialsSessionRequestFromJson(json); - - @override - Map toJson() => _$CredentialsSessionRequestToJson(this); - - // Request implementation - final String username; final String password; @override Future perform() async { // We need to login to fetch the faculties, so perform a temporary login. + final tempSession = await NetworkRouter.login( username, password, diff --git a/uni/lib/controller/session/credentials/session.dart b/uni/lib/controller/session/credentials/session.dart index 22d898b11..3bf3e0dd0 100644 --- a/uni/lib/controller/session/credentials/session.dart +++ b/uni/lib/controller/session/credentials/session.dart @@ -1,6 +1,10 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:uni/controller/session/credentials/request.dart'; import 'package:uni/controller/session/session.dart'; +part '../../../generated/controller/session/credentials/session.g.dart'; + +@JsonSerializable(explicitToJson: true) class CredentialsSession extends Session { CredentialsSession({ required super.username, @@ -9,6 +13,16 @@ class CredentialsSession extends Session { required this.password, }); + // Serialization logic + + factory CredentialsSession.fromJson(Map json) => + _$CredentialsSessionFromJson(json); + + @override + Map toJson() => _$CredentialsSessionToJson(this); + + // Session implementation + final String password; @override diff --git a/uni/lib/controller/session/federated/request.dart b/uni/lib/controller/session/federated/request.dart index e5b4d695d..848ec0703 100644 --- a/uni/lib/controller/session/federated/request.dart +++ b/uni/lib/controller/session/federated/request.dart @@ -1,30 +1,16 @@ import 'dart:convert'; -import 'package:json_annotation/json_annotation.dart'; import 'package:logger/logger.dart'; import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/session/federated/session.dart'; import 'package:uni/controller/session/request.dart'; -part '../../../generated/controller/session/federated/request.g.dart'; - -@JsonSerializable(explicitToJson: true) class FederatedSessionRequest extends SessionRequest { FederatedSessionRequest({ required this.credential, }); - // Serialization logic - - factory FederatedSessionRequest.fromJson(Map json) => - _$FederatedSessionRequestFromJson(json); - - @override - Map toJson() => _$FederatedSessionRequestToJson(this); - - // Request implementation - final Credential credential; Future _getUsername() async { diff --git a/uni/lib/controller/session/federated/session.dart b/uni/lib/controller/session/federated/session.dart index e98802f8f..01498a23d 100644 --- a/uni/lib/controller/session/federated/session.dart +++ b/uni/lib/controller/session/federated/session.dart @@ -1,7 +1,12 @@ +import 'package:json_annotation/json_annotation.dart'; import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/session/federated/request.dart'; import 'package:uni/controller/session/session.dart'; +import 'package:url_launcher/url_launcher.dart'; +part '../../../generated/controller/session/federated/session.g.dart'; + +@JsonSerializable(explicitToJson: true) class FederatedSession extends Session { FederatedSession({ required super.username, @@ -10,10 +15,33 @@ class FederatedSession extends Session { required this.credential, }); + // Serialization logic + + factory FederatedSession.fromJson(Map json) => + _$FederatedSessionFromJson(json); + + @override + Map toJson() => _$FederatedSessionToJson(this); + final Credential credential; @override FederatedSessionRequest createRefreshRequest() => FederatedSessionRequest( credential: credential, ); + + @override + Future onClose() async { + await super.onClose(); + + final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); + final logoutUri = credential.generateLogoutUrl(redirectUri: homeUri); + + if (logoutUri == null) { + throw Exception('Failed to generate logout url'); + } + + await launchUrl(logoutUri); + // await openUrl(logoutUri); + } } diff --git a/uni/lib/controller/session/request.dart b/uni/lib/controller/session/request.dart index f3a8c4be9..3108b935e 100644 --- a/uni/lib/controller/session/request.dart +++ b/uni/lib/controller/session/request.dart @@ -1,30 +1,5 @@ -import 'package:uni/controller/session/credentials/request.dart'; -import 'package:uni/controller/session/federated/request.dart'; import 'package:uni/controller/session/session.dart'; -const _requestsFromJson = [ - FederatedSessionRequest.fromJson, - CredentialsSessionRequest.fromJson, -]; - abstract class SessionRequest { - // Serialization logic - - static SessionRequest fromJson(Map json) { - for (final fromJson in _requestsFromJson) { - try { - return fromJson(json); - } catch (err) { - // ignore - } - } - - throw Exception('Unknown session request type'); - } - - Map toJson(); - - // Request implementation - Future perform(); } diff --git a/uni/lib/controller/session/session.dart b/uni/lib/controller/session/session.dart index 8fa974452..6781ba119 100644 --- a/uni/lib/controller/session/session.dart +++ b/uni/lib/controller/session/session.dart @@ -1,7 +1,16 @@ import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/controller/session/credentials/session.dart'; +import 'package:uni/controller/session/federated/session.dart'; import 'package:uni/controller/session/request.dart'; +const _sessionsFromJson = [ + FederatedSession.fromJson, + CredentialsSession.fromJson, +]; + abstract class Session { Session({ required this.username, @@ -9,9 +18,41 @@ abstract class Session { required this.faculties, }) : assert(faculties.isNotEmpty, 'session must have faculties'); + // Serialization logic + + static Session? fromJson(Map json) { + for (final fromJson in _sessionsFromJson) { + try { + return fromJson(json); + } catch (err) { + // ignore + } + } + + return null; + } + + Map toJson(); + + // Session implementation + final String username; final List faculties; + @CookieConverter() final List cookies; // TODO(limwa): use a CookieJar SessionRequest createRefreshRequest(); + + @mustCallSuper + Future onClose() async {} +} + +class CookieConverter implements JsonConverter { + const CookieConverter(); + + @override + Cookie fromJson(String json) => Cookie.fromSetCookieValue(json); + + @override + String toJson(Cookie object) => object.toString(); } diff --git a/uni/lib/generated/controller/session/credentials/session.g.dart b/uni/lib/generated/controller/session/credentials/session.g.dart new file mode 100644 index 000000000..d45b963a8 --- /dev/null +++ b/uni/lib/generated/controller/session/credentials/session.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/credentials/session.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CredentialsSession _$CredentialsSessionFromJson(Map json) => + CredentialsSession( + username: json['username'] as String, + cookies: (json['cookies'] as List) + .map((e) => const CookieConverter().fromJson(e as String)) + .toList(), + faculties: + (json['faculties'] as List).map((e) => e as String).toList(), + password: json['password'] as String, + ); + +Map _$CredentialsSessionToJson(CredentialsSession instance) => + { + 'username': instance.username, + 'faculties': instance.faculties, + 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), + 'password': instance.password, + }; diff --git a/uni/lib/generated/controller/session/federated/request.g.dart b/uni/lib/generated/controller/session/federated/request.g.dart deleted file mode 100644 index 200fcc1e8..000000000 --- a/uni/lib/generated/controller/session/federated/request.g.dart +++ /dev/null @@ -1,20 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../../../../controller/session/federated/request.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -FederatedSessionRequest _$FederatedSessionRequestFromJson( - Map json) => - FederatedSessionRequest( - credential: - Credential.fromJson(json['credential'] as Map), - ); - -Map _$FederatedSessionRequestToJson( - FederatedSessionRequest instance) => - { - 'credential': instance.credential.toJson(), - }; diff --git a/uni/lib/generated/controller/session/federated/session.g.dart b/uni/lib/generated/controller/session/federated/session.g.dart new file mode 100644 index 000000000..301338309 --- /dev/null +++ b/uni/lib/generated/controller/session/federated/session.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../controller/session/federated/session.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FederatedSession _$FederatedSessionFromJson(Map json) => + FederatedSession( + username: json['username'] as String, + cookies: (json['cookies'] as List) + .map((e) => const CookieConverter().fromJson(e as String)) + .toList(), + faculties: + (json['faculties'] as List).map((e) => e as String).toList(), + credential: + Credential.fromJson(json['credential'] as Map), + ); + +Map _$FederatedSessionToJson(FederatedSession instance) => + { + 'username': instance.username, + 'faculties': instance.faculties, + 'cookies': instance.cookies.map(const CookieConverter().toJson).toList(), + 'credential': instance.credential.toJson(), + }; From e7b177e9f753709f6a4cc596c92d67bbb1617807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Tue, 30 Jul 2024 18:50:21 +0100 Subject: [PATCH 12/99] refactor: add NetworkRouter.login method again --- .../controller/networking/network_router.dart | 35 ++++++++++++++++++- .../session/credentials/request.dart | 8 +---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index f5ab48145..addced8b5 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -5,8 +5,8 @@ import 'dart:io'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; import 'package:logger/logger.dart'; -import 'package:openid_client/openid_client.dart'; import 'package:synchronized/synchronized.dart'; +import 'package:uni/controller/session/credentials/session.dart'; import 'package:uni/controller/session/session.dart'; import 'package:uni/utils/constants.dart'; import 'package:uni/view/navigation_service.dart'; @@ -50,6 +50,39 @@ class NetworkRouter { } } + static Future login(String username, String password) async { + final url = '${getBaseUrl('feup')}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; + } + + final responseBody = json.decode(response.body) as Map; + if (!(responseBody['authenticated'] as bool)) { + Logger().e('Login failed: user not authenticated'); + return null; + } + + final realUsername = responseBody['codigo'] as String; + final session = CredentialsSession( + username: realUsername, + cookies: extractCookies(response), + faculties: faculties, + password: password, + ); + + Logger().i('Login successful'); + _lastLoginTime = DateTime.now(); + _cachedSession = session; + + return session; + } + /// Returns the response body of the login in Sigarra /// given username [user] and password [pass]. static Future loginInSigarra( diff --git a/uni/lib/controller/session/credentials/request.dart b/uni/lib/controller/session/credentials/request.dart index f3b9595a1..48f1a9d26 100644 --- a/uni/lib/controller/session/credentials/request.dart +++ b/uni/lib/controller/session/credentials/request.dart @@ -22,13 +22,7 @@ class CredentialsSessionRequest extends SessionRequest { Future perform() async { // We need to login to fetch the faculties, so perform a temporary login. - final tempSession = await NetworkRouter.login( - username, - password, - ['feup'], - persistentSession: false, - ignoreCached: true, - ); + final tempSession = await NetworkRouter.login(username, password); if (tempSession == null) { // Get the fail reason. From cf66e05cd2003191b9dfad96d3594f613b509ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 7 Aug 2024 23:18:05 +0100 Subject: [PATCH 13/99] refactor: some more work on http rewrite --- packages/uni_app/lib/controller/cleanup.dart | 2 +- packages/uni_app/lib/utils/derived.dart | 31 ++++++ .../session/authentication_controller.dart | 40 ++++++++ .../controller/session/federated/session.dart | 5 +- uni/lib/controller/session/http.dart | 94 +++++++++++++++++++ uni/lib/controller/session/session.dart | 2 +- 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 packages/uni_app/lib/utils/derived.dart create mode 100644 uni/lib/controller/session/authentication_controller.dart create mode 100644 uni/lib/controller/session/http.dart diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index fe968b7f7..6f47e9340 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -20,7 +20,7 @@ Future cleanupStoredData(BuildContext context) async { final providers = StateProviders.fromContext(context); final session = providers.sessionProvider.state; if (session != null) { - unawaited(session.onClose()); + unawaited(session.close()); } providers.invalidate(); diff --git a/packages/uni_app/lib/utils/derived.dart b/packages/uni_app/lib/utils/derived.dart new file mode 100644 index 000000000..9e5055d4c --- /dev/null +++ b/packages/uni_app/lib/utils/derived.dart @@ -0,0 +1,31 @@ +import 'dart:async'; + +class Derived { + Derived(this._input, this.compute, {Stream? inputStream}) + : _output = compute(_input) { + if (inputStream != null) { + inputStream.listen((value) => input = value); + } + } + + final StreamController _controller = StreamController.broadcast(); + Stream get stream => _controller.stream; + + final O Function(I) compute; + I _input; + O _output; + + I get input => _input; + set input(I newValue) { + if (newValue != _input) { + _input = newValue; + _output = compute(_input); + _controller.add(_output); + } + } + + O get output => _output; + + Derived and(N Function(O) newCompute) => + Derived(_output, newCompute, inputStream: stream); +} diff --git a/uni/lib/controller/session/authentication_controller.dart b/uni/lib/controller/session/authentication_controller.dart new file mode 100644 index 000000000..68e277e3b --- /dev/null +++ b/uni/lib/controller/session/authentication_controller.dart @@ -0,0 +1,40 @@ +import 'dart:async'; + +import 'package:synchronized/synchronized.dart'; +import 'package:uni/controller/session/session.dart'; + +class AuthenticationController { + AuthenticationController(this._session); + + Session _session; + + final Lock _authenticationLock = Lock(); + Future? nextAuthentication; + + Future get session async { + final nextAuthentication = this.nextAuthentication; + if (nextAuthentication != null) { + await nextAuthentication; + } + + return _session; + } + + Future _reauthenticate() async { + final refreshRequest = _session.createRefreshRequest(); + _session = await refreshRequest.perform(); + + await _authenticationLock.synchronized(() => nextAuthentication = null); + } + + Future invalidate() async { + // This check is used to avoid unnecessary lock acquisitions + if (nextAuthentication != null) { + return; + } + + // A lock is needed for nextAuthentication because ??= is not atomic + await _authenticationLock + .synchronized(() => nextAuthentication ??= _reauthenticate()); + } +} diff --git a/uni/lib/controller/session/federated/session.dart b/uni/lib/controller/session/federated/session.dart index 01498a23d..b09660343 100644 --- a/uni/lib/controller/session/federated/session.dart +++ b/uni/lib/controller/session/federated/session.dart @@ -31,8 +31,8 @@ class FederatedSession extends Session { ); @override - Future onClose() async { - await super.onClose(); + Future close() async { + await super.close(); final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); final logoutUri = credential.generateLogoutUrl(redirectUri: homeUri); @@ -42,6 +42,5 @@ class FederatedSession extends Session { } await launchUrl(logoutUri); - // await openUrl(logoutUri); } } diff --git a/uni/lib/controller/session/http.dart b/uni/lib/controller/session/http.dart new file mode 100644 index 000000000..c46401b8b --- /dev/null +++ b/uni/lib/controller/session/http.dart @@ -0,0 +1,94 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:http/http.dart' as http; +import 'package:http/retry.dart' show RetryClient; +import 'package:uni/controller/session/authentication_controller.dart'; + +class TimeoutClient extends http.BaseClient { + TimeoutClient(http.Client inner, {required Duration timeout}) + : _inner = inner, + _timeout = timeout; + + final http.Client _inner; + final Duration _timeout; + + @override + Future send(http.BaseRequest request) => + _inner.send(request).timeout(_timeout); + + @override + void close() => _inner.close(); +} + +class CookieClient extends http.BaseClient { + CookieClient( + this._inner, { + required FutureOr> Function() getCookies, + }) : _getCookies = getCookies; + + final http.Client _inner; + final FutureOr> Function() _getCookies; + + @override + Future send(http.BaseRequest request) async { + final sessionCookies = await _getCookies(); + + final initialCookies = request.headers[HttpHeaders.cookieHeader]; + final allCookies = [ + if (initialCookies != null) initialCookies, + ...sessionCookies.map((cookie) => cookie.toString()), + ].join('; '); + + request.headers[HttpHeaders.cookieHeader] = allCookies; + return _inner.send(request); + } + + @override + void close() => _inner.close(); +} + +class UniClient extends http.BaseClient { + UniClient(http.Client inner, + {required AuthenticationController authenticationController}) + : _authenticationController = authenticationController { + _inner = _createInnerClient(inner); + } + + static const Duration _timeout = Duration(seconds: 30); + late final http.Client _inner; + + final AuthenticationController _authenticationController; + + http.Client _createInnerClient(http.Client inner) => RetryClient.withDelays( + CookieClient( + TimeoutClient(inner, timeout: _timeout), + getCookies: () => _authenticationController.session + .then((session) => session.cookies), + ), + [Duration.zero], + when: (response) => response.statusCode == 403, + onRetry: (request, response, attempt) => + _authenticationController.invalidate(), + ); + + @override + Future send(http.BaseRequest request) async { + final response = await _inner.send(request).timeout(_timeout); + if (response.statusCode == 200) { + return response; + } + + // TODO(limwa): check if the condition is correct + if (response.statusCode == 403) { + // kill the session aka ulogout the user from the app + final session = await _authenticationController.session; + await session.close(); + } + + return Future.error('HTTP Error: ${response.statusCode}'); + } + + @override + void close() => _inner.close(); +} diff --git a/uni/lib/controller/session/session.dart b/uni/lib/controller/session/session.dart index 6781ba119..e0aab5e5f 100644 --- a/uni/lib/controller/session/session.dart +++ b/uni/lib/controller/session/session.dart @@ -44,7 +44,7 @@ abstract class Session { SessionRequest createRefreshRequest(); @mustCallSuper - Future onClose() async {} + Future close() async {} } class CookieConverter implements JsonConverter { From 8a3f24153c687e85658d2df94ff6c86b08d698d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 21 Aug 2024 18:36:17 +0100 Subject: [PATCH 14/99] refactor: continue refactor --- .../background_workers/notifications.dart | 2 +- .../notifications/tuition_notification.dart | 2 +- .../fetchers/calendar_fetcher_html.dart | 2 +- .../all_course_units_fetcher.dart | 2 +- .../course_units_info_fetcher.dart | 2 +- .../current_course_units_fetcher.dart | 2 +- .../controller/fetchers/courses_fetcher.dart | 2 +- .../lib/controller/fetchers/exam_fetcher.dart | 2 +- .../fetchers/faculties_fetcher.dart | 2 +- .../lib/controller/fetchers/fees_fetcher.dart | 2 +- .../fetchers/library_occupation_fetcher.dart | 2 +- .../controller/fetchers/print_fetcher.dart | 2 +- .../controller/fetchers/profile_fetcher.dart | 2 +- .../fetchers/reference_fetcher.dart | 2 +- .../fetchers/restaurant_fetcher.dart | 2 +- .../schedule_fetcher/schedule_fetcher.dart | 2 +- .../schedule_fetcher_api.dart | 2 +- .../schedule_fetcher_html.dart | 2 +- .../fetchers/session_dependant_fetcher.dart | 2 +- .../local_storage/file_offline_storage.dart | 2 +- .../local_storage/preferences_controller.dart | 10 +- .../controller/networking/network_router.dart | 138 +----------------- .../parsers/parser_course_unit_info.dart | 2 +- .../parsers/parser_schedule_html.dart | 2 +- .../uni_app/lib/model/entities/session.dart | 42 ------ .../lazy/course_units_info_provider.dart | 2 +- .../model/providers/lazy/exam_provider.dart | 2 +- .../providers/lazy/lecture_provider.dart | 2 +- .../providers/startup/profile_provider.dart | 2 +- .../providers/startup/session_provider.dart | 6 +- .../lib/view/bug_report/widgets/form.dart | 5 +- .../view/common_widgets/faculty_filter.dart | 2 +- .../widgets/course_unit_student_row.dart | 2 +- packages/uni_app/lib/view/login/login.dart | 2 +- .../integration/src/exams2_page_test.dart | 2 +- .../test/integration/src/exams_page_test.dart | 2 +- .../integration/src/schedule_page_test.dart | 2 +- .../src/schedule_page_test.mocks.dart | 4 +- .../lecture_provider_test.mocks.dart | 2 +- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- .../session/authentication_controller.dart | 40 ----- .../controller/session/federated/request.dart | 67 --------- uni/lib/controller/session/http.dart | 94 ------------ uni/lib/controller/session/request.dart | 5 - .../session/credentials/request.g.dart | 2 +- .../session/credentials/session.g.dart | 2 +- .../session/federated/session.g.dart | 2 +- uni/lib/http/client/callback.dart | 18 +++ uni/lib/http/client/cookie.dart | 29 ++++ uni/lib/http/client/timeout.dart | 17 +++ uni/lib/http/utils.dart | 19 +++ .../session/authentication_controller.dart | 60 ++++++++ uni/lib/session/authentication_exception.dart | 5 + uni/lib/session/credentials/initiator.dart | 18 +++ .../session/credentials/request.dart | 11 +- .../session/credentials/session.dart | 20 ++- uni/lib/session/federated/initiator.dart | 44 ++++++ uni/lib/session/federated/request.dart | 51 +++++++ .../session/federated/session.dart | 26 ++-- uni/lib/session/http.dart | 77 ++++++++++ uni/lib/session/initiator.dart | 14 ++ uni/lib/session/rejection.dart | 7 + uni/lib/session/request.dart | 21 +++ uni/lib/{controller => }/session/session.dart | 12 +- uni/lib/sigarra/endpoints/api.dart | 1 + .../sigarra/endpoints/api/authentication.dart | 20 +++ .../endpoints/html/authentication.dart | 16 ++ uni/lib/sigarra/endpoints/oidc.dart | 1 + uni/lib/sigarra/endpoints/oidc/token.dart | 31 ++++ uni/lib/sigarra/options.dart | 44 ++++++ 71 files changed, 591 insertions(+), 458 deletions(-) delete mode 100644 packages/uni_app/lib/model/entities/session.dart delete mode 100644 uni/lib/controller/session/authentication_controller.dart delete mode 100644 uni/lib/controller/session/federated/request.dart delete mode 100644 uni/lib/controller/session/http.dart delete mode 100644 uni/lib/controller/session/request.dart rename uni/lib/generated/{controller => }/session/credentials/request.g.dart (90%) rename uni/lib/generated/{controller => }/session/credentials/session.g.dart (93%) rename uni/lib/generated/{controller => }/session/federated/session.g.dart (94%) create mode 100644 uni/lib/http/client/callback.dart create mode 100644 uni/lib/http/client/cookie.dart create mode 100644 uni/lib/http/client/timeout.dart create mode 100644 uni/lib/http/utils.dart create mode 100644 uni/lib/session/authentication_controller.dart create mode 100644 uni/lib/session/authentication_exception.dart create mode 100644 uni/lib/session/credentials/initiator.dart rename uni/lib/{controller => }/session/credentials/request.dart (81%) rename uni/lib/{controller => }/session/credentials/session.dart (56%) create mode 100644 uni/lib/session/federated/initiator.dart create mode 100644 uni/lib/session/federated/request.dart rename uni/lib/{controller => }/session/federated/session.dart (59%) create mode 100644 uni/lib/session/http.dart create mode 100644 uni/lib/session/initiator.dart create mode 100644 uni/lib/session/rejection.dart create mode 100644 uni/lib/session/request.dart rename uni/lib/{controller => }/session/session.dart (80%) create mode 100644 uni/lib/sigarra/endpoints/api.dart create mode 100644 uni/lib/sigarra/endpoints/api/authentication.dart create mode 100644 uni/lib/sigarra/endpoints/html/authentication.dart create mode 100644 uni/lib/sigarra/endpoints/oidc.dart create mode 100644 uni/lib/sigarra/endpoints/oidc/token.dart create mode 100644 uni/lib/sigarra/options.dart diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index 6bc40b4f2..49e2bda36 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -10,7 +10,7 @@ import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; import 'package:uni/controller/local_storage/notification_timeout_storage.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:workmanager/workmanager.dart'; /// diff --git a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart index 6785b2fb4..16a461625 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/fees_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/utils/duration_string_formatter.dart'; class TuitionNotification extends Notification { diff --git a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart index 853f1ff1a..f9565c9ca 100644 --- a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_calendar.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/calendar_event.dart'; /// Fetch the school calendar from HTML diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index e59d72f14..03c1245cc 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -1,6 +1,6 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_units.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart index 3b3232b51..73abb394c 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart @@ -2,7 +2,7 @@ import 'package:html/parser.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_unit_info.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart index ee69589ac..487b1de44 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; class CurrentCourseUnitsFetcher implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart index 65a13ada3..b6ad394b5 100644 --- a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; /// Returns the user's current list of [CourseUnit]. diff --git a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart index c8fb12efd..c3a6828be 100644 --- a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.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'; diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index febcd1844..b2dbd474f 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -1,6 +1,6 @@ import 'package:html/parser.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; Future> getStudentFaculties(Session session) async { final response = await NetworkRouter.getWithCookies( diff --git a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart index a14436c7e..eb1f5200c 100644 --- a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; class FeesFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 01ecf8019..a12c913be 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_library_occupation.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/library_occupation.dart'; /// Fetch the library occupation from Google Sheets diff --git a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart index 47c26b067..85d93d278 100644 --- a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; class PrintFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart index 8438285e9..72ef27f05 100644 --- a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart @@ -2,7 +2,7 @@ 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'; import 'package:uni/controller/parsers/parser_courses.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/profile.dart'; class ProfileFetcher implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart index 0d7a89ad3..b5a4ad3d9 100644 --- a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; class ReferenceFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart index 8c427265f..3f01421ed 100644 --- a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart @@ -1,6 +1,6 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_restaurants.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/restaurant.dart'; /// Class for fetching the menu diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index 7c4428d16..3bb01de54 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -1,5 +1,5 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index 270762fd4..3b31ac682 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -2,7 +2,7 @@ import 'package:http/http.dart' as http; 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.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index b72389558..01833ce53 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -3,7 +3,7 @@ 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'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; diff --git a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart index 9dfddb261..5c2d1f317 100644 --- a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart @@ -1,4 +1,4 @@ -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; abstract class SessionDependantFetcher { List getEndpoints(Session session); diff --git a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart index 602177675..2e3da04ad 100644 --- a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart +++ b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart @@ -6,7 +6,7 @@ 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/controller/session/session.dart'; +import 'package:uni/session/session.dart'; /// The offline image storage location on the device. Future get _localPath async { diff --git a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart index d5d3e4b59..054f1a994 100644 --- a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart +++ b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/utils/favorite_widget_type.dart'; @@ -71,7 +71,9 @@ class PreferencesController { Session session, ) async { await _secureStorage.write( - key: _userSession, value: jsonEncode(session.toJson())); + key: _userSession, + value: jsonEncode(session.toJson()), + ); } static Future getSavedSession() async { @@ -84,6 +86,10 @@ class PreferencesController { return Session.fromJson(json); } + static Future isSessionPersistent() async { + return _secureStorage.containsKey(key: _userSession); + } + /// Sets whether or not the Terms and Conditions have been accepted. static Future setTermsAndConditionsAcceptance({ required bool areAccepted, diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index addced8b5..ca419d4d6 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -6,8 +6,8 @@ import 'package:http/http.dart' as http; import 'package:http/http.dart'; import 'package:logger/logger.dart'; import 'package:synchronized/synchronized.dart'; -import 'package:uni/controller/session/credentials/session.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/utils/constants.dart'; import 'package:uni/view/navigation_service.dart'; @@ -26,17 +26,6 @@ class NetworkRouter { /// The timeout for Sigarra login requests. static const Duration _requestTimeout = Duration(seconds: 30); - /// 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; - /// Re-authenticates the user via the Sigarra API /// using data stored in [session], /// returning an updated Session if successful. @@ -99,114 +88,6 @@ class NetworkRouter { return response.body; } - /// Extracts the cookies present in [response]. - static List extractCookies(http.Response response) { - final setCookieHeaders = - response.headersSplitValues[HttpHeaders.setCookieHeader]; - if (setCookieHeaders == null) { - return []; - } - - final cookies = []; - for (final value in setCookieHeaders) { - cookies.add(Cookie.fromSetCookieValue(value)); - } - - return cookies; - } - - /// Makes an authenticated GET request with the given [session] to the - /// resource located at [baseUrl] with the given [query] parameters. - /// If the request fails with a 403 status code, the user is re-authenticated - /// and the session is updated. - static Future getWithCookies( - String baseUrl, - Map query, - Session session, { - Duration timeout = _requestTimeout, - }) async { - var url = baseUrl; - if (!url.contains('?')) { - url += '?'; - } - query.forEach((key, value) { - url += '$key=$value&'; - }); - if (query.isNotEmpty) { - url = url.substring(0, url.length - 1); - } - - final headers = {}; - headers['cookie'] = session.cookies.join('; '); - - final response = await (httpClient != null - ? httpClient!.get(url.toUri(), headers: headers).timeout(timeout) - : http.get(url.toUri(), headers: headers)) - .timeout(timeout); - - if (response.statusCode == 200) { - return response; - } - - final forbidden = response.statusCode == 403; - if (forbidden) { - 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) { - NavigationService.logoutAndPopHistory(); - return Future.error( - 'Re-login failed; user might have changed password', - ); - } - - session - ..username = newSession.username // (thePeras): Why is this necessary? - ..cookies = - newSession.cookies; // TODO(limwa): because it is very bad code xD - - headers['cookie'] = session.cookies.join('; '); - return http.get(url.toUri(), headers: headers).timeout(timeout); - } else { - // If the user is logged in but still got a 403, they are - // forbidden to access the resource or the login was invalid - // at the time of the request, - // but other thread re-authenticated. - // Since we do not know which one is the case, we try again. - headers['cookie'] = session.cookies.join('; '); - final response = - await http.get(url.toUri(), headers: headers).timeout(timeout); - return response.statusCode == 200 - ? Future.value(response) - : Future.error('HTTP Error: ${response.statusCode}'); - } - } - - return Future.error('HTTP Error: ${response.statusCode}'); - } - - /// Check if the user is still logged in, - /// performing a health check on the user's personal page. - static Future userLoggedIn(Session session) async { - 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.join('; '); - - final response = await (httpClient != null - ? httpClient!.get(url.toUri(), headers: headers) - : http.get(url.toUri(), headers: headers)); - - return response.statusCode == 200; - } - /// Returns the base url of the user's faculties. static List getBaseUrls(List faculties) { return faculties.map(getBaseUrl).toList(); @@ -221,19 +102,4 @@ class NetworkRouter { static List getBaseUrlsFromSession(Session session) { return NetworkRouter.getBaseUrls(session.faculties); } - - /// Makes an HTTP request to terminate the session in Sigarra. - static Future killSigarraAuthentication( - List faculties) async { - 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'); - } - - return response; - } } diff --git a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart index aceb39afc..c0a99bc41 100644 --- a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart +++ b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:html/parser.dart'; import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_file.dart'; diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart index 70c7967f0..ad3b4e354 100644 --- a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart +++ b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart @@ -4,7 +4,7 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/model/utils/time/weekday_mapper.dart'; diff --git a/packages/uni_app/lib/model/entities/session.dart b/packages/uni_app/lib/model/entities/session.dart deleted file mode 100644 index 27a51ddd3..000000000 --- a/packages/uni_app/lib/model/entities/session.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:http/http.dart' as http; -import 'package:uni/controller/networking/network_router.dart'; - -/// Stores information about a user session. -class Session { - Session({ - required this.username, - required this.cookies, - required this.faculties, - this.persistentSession = false, - this.federatedSession = false, - }) : assert(faculties.isNotEmpty, 'session must have faculties'); - - String username; - List cookies; - List faculties; - bool persistentSession; - bool federatedSession; - - /// Creates a new Session instance from an HTTP response. - /// Returns null if the authentication failed. - static Session? fromLogin( - http.Response response, - List faculties, { - required bool persistentSession, - }) { - final responseBody = json.decode(response.body) as Map; - - if (!(responseBody['authenticated'] as bool)) { - return null; - } - - return Session( - faculties: faculties, - username: responseBody['codigo'] as String, - cookies: NetworkRouter.extractCookies(response), - ); - } -} diff --git a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart index 53d3e3de2..3432e75df 100644 --- a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart @@ -2,7 +2,7 @@ import 'dart:collection'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; diff --git a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart index 2b2074a34..9dd0287e7 100644 --- a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:uni/controller/fetchers/exam_fetcher.dart'; import 'package:uni/controller/local_storage/database/app_exams_database.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index 78eeca70c..c8abc3518 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; diff --git a/packages/uni_app/lib/model/providers/startup/profile_provider.dart b/packages/uni_app/lib/model/providers/startup/profile_provider.dart index 0d6d6bbe6..622ec1631 100644 --- a/packages/uni_app/lib/model/providers/startup/profile_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/profile_provider.dart @@ -13,7 +13,7 @@ import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 3c7926e55..a5ddf2b2e 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -5,9 +5,9 @@ import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/controller/session/federated/request.dart'; -import 'package:uni/controller/session/request.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/federated/request.dart'; +import 'package:uni/session/request.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; diff --git a/packages/uni_app/lib/view/bug_report/widgets/form.dart b/packages/uni_app/lib/view/bug_report/widgets/form.dart index fe313db9b..10bcc9b0a 100644 --- a/packages/uni_app/lib/view/bug_report/widgets/form.dart +++ b/packages/uni_app/lib/view/bug_report/widgets/form.dart @@ -245,7 +245,10 @@ class BugReportFormState extends State { setState(() { _isButtonTapped = true; }); - final faculties = PreferencesController.getUserFaculties(); + final savedSession = await PreferencesController.getSavedSession(); + final faculties = savedSession?.faculties ?? + []; // FIXME: get session from provider so that even non-persisted sessions can be used + final bugReport = BugReport( titleController.text, descriptionController.text, diff --git a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart index 6b01b1bce..e1eb8b5bf 100644 --- a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart +++ b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; class FacultyFilter extends StatelessWidget { const FacultyFilter({ diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart index 635cfdc79..2469f1b1c 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index 56f0d25a2..a35e84421 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.dart @@ -8,7 +8,7 @@ import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/controller/networking/url_launcher.dart'; -import 'package:uni/controller/session/credentials/request.dart'; +import 'package:uni/session/credentials/request.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; diff --git a/packages/uni_app/test/integration/src/exams2_page_test.dart b/packages/uni_app/test/integration/src/exams2_page_test.dart index b0497620a..e7aaf4593 100644 --- a/packages/uni_app/test/integration/src/exams2_page_test.dart +++ b/packages/uni_app/test/integration/src/exams2_page_test.dart @@ -9,7 +9,7 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.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'; diff --git a/packages/uni_app/test/integration/src/exams_page_test.dart b/packages/uni_app/test/integration/src/exams_page_test.dart index cf97b24cc..dd092cd1d 100644 --- a/packages/uni_app/test/integration/src/exams_page_test.dart +++ b/packages/uni_app/test/integration/src/exams_page_test.dart @@ -8,7 +8,7 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.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'; diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart index bc39d1ee0..adb99a3b9 100644 --- a/packages/uni_app/test/integration/src/schedule_page_test.dart +++ b/packages/uni_app/test/integration/src/schedule_page_test.dart @@ -8,7 +8,7 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; diff --git a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart index 7512f7751..4166b8def 100644 --- a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart +++ b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -12,11 +12,11 @@ import 'package:flutter/material.dart' as _i12; import 'package:http/http.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i5; -import 'package:uni/controller/session/request.dart' as _i11; -import 'package:uni/controller/session/session.dart' as _i9; import 'package:uni/model/providers/startup/session_provider.dart' as _i7; import 'package:uni/model/providers/state_providers.dart' as _i10; import 'package:uni/model/request_status.dart' as _i8; +import 'package:uni/session/request.dart' as _i11; +import 'package:uni/session/session.dart' as _i9; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values diff --git a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart index 704a44fa9..32fb701a4 100644 --- a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart +++ b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart @@ -14,8 +14,8 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart' as _i3; import 'package:uni/model/entities/lecture.dart' as _i5; import 'package:uni/model/entities/profile.dart' as _i7; -import 'package:uni/controller/session/session.dart' as _i6; import 'package:uni/model/utils/time/week.dart' as _i8; +import 'package:uni/session/session.dart' as _i6; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values diff --git a/packages/uni_app/test/unit/providers/exams_provider_test.dart b/packages/uni_app/test/unit/providers/exams_provider_test.dart index b4146f36e..2205ff8b9 100644 --- a/packages/uni_app/test/unit/providers/exams_provider_test.dart +++ b/packages/uni_app/test/unit/providers/exams_provider_test.dart @@ -4,7 +4,7 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.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'; diff --git a/packages/uni_app/test/unit/providers/lecture_provider_test.dart b/packages/uni_app/test/unit/providers/lecture_provider_test.dart index f0fc74e15..0859f164b 100644 --- a/packages/uni_app/test/unit/providers/lecture_provider_test.dart +++ b/packages/uni_app/test/unit/providers/lecture_provider_test.dart @@ -4,7 +4,7 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; diff --git a/uni/lib/controller/session/authentication_controller.dart b/uni/lib/controller/session/authentication_controller.dart deleted file mode 100644 index 68e277e3b..000000000 --- a/uni/lib/controller/session/authentication_controller.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:async'; - -import 'package:synchronized/synchronized.dart'; -import 'package:uni/controller/session/session.dart'; - -class AuthenticationController { - AuthenticationController(this._session); - - Session _session; - - final Lock _authenticationLock = Lock(); - Future? nextAuthentication; - - Future get session async { - final nextAuthentication = this.nextAuthentication; - if (nextAuthentication != null) { - await nextAuthentication; - } - - return _session; - } - - Future _reauthenticate() async { - final refreshRequest = _session.createRefreshRequest(); - _session = await refreshRequest.perform(); - - await _authenticationLock.synchronized(() => nextAuthentication = null); - } - - Future invalidate() async { - // This check is used to avoid unnecessary lock acquisitions - if (nextAuthentication != null) { - return; - } - - // A lock is needed for nextAuthentication because ??= is not atomic - await _authenticationLock - .synchronized(() => nextAuthentication ??= _reauthenticate()); - } -} diff --git a/uni/lib/controller/session/federated/request.dart b/uni/lib/controller/session/federated/request.dart deleted file mode 100644 index 848ec0703..000000000 --- a/uni/lib/controller/session/federated/request.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'dart:convert'; - -import 'package:logger/logger.dart'; -import 'package:openid_client/openid_client.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/session/federated/session.dart'; -import 'package:uni/controller/session/request.dart'; - -class FederatedSessionRequest extends SessionRequest { - FederatedSessionRequest({ - required this.credential, - }); - - final Credential credential; - - Future _getUsername() async { - final userInfo = await credential.getUserInfo(); - return userInfo.getTyped('nmec')!; - } - - Future> _getFaculties() async { - final userInfo = await credential.getUserInfo(); - final faculties = userInfo - .getTyped>('ous')! - .cast() - .map((element) => element.toLowerCase()) - .toList(); - - return faculties; - } - - @override - Future perform() async { - final authorizedClient = credential.createHttpClient(); - - final sigarraTokenEndpoint = - Uri.parse('https://sigarra.up.pt/auth/oidc/token'); - - final response = await authorizedClient.get( - sigarraTokenEndpoint, - headers: { - 'Content-Type': 'application/json', - }, - ); - - if (response.statusCode != 200) { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - // TODO (limwa): Is checking the result necessary? - final body = jsonDecode(response.body) as Map; - if (body['result'] != 'OK') { - Logger().e('Failed to get token from SIGARRA'); - throw Exception('Failed to get token from SIGARRA'); - } - - final cookies = NetworkRouter.extractCookies(response); - - return FederatedSession( - username: await _getUsername(), - faculties: await _getFaculties(), - cookies: cookies, - credential: credential, - ); - } -} diff --git a/uni/lib/controller/session/http.dart b/uni/lib/controller/session/http.dart deleted file mode 100644 index c46401b8b..000000000 --- a/uni/lib/controller/session/http.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:http/http.dart' as http; -import 'package:http/retry.dart' show RetryClient; -import 'package:uni/controller/session/authentication_controller.dart'; - -class TimeoutClient extends http.BaseClient { - TimeoutClient(http.Client inner, {required Duration timeout}) - : _inner = inner, - _timeout = timeout; - - final http.Client _inner; - final Duration _timeout; - - @override - Future send(http.BaseRequest request) => - _inner.send(request).timeout(_timeout); - - @override - void close() => _inner.close(); -} - -class CookieClient extends http.BaseClient { - CookieClient( - this._inner, { - required FutureOr> Function() getCookies, - }) : _getCookies = getCookies; - - final http.Client _inner; - final FutureOr> Function() _getCookies; - - @override - Future send(http.BaseRequest request) async { - final sessionCookies = await _getCookies(); - - final initialCookies = request.headers[HttpHeaders.cookieHeader]; - final allCookies = [ - if (initialCookies != null) initialCookies, - ...sessionCookies.map((cookie) => cookie.toString()), - ].join('; '); - - request.headers[HttpHeaders.cookieHeader] = allCookies; - return _inner.send(request); - } - - @override - void close() => _inner.close(); -} - -class UniClient extends http.BaseClient { - UniClient(http.Client inner, - {required AuthenticationController authenticationController}) - : _authenticationController = authenticationController { - _inner = _createInnerClient(inner); - } - - static const Duration _timeout = Duration(seconds: 30); - late final http.Client _inner; - - final AuthenticationController _authenticationController; - - http.Client _createInnerClient(http.Client inner) => RetryClient.withDelays( - CookieClient( - TimeoutClient(inner, timeout: _timeout), - getCookies: () => _authenticationController.session - .then((session) => session.cookies), - ), - [Duration.zero], - when: (response) => response.statusCode == 403, - onRetry: (request, response, attempt) => - _authenticationController.invalidate(), - ); - - @override - Future send(http.BaseRequest request) async { - final response = await _inner.send(request).timeout(_timeout); - if (response.statusCode == 200) { - return response; - } - - // TODO(limwa): check if the condition is correct - if (response.statusCode == 403) { - // kill the session aka ulogout the user from the app - final session = await _authenticationController.session; - await session.close(); - } - - return Future.error('HTTP Error: ${response.statusCode}'); - } - - @override - void close() => _inner.close(); -} diff --git a/uni/lib/controller/session/request.dart b/uni/lib/controller/session/request.dart deleted file mode 100644 index 3108b935e..000000000 --- a/uni/lib/controller/session/request.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:uni/controller/session/session.dart'; - -abstract class SessionRequest { - Future perform(); -} diff --git a/uni/lib/generated/controller/session/credentials/request.g.dart b/uni/lib/generated/session/credentials/request.g.dart similarity index 90% rename from uni/lib/generated/controller/session/credentials/request.g.dart rename to uni/lib/generated/session/credentials/request.g.dart index c7bfabdb3..8d489640e 100644 --- a/uni/lib/generated/controller/session/credentials/request.g.dart +++ b/uni/lib/generated/session/credentials/request.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of '../../../../controller/session/credentials/request.dart'; +part of '../../../session/credentials/request.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/uni/lib/generated/controller/session/credentials/session.g.dart b/uni/lib/generated/session/credentials/session.g.dart similarity index 93% rename from uni/lib/generated/controller/session/credentials/session.g.dart rename to uni/lib/generated/session/credentials/session.g.dart index d45b963a8..f27b7036f 100644 --- a/uni/lib/generated/controller/session/credentials/session.g.dart +++ b/uni/lib/generated/session/credentials/session.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of '../../../../controller/session/credentials/session.dart'; +part of '../../../session/credentials/session.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/uni/lib/generated/controller/session/federated/session.g.dart b/uni/lib/generated/session/federated/session.g.dart similarity index 94% rename from uni/lib/generated/controller/session/federated/session.g.dart rename to uni/lib/generated/session/federated/session.g.dart index 301338309..60f67726d 100644 --- a/uni/lib/generated/controller/session/federated/session.g.dart +++ b/uni/lib/generated/session/federated/session.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of '../../../../controller/session/federated/session.dart'; +part of '../../../session/federated/session.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/uni/lib/http/client/callback.dart b/uni/lib/http/client/callback.dart new file mode 100644 index 000000000..497c892eb --- /dev/null +++ b/uni/lib/http/client/callback.dart @@ -0,0 +1,18 @@ +import 'package:http/http.dart' as http; + +class CallbackClient extends http.BaseClient { + CallbackClient(http.Client inner, + {required Future Function(http.BaseRequest) send}) + : _inner = inner, + _send = send; + + final http.Client _inner; + final Future Function(http.BaseRequest) _send; + + @override + Future send(http.BaseRequest request) => + _send(request); + + @override + void close() => _inner.close(); +} diff --git a/uni/lib/http/client/cookie.dart b/uni/lib/http/client/cookie.dart new file mode 100644 index 000000000..eae125ee2 --- /dev/null +++ b/uni/lib/http/client/cookie.dart @@ -0,0 +1,29 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:http/http.dart' as http; + +class CookieClient extends http.BaseClient { + CookieClient( + this._inner, { + required this.cookies, + }); + + final http.Client _inner; + final List cookies; + + @override + Future send(http.BaseRequest request) async { + final initialCookies = request.headers[HttpHeaders.cookieHeader]; + final allCookies = [ + if (initialCookies != null) initialCookies, + ...cookies.map((cookie) => cookie.toString()), + ].join('; '); + + request.headers[HttpHeaders.cookieHeader] = allCookies; + return _inner.send(request); + } + + @override + void close() => _inner.close(); +} diff --git a/uni/lib/http/client/timeout.dart b/uni/lib/http/client/timeout.dart new file mode 100644 index 000000000..e3e533a7d --- /dev/null +++ b/uni/lib/http/client/timeout.dart @@ -0,0 +1,17 @@ +import 'package:http/http.dart' as http; + +class TimeoutClient extends http.BaseClient { + TimeoutClient(http.Client inner, {required Duration timeout}) + : _inner = inner, + _timeout = timeout; + + final http.Client _inner; + final Duration _timeout; + + @override + Future send(http.BaseRequest request) => + _inner.send(request).timeout(_timeout); + + @override + void close() => _inner.close(); +} diff --git a/uni/lib/http/utils.dart b/uni/lib/http/utils.dart new file mode 100644 index 000000000..f8aa8bc54 --- /dev/null +++ b/uni/lib/http/utils.dart @@ -0,0 +1,19 @@ +import 'dart:io'; + +import 'package:http/http.dart' as http; + +/// Extracts the cookies present in [response]. +List extractCookies(http.Response response) { + final setCookieHeaders = + response.headersSplitValues[HttpHeaders.setCookieHeader]; + if (setCookieHeaders == null) { + return []; + } + + final cookies = []; + for (final value in setCookieHeaders) { + cookies.add(Cookie.fromSetCookieValue(value)); + } + + return cookies; +} diff --git a/uni/lib/session/authentication_controller.dart b/uni/lib/session/authentication_controller.dart new file mode 100644 index 000000000..748cc16ec --- /dev/null +++ b/uni/lib/session/authentication_controller.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:synchronized/synchronized.dart'; +import 'package:uni/session/session.dart'; + +class AuthenticationSnapshot { + AuthenticationSnapshot( + this.session, { + required void Function(AuthenticationSnapshot snapshot) onInvalidate, + }) : _onInvalidate = onInvalidate; + + final Session session; + final FutureOr Function(AuthenticationSnapshot) _onInvalidate; + + FutureOr invalidate() => _onInvalidate(this); +} + +class AuthenticationController { + AuthenticationController(this._session); + + Session _session; + + final Lock _authenticationLock = Lock(); + Future? _nextAuthentication; + + Future get snapshot async { + final nextAuthentication = _nextAuthentication; + if (nextAuthentication != null) { + await nextAuthentication; + } + + return AuthenticationSnapshot( + _session, + onInvalidate: (snapshot) => _invalidate(snapshot.session), + ); + } + + Future _reauthenticate() async { + final refreshRequest = _session.createRefreshRequest(); + _session = await refreshRequest.perform(); + + await _authenticationLock.synchronized(() => _nextAuthentication = null); + } + + Future _invalidate(Session session) async { + // This check is intentionally used twice to avoid unnecessary lock + // acquisitions. + if (_nextAuthentication != null || _session != session) { + return; + } + + await _authenticationLock.synchronized(() { + if (_nextAuthentication != null || _session != session) { + return; + } + + _nextAuthentication = _reauthenticate(); + }); + } +} diff --git a/uni/lib/session/authentication_exception.dart b/uni/lib/session/authentication_exception.dart new file mode 100644 index 000000000..654b9444d --- /dev/null +++ b/uni/lib/session/authentication_exception.dart @@ -0,0 +1,5 @@ +class AuthenticationException implements Exception { + const AuthenticationException(this.message); + + final String message; +} diff --git a/uni/lib/session/credentials/initiator.dart b/uni/lib/session/credentials/initiator.dart new file mode 100644 index 000000000..1b457917a --- /dev/null +++ b/uni/lib/session/credentials/initiator.dart @@ -0,0 +1,18 @@ +import 'package:uni/session/credentials/request.dart'; +import 'package:uni/session/initiator.dart'; + +class CredentialsSessionInitiator extends SessionInitiator { + CredentialsSessionInitiator({ + required this.username, + required this.password, + }); + + final String username; + final String password; + + @override + CredentialsSessionRequest initiate() => CredentialsSessionRequest( + username: username, + password: password, + ); +} diff --git a/uni/lib/controller/session/credentials/request.dart b/uni/lib/session/credentials/request.dart similarity index 81% rename from uni/lib/controller/session/credentials/request.dart rename to uni/lib/session/credentials/request.dart index 48f1a9d26..168b07ed4 100644 --- a/uni/lib/controller/session/credentials/request.dart +++ b/uni/lib/session/credentials/request.dart @@ -1,12 +1,13 @@ +import 'package:http/http.dart' as http; import 'package:json_annotation/json_annotation.dart'; import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; -import 'package:uni/controller/session/credentials/session.dart'; -import 'package:uni/controller/session/request.dart'; import 'package:uni/model/entities/login_exceptions.dart'; +import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/request.dart'; -part '../../../generated/controller/session/credentials/request.g.dart'; +part '../../generated/session/credentials/request.g.dart'; @JsonSerializable(explicitToJson: true) class CredentialsSessionRequest extends SessionRequest { @@ -19,9 +20,9 @@ class CredentialsSessionRequest extends SessionRequest { final String password; @override - Future perform() async { + Future perform([http.Client? client]) async { + // TODO (limwa): Use client // We need to login to fetch the faculties, so perform a temporary login. - final tempSession = await NetworkRouter.login(username, password); if (tempSession == null) { diff --git a/uni/lib/controller/session/credentials/session.dart b/uni/lib/session/credentials/session.dart similarity index 56% rename from uni/lib/controller/session/credentials/session.dart rename to uni/lib/session/credentials/session.dart index 3bf3e0dd0..a834ab764 100644 --- a/uni/lib/controller/session/credentials/session.dart +++ b/uni/lib/session/credentials/session.dart @@ -1,8 +1,8 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:uni/controller/session/credentials/request.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/credentials/request.dart'; +import 'package:uni/session/session.dart'; -part '../../../generated/controller/session/credentials/session.g.dart'; +part '../../generated/session/credentials/session.g.dart'; @JsonSerializable(explicitToJson: true) class CredentialsSession extends Session { @@ -30,4 +30,18 @@ class CredentialsSession extends Session { username: username, password: password, ); + + // @override + // Future close() async { + // await super.close(); + + // final url = '${NetworkRouter.getBaseUrl(faculties[0])}vld_validacao.sair'; + // final response = await http.get(url.toUri()); // TODO: make use of UniClient + + // if (response.statusCode == 200) { + // Logger().i('Logout Successful'); + // } else { + // Logger().i('Logout Failed'); + // } + // } } diff --git a/uni/lib/session/federated/initiator.dart b/uni/lib/session/federated/initiator.dart new file mode 100644 index 000000000..ed7e7d30c --- /dev/null +++ b/uni/lib/session/federated/initiator.dart @@ -0,0 +1,44 @@ +import 'package:openid_client/openid_client.dart'; +import 'package:uni/session/federated/request.dart'; +import 'package:uni/session/initiator.dart'; +import 'package:uni/session/request.dart'; + +class FederatedSessionInitiator extends SessionInitiator { + FederatedSessionInitiator({ + required this.realm, + required this.clientId, + required this.redirectUri, + required this.delegateAuthentication, + }); + + final Uri realm; + final String clientId; + final Uri redirectUri; + final Future Function(Flow flow) delegateAuthentication; + + @override + Future initiate() async { + final issuer = await Issuer.discover(realm); + final client = Client( + issuer, + clientId, + ); + + final flow = Flow.authorizationCodeWithPKCE( + client, + scopes: [ + 'openid', + 'profile', + 'email', + 'offline_access', + 'audience', + 'uporto_data', + ], + )..redirectUri = redirectUri; + + final uri = await delegateAuthentication(flow); + final credential = await flow.callback(uri.queryParameters); + + return FederatedSessionRequest(credential: credential); + } +} diff --git a/uni/lib/session/federated/request.dart b/uni/lib/session/federated/request.dart new file mode 100644 index 000000000..09de66c50 --- /dev/null +++ b/uni/lib/session/federated/request.dart @@ -0,0 +1,51 @@ +import 'package:http/http.dart' as http; +import 'package:openid_client/openid_client.dart'; +import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/request.dart'; +import 'package:uni/sigarra/endpoints/oidc.dart' as oidc; +import 'package:uni/sigarra/options.dart'; + +class FederatedSessionRequest extends SessionRequest { + FederatedSessionRequest({ + required this.credential, + }); + + final Credential credential; + + String _getUsername(UserInfo userInfo) { + return userInfo.getTyped('nmec')!; + } + + List _getFaculties(UserInfo userInfo) { + final faculties = userInfo + .getTyped>('ous')! + .cast() + .map((element) => element.toLowerCase()) + .toList(); + + return faculties; + } + + @override + Future perform([ + http.Client? client, + ]) async { + final userInfo = await credential.getUserInfo(); + final username = _getUsername(userInfo); + final faculties = _getFaculties(userInfo); + + final authorizedClient = credential.createHttpClient(client); + final cookies = await oidc.getCookies( + options: BaseRequestOptions( + client: authorizedClient, + ), + ); + + return FederatedSession( + username: username, + cookies: cookies, + faculties: faculties, + credential: credential, + ); + } +} diff --git a/uni/lib/controller/session/federated/session.dart b/uni/lib/session/federated/session.dart similarity index 59% rename from uni/lib/controller/session/federated/session.dart rename to uni/lib/session/federated/session.dart index b09660343..f3e78a4cb 100644 --- a/uni/lib/controller/session/federated/session.dart +++ b/uni/lib/session/federated/session.dart @@ -1,10 +1,10 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:openid_client/openid_client.dart'; -import 'package:uni/controller/session/federated/request.dart'; -import 'package:uni/controller/session/session.dart'; +import 'package:uni/session/federated/request.dart'; +import 'package:uni/session/session.dart'; import 'package:url_launcher/url_launcher.dart'; -part '../../../generated/controller/session/federated/session.g.dart'; +part '../../generated/session/federated/session.g.dart'; @JsonSerializable(explicitToJson: true) class FederatedSession extends Session { @@ -30,17 +30,17 @@ class FederatedSession extends Session { credential: credential, ); - @override - Future close() async { - await super.close(); + // @override + // Future close() async { + // await super.close(); - final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); - final logoutUri = credential.generateLogoutUrl(redirectUri: homeUri); + // final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); + // final logoutUri = credential.generateLogoutUrl(redirectUri: homeUri); - if (logoutUri == null) { - throw Exception('Failed to generate logout url'); - } + // if (logoutUri == null) { + // throw Exception('Failed to generate logout url'); + // } - await launchUrl(logoutUri); - } + // await launchUrl(logoutUri); + // } } diff --git a/uni/lib/session/http.dart b/uni/lib/session/http.dart new file mode 100644 index 000000000..0104c1ba7 --- /dev/null +++ b/uni/lib/session/http.dart @@ -0,0 +1,77 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:http/retry.dart' show RetryClient; +import 'package:logger/logger.dart'; +import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/session/authentication_controller.dart'; +import 'package:uni/session/session.dart'; + +class AuthenticatedClient extends http.BaseClient { + AuthenticatedClient( + http.Client inner, { + required AuthenticationController authenticationController, + }) : _authenticationController = authenticationController { + _innerWithoutReauthentication = + _createInnerClientWithoutReauthentication(inner); + _inner = RetryClient.withDelays( + _innerWithoutReauthentication, + [Duration.zero], + when: shouldReauthenticate, + onRetry: (request, response, attempt) => + _authenticationController.invalidate(), + ); + } + + late final http.Client _inner; + late final http.Client _innerWithoutReauthentication; + + final AuthenticationController _authenticationController; + final FutureOr Function(Session) _shouldInvalidateSession; + + http.Client _createInnerClientWithoutReauthentication(http.Client inner) => + CookieClient( + inner, + getCookies: () => _authenticationController.session + .then((session) => session.cookies), + ); + + Future shouldReauthenticate(http.BaseResponse response) async => + response.statusCode == 403 && !await _isUserLoggedIn(); + + /// Check if the user is still logged in, + /// performing a health check on the user's personal page. + Future _isUserLoggedIn() async { + Logger().d('Checking if user is still logged in'); + + final session = await _authenticationController.session; + + final url = '${NetworkRouter.getBaseUrl(session.mainFaculty)}' + 'fest_geral.cursos_list?pv_num_unico=${session.username}'; + + final response = await _innerWithoutReauthentication.get(url.toUri()); + return response.statusCode == 200; + } + + @override + Future send(http.BaseRequest request) async { + final response = await _inner.send(request); + if (response.statusCode == 200) { + return response; + } + + // If it should still be reauthenticated, even after the retry, + // then the session should be invalidated. + if (await shouldReauthenticate(response)) { + // TODO(limwa): maybe throw exception instead? + final session = await _authenticationController.session; + await session.close(); + // NavigationService.logoutAndPopHistory(); + } + + return Future.error('HTTP Error: ${response.statusCode}'); + } + + @override + void close() => _inner.close(); +} diff --git a/uni/lib/session/initiator.dart b/uni/lib/session/initiator.dart new file mode 100644 index 000000000..5ce72604a --- /dev/null +++ b/uni/lib/session/initiator.dart @@ -0,0 +1,14 @@ +import 'dart:async'; + +import 'package:uni/session/request.dart'; + +/// In the authentication flow, the [SessionInitiator] is the component +/// responsible for handling the initial intention of the user to authenticate +/// in the app. +/// +/// When the user is in the login screen, each login method will have its own +/// initiator. An initiator only needs to be able to create a [SessionRequest] +/// and is not responsible for the actual authentication of the user. +abstract class SessionInitiator { + FutureOr initiate(); +} diff --git a/uni/lib/session/rejection.dart b/uni/lib/session/rejection.dart new file mode 100644 index 000000000..57eaaa0aa --- /dev/null +++ b/uni/lib/session/rejection.dart @@ -0,0 +1,7 @@ +import 'dart:async'; + +import 'package:uni/session/request.dart'; + +abstract interface class SessionRejectionHandler { + FutureOr onSessionRejected(SessionRequest request); +} diff --git a/uni/lib/session/request.dart b/uni/lib/session/request.dart new file mode 100644 index 000000000..03ca89567 --- /dev/null +++ b/uni/lib/session/request.dart @@ -0,0 +1,21 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:uni/session/authentication_exception.dart'; +import 'package:uni/session/initiator.dart'; +import 'package:uni/session/session.dart'; + +/// In the authentication flow, a [SessionRequest] is the component responsible +/// for performing the actual authentication of the user. A [SessionRequest] +/// can be created by an [SessionInitiator] or with the +/// [Session.createRefreshRequest] method. +/// +/// If the authentication is unsuccessful, the [SessionRequest] will throw an +/// [AuthenticationException]. +abstract class SessionRequest { + /// Performs the authentication request. + /// + /// If the authentication fails, the method will throw an + /// [AuthenticationException]. + FutureOr perform([http.Client? client]); +} diff --git a/uni/lib/controller/session/session.dart b/uni/lib/session/session.dart similarity index 80% rename from uni/lib/controller/session/session.dart rename to uni/lib/session/session.dart index e0aab5e5f..da69d30d6 100644 --- a/uni/lib/controller/session/session.dart +++ b/uni/lib/session/session.dart @@ -1,10 +1,9 @@ import 'dart:io'; -import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'package:uni/controller/session/credentials/session.dart'; -import 'package:uni/controller/session/federated/session.dart'; -import 'package:uni/controller/session/request.dart'; +import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/request.dart'; const _sessionsFromJson = [ FederatedSession.fromJson, @@ -41,10 +40,9 @@ abstract class Session { @CookieConverter() final List cookies; // TODO(limwa): use a CookieJar - SessionRequest createRefreshRequest(); + String get mainFaculty => faculties.first; - @mustCallSuper - Future close() async {} + SessionRequest createRefreshRequest(); } class CookieConverter implements JsonConverter { diff --git a/uni/lib/sigarra/endpoints/api.dart b/uni/lib/sigarra/endpoints/api.dart new file mode 100644 index 000000000..36e7041a9 --- /dev/null +++ b/uni/lib/sigarra/endpoints/api.dart @@ -0,0 +1 @@ +export 'api/authentication.dart'; diff --git a/uni/lib/sigarra/endpoints/api/authentication.dart b/uni/lib/sigarra/endpoints/api/authentication.dart new file mode 100644 index 000000000..5cadfea6e --- /dev/null +++ b/uni/lib/sigarra/endpoints/api/authentication.dart @@ -0,0 +1,20 @@ +import 'package:http/http.dart' as http; +import 'package:uni/sigarra/options.dart'; + +Future login({ + required String username, + required String password, + FacultyRequestOptions? options, +}) { + options = options ?? FacultyRequestOptions(); + + final loginUrl = options.baseUrl.resolve('mob_val_geral.autentica'); + + return options.client.post( + loginUrl, + body: { + 'pv_login': username, + 'pv_password': password, + }, + ); +} diff --git a/uni/lib/sigarra/endpoints/html/authentication.dart b/uni/lib/sigarra/endpoints/html/authentication.dart new file mode 100644 index 000000000..cecac1649 --- /dev/null +++ b/uni/lib/sigarra/endpoints/html/authentication.dart @@ -0,0 +1,16 @@ +import 'package:uni/sigarra/options.dart'; + +Future logout({ + FacultyRequestOptions? options, +}) async { + options = options ?? FacultyRequestOptions(); + + final logoutUrl = options.baseUrl.resolve('vld_validacao.sair'); + final response = await options.client.get(logoutUrl); + + if (response.statusCode == 200) { + return; + } + + throw Exception('Failed to logout from SIGARRA'); +} diff --git a/uni/lib/sigarra/endpoints/oidc.dart b/uni/lib/sigarra/endpoints/oidc.dart new file mode 100644 index 000000000..c298d4659 --- /dev/null +++ b/uni/lib/sigarra/endpoints/oidc.dart @@ -0,0 +1 @@ +export 'oidc/token.dart'; diff --git a/uni/lib/sigarra/endpoints/oidc/token.dart b/uni/lib/sigarra/endpoints/oidc/token.dart new file mode 100644 index 000000000..7a2ca5991 --- /dev/null +++ b/uni/lib/sigarra/endpoints/oidc/token.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:uni/http/utils.dart'; +import 'package:uni/sigarra/options.dart'; + +/// Returns the cookies for SIGARRA using the OIDC token. +/// +/// The client must be authorized to make this request. +Future> getCookies({ + BaseRequestOptions? options, +}) async { + options = options ?? BaseRequestOptions(); + + final tokenUrl = options.baseUrl.resolve('auth/oidc/token'); + final response = await options.client.post( + tokenUrl, + headers: { + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final body = jsonDecode(response.body) as Map; + if (body['result'] == 'OK') { + return extractCookies(response); + } + } + + throw Exception('Failed to get token from SIGARRA'); +} diff --git a/uni/lib/sigarra/options.dart b/uni/lib/sigarra/options.dart new file mode 100644 index 000000000..1e6f063ef --- /dev/null +++ b/uni/lib/sigarra/options.dart @@ -0,0 +1,44 @@ +import 'package:http/http.dart' as http; + +class BaseRequestOptions { + BaseRequestOptions({http.Client? client}) : client = client ?? http.Client(); + + final http.Client client; + + Uri get baseUrl => Uri(scheme: 'https', host: 'sigarra.up.pt'); + + BaseRequestOptions copyWith({ + http.Client? client, + }) { + return BaseRequestOptions( + client: client ?? this.client, + ); + } +} + +class FacultyRequestOptions extends BaseRequestOptions { + FacultyRequestOptions({ + this.faculty = 'up', + this.language = 'pt', + super.client, + }); + + final String faculty; + final String language; + + @override + Uri get baseUrl => super.baseUrl.resolve('/$faculty/$language/'); + + @override + FacultyRequestOptions copyWith({ + String? language, + String? faculty, + http.Client? client, + }) { + return FacultyRequestOptions( + language: language ?? this.language, + faculty: faculty ?? this.faculty, + client: client ?? this.client, + ); + } +} From 62411af10cb1363cccc920e35eabb6b83fc1ddce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 21 Aug 2024 18:49:03 +0100 Subject: [PATCH 15/99] refactor: use new package structure --- .../uni_app}/lib/generated/session/credentials/request.g.dart | 0 .../uni_app}/lib/generated/session/credentials/session.g.dart | 0 .../uni_app}/lib/generated/session/federated/session.g.dart | 0 {uni => packages/uni_app}/lib/http/client/callback.dart | 0 {uni => packages/uni_app}/lib/http/client/cookie.dart | 0 {uni => packages/uni_app}/lib/http/client/timeout.dart | 0 {uni => packages/uni_app}/lib/http/utils.dart | 0 .../uni_app}/lib/session/authentication_controller.dart | 0 .../uni_app}/lib/session/authentication_exception.dart | 0 .../uni_app}/lib/session/credentials/initiator.dart | 0 {uni => packages/uni_app}/lib/session/credentials/request.dart | 0 {uni => packages/uni_app}/lib/session/credentials/session.dart | 0 {uni => packages/uni_app}/lib/session/federated/initiator.dart | 0 {uni => packages/uni_app}/lib/session/federated/request.dart | 0 {uni => packages/uni_app}/lib/session/federated/session.dart | 0 {uni => packages/uni_app}/lib/session/http.dart | 3 ++- {uni => packages/uni_app}/lib/session/initiator.dart | 0 {uni => packages/uni_app}/lib/session/rejection.dart | 0 {uni => packages/uni_app}/lib/session/request.dart | 0 {uni => packages/uni_app}/lib/session/session.dart | 0 {uni => packages/uni_app}/lib/sigarra/endpoints/api.dart | 0 .../uni_app}/lib/sigarra/endpoints/api/authentication.dart | 0 .../uni_app}/lib/sigarra/endpoints/html/authentication.dart | 0 {uni => packages/uni_app}/lib/sigarra/endpoints/oidc.dart | 0 .../uni_app}/lib/sigarra/endpoints/oidc/token.dart | 0 {uni => packages/uni_app}/lib/sigarra/options.dart | 0 26 files changed, 2 insertions(+), 1 deletion(-) rename {uni => packages/uni_app}/lib/generated/session/credentials/request.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/session/credentials/session.g.dart (100%) rename {uni => packages/uni_app}/lib/generated/session/federated/session.g.dart (100%) rename {uni => packages/uni_app}/lib/http/client/callback.dart (100%) rename {uni => packages/uni_app}/lib/http/client/cookie.dart (100%) rename {uni => packages/uni_app}/lib/http/client/timeout.dart (100%) rename {uni => packages/uni_app}/lib/http/utils.dart (100%) rename {uni => packages/uni_app}/lib/session/authentication_controller.dart (100%) rename {uni => packages/uni_app}/lib/session/authentication_exception.dart (100%) rename {uni => packages/uni_app}/lib/session/credentials/initiator.dart (100%) rename {uni => packages/uni_app}/lib/session/credentials/request.dart (100%) rename {uni => packages/uni_app}/lib/session/credentials/session.dart (100%) rename {uni => packages/uni_app}/lib/session/federated/initiator.dart (100%) rename {uni => packages/uni_app}/lib/session/federated/request.dart (100%) rename {uni => packages/uni_app}/lib/session/federated/session.dart (100%) rename {uni => packages/uni_app}/lib/session/http.dart (99%) rename {uni => packages/uni_app}/lib/session/initiator.dart (100%) rename {uni => packages/uni_app}/lib/session/rejection.dart (100%) rename {uni => packages/uni_app}/lib/session/request.dart (100%) rename {uni => packages/uni_app}/lib/session/session.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/endpoints/api.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/endpoints/api/authentication.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/endpoints/html/authentication.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/endpoints/oidc.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/endpoints/oidc/token.dart (100%) rename {uni => packages/uni_app}/lib/sigarra/options.dart (100%) diff --git a/uni/lib/generated/session/credentials/request.g.dart b/packages/uni_app/lib/generated/session/credentials/request.g.dart similarity index 100% rename from uni/lib/generated/session/credentials/request.g.dart rename to packages/uni_app/lib/generated/session/credentials/request.g.dart diff --git a/uni/lib/generated/session/credentials/session.g.dart b/packages/uni_app/lib/generated/session/credentials/session.g.dart similarity index 100% rename from uni/lib/generated/session/credentials/session.g.dart rename to packages/uni_app/lib/generated/session/credentials/session.g.dart diff --git a/uni/lib/generated/session/federated/session.g.dart b/packages/uni_app/lib/generated/session/federated/session.g.dart similarity index 100% rename from uni/lib/generated/session/federated/session.g.dart rename to packages/uni_app/lib/generated/session/federated/session.g.dart diff --git a/uni/lib/http/client/callback.dart b/packages/uni_app/lib/http/client/callback.dart similarity index 100% rename from uni/lib/http/client/callback.dart rename to packages/uni_app/lib/http/client/callback.dart diff --git a/uni/lib/http/client/cookie.dart b/packages/uni_app/lib/http/client/cookie.dart similarity index 100% rename from uni/lib/http/client/cookie.dart rename to packages/uni_app/lib/http/client/cookie.dart diff --git a/uni/lib/http/client/timeout.dart b/packages/uni_app/lib/http/client/timeout.dart similarity index 100% rename from uni/lib/http/client/timeout.dart rename to packages/uni_app/lib/http/client/timeout.dart diff --git a/uni/lib/http/utils.dart b/packages/uni_app/lib/http/utils.dart similarity index 100% rename from uni/lib/http/utils.dart rename to packages/uni_app/lib/http/utils.dart diff --git a/uni/lib/session/authentication_controller.dart b/packages/uni_app/lib/session/authentication_controller.dart similarity index 100% rename from uni/lib/session/authentication_controller.dart rename to packages/uni_app/lib/session/authentication_controller.dart diff --git a/uni/lib/session/authentication_exception.dart b/packages/uni_app/lib/session/authentication_exception.dart similarity index 100% rename from uni/lib/session/authentication_exception.dart rename to packages/uni_app/lib/session/authentication_exception.dart diff --git a/uni/lib/session/credentials/initiator.dart b/packages/uni_app/lib/session/credentials/initiator.dart similarity index 100% rename from uni/lib/session/credentials/initiator.dart rename to packages/uni_app/lib/session/credentials/initiator.dart diff --git a/uni/lib/session/credentials/request.dart b/packages/uni_app/lib/session/credentials/request.dart similarity index 100% rename from uni/lib/session/credentials/request.dart rename to packages/uni_app/lib/session/credentials/request.dart diff --git a/uni/lib/session/credentials/session.dart b/packages/uni_app/lib/session/credentials/session.dart similarity index 100% rename from uni/lib/session/credentials/session.dart rename to packages/uni_app/lib/session/credentials/session.dart diff --git a/uni/lib/session/federated/initiator.dart b/packages/uni_app/lib/session/federated/initiator.dart similarity index 100% rename from uni/lib/session/federated/initiator.dart rename to packages/uni_app/lib/session/federated/initiator.dart diff --git a/uni/lib/session/federated/request.dart b/packages/uni_app/lib/session/federated/request.dart similarity index 100% rename from uni/lib/session/federated/request.dart rename to packages/uni_app/lib/session/federated/request.dart diff --git a/uni/lib/session/federated/session.dart b/packages/uni_app/lib/session/federated/session.dart similarity index 100% rename from uni/lib/session/federated/session.dart rename to packages/uni_app/lib/session/federated/session.dart diff --git a/uni/lib/session/http.dart b/packages/uni_app/lib/session/http.dart similarity index 99% rename from uni/lib/session/http.dart rename to packages/uni_app/lib/session/http.dart index 0104c1ba7..2be05d0d2 100644 --- a/uni/lib/session/http.dart +++ b/packages/uni_app/lib/session/http.dart @@ -6,7 +6,7 @@ import 'package:logger/logger.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/session/authentication_controller.dart'; import 'package:uni/session/session.dart'; - +/* class AuthenticatedClient extends http.BaseClient { AuthenticatedClient( http.Client inner, { @@ -75,3 +75,4 @@ class AuthenticatedClient extends http.BaseClient { @override void close() => _inner.close(); } +*/ diff --git a/uni/lib/session/initiator.dart b/packages/uni_app/lib/session/initiator.dart similarity index 100% rename from uni/lib/session/initiator.dart rename to packages/uni_app/lib/session/initiator.dart diff --git a/uni/lib/session/rejection.dart b/packages/uni_app/lib/session/rejection.dart similarity index 100% rename from uni/lib/session/rejection.dart rename to packages/uni_app/lib/session/rejection.dart diff --git a/uni/lib/session/request.dart b/packages/uni_app/lib/session/request.dart similarity index 100% rename from uni/lib/session/request.dart rename to packages/uni_app/lib/session/request.dart diff --git a/uni/lib/session/session.dart b/packages/uni_app/lib/session/session.dart similarity index 100% rename from uni/lib/session/session.dart rename to packages/uni_app/lib/session/session.dart diff --git a/uni/lib/sigarra/endpoints/api.dart b/packages/uni_app/lib/sigarra/endpoints/api.dart similarity index 100% rename from uni/lib/sigarra/endpoints/api.dart rename to packages/uni_app/lib/sigarra/endpoints/api.dart diff --git a/uni/lib/sigarra/endpoints/api/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart similarity index 100% rename from uni/lib/sigarra/endpoints/api/authentication.dart rename to packages/uni_app/lib/sigarra/endpoints/api/authentication.dart diff --git a/uni/lib/sigarra/endpoints/html/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart similarity index 100% rename from uni/lib/sigarra/endpoints/html/authentication.dart rename to packages/uni_app/lib/sigarra/endpoints/html/authentication.dart diff --git a/uni/lib/sigarra/endpoints/oidc.dart b/packages/uni_app/lib/sigarra/endpoints/oidc.dart similarity index 100% rename from uni/lib/sigarra/endpoints/oidc.dart rename to packages/uni_app/lib/sigarra/endpoints/oidc.dart diff --git a/uni/lib/sigarra/endpoints/oidc/token.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart similarity index 100% rename from uni/lib/sigarra/endpoints/oidc/token.dart rename to packages/uni_app/lib/sigarra/endpoints/oidc/token.dart diff --git a/uni/lib/sigarra/options.dart b/packages/uni_app/lib/sigarra/options.dart similarity index 100% rename from uni/lib/sigarra/options.dart rename to packages/uni_app/lib/sigarra/options.dart From 1e1ad89035df0f5a81265bafe9afc82e610fd186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 21 Aug 2024 22:10:56 +0100 Subject: [PATCH 16/99] refactor: some more progress --- .../background_workers/notifications.dart | 2 +- .../notifications/tuition_notification.dart | 2 +- packages/uni_app/lib/controller/cleanup.dart | 12 +-- .../fetchers/calendar_fetcher_html.dart | 2 +- .../all_course_units_fetcher.dart | 2 +- .../course_units_info_fetcher.dart | 2 +- .../current_course_units_fetcher.dart | 2 +- .../controller/fetchers/courses_fetcher.dart | 2 +- .../lib/controller/fetchers/exam_fetcher.dart | 2 +- .../fetchers/faculties_fetcher.dart | 2 +- .../lib/controller/fetchers/fees_fetcher.dart | 2 +- .../fetchers/library_occupation_fetcher.dart | 2 +- .../controller/fetchers/print_fetcher.dart | 2 +- .../controller/fetchers/profile_fetcher.dart | 2 +- .../fetchers/reference_fetcher.dart | 2 +- .../fetchers/restaurant_fetcher.dart | 2 +- .../schedule_fetcher/schedule_fetcher.dart | 2 +- .../schedule_fetcher_api.dart | 2 +- .../schedule_fetcher_html.dart | 2 +- .../fetchers/session_dependant_fetcher.dart | 2 +- .../local_storage/file_offline_storage.dart | 2 +- .../local_storage/preferences_controller.dart | 2 +- .../controller/networking/network_router.dart | 23 ++++-- .../parsers/parser_course_unit_info.dart | 2 +- .../parsers/parser_schedule_html.dart | 2 +- .../lib/http/client/authenticated.dart | 63 +++++++++++++++ .../uni_app/lib/http/client/callback.dart | 7 +- packages/uni_app/lib/http/client/cookie.dart | 8 +- .../lazy/course_units_info_provider.dart | 2 +- .../model/providers/lazy/exam_provider.dart | 2 +- .../providers/lazy/lecture_provider.dart | 2 +- .../providers/startup/profile_provider.dart | 2 +- .../providers/startup/session_provider.dart | 6 +- .../lib/session/{ => base}/initiator.dart | 2 +- .../lib/session/{ => base}/request.dart | 8 +- .../lib/session/{ => base}/session.dart | 2 +- ...cation_controller.dart => controller.dart} | 26 +++---- .../lib/session/credentials/initiator.dart | 2 +- .../lib/session/credentials/request.dart | 4 +- .../lib/session/credentials/session.dart | 2 +- ...ication_exception.dart => exceptions.dart} | 0 .../lib/session/federated/initiator.dart | 18 ++--- .../lib/session/federated/request.dart | 43 +++++----- .../lib/session/federated/session.dart | 3 +- packages/uni_app/lib/session/http.dart | 78 ------------------- packages/uni_app/lib/session/rejection.dart | 2 +- .../view/common_widgets/faculty_filter.dart | 2 +- .../widgets/course_unit_student_row.dart | 2 +- packages/uni_app/lib/view/login/login.dart | 2 +- .../integration/src/exams2_page_test.dart | 2 +- .../test/integration/src/exams_page_test.dart | 2 +- .../integration/src/schedule_page_test.dart | 2 +- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- 54 files changed, 190 insertions(+), 189 deletions(-) create mode 100644 packages/uni_app/lib/http/client/authenticated.dart rename packages/uni_app/lib/session/{ => base}/initiator.dart (91%) rename packages/uni_app/lib/session/{ => base}/request.dart (75%) rename packages/uni_app/lib/session/{ => base}/session.dart (96%) rename packages/uni_app/lib/session/{authentication_controller.dart => controller.dart} (78%) rename packages/uni_app/lib/session/{authentication_exception.dart => exceptions.dart} (100%) delete mode 100644 packages/uni_app/lib/session/http.dart diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index 49e2bda36..4adf48fad 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -10,7 +10,7 @@ import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; import 'package:uni/controller/local_storage/notification_timeout_storage.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; import 'package:workmanager/workmanager.dart'; /// diff --git a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart index 16a461625..30a8bc636 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/fees_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/utils/duration_string_formatter.dart'; class TuitionNotification extends Notification { diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index 6f47e9340..ea7b1cd8d 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -18,10 +18,10 @@ import 'package:uni/model/providers/state_providers.dart'; Future cleanupStoredData(BuildContext context) async { final providers = StateProviders.fromContext(context); - final session = providers.sessionProvider.state; - if (session != null) { - unawaited(session.close()); - } + // final session = providers.sessionProvider.state; + // if (session != null) { + // unawaited(session.close()); + // } providers.invalidate(); @@ -36,8 +36,8 @@ Future cleanupStoredData(BuildContext context) async { AppLastUserInfoUpdateDatabase().deleteLastUpdate(), AppBusStopDatabase().deleteBusStops(), AppCourseUnitsDatabase().deleteCourseUnits(), - if (session != null) - NetworkRouter.killSigarraAuthentication(session.faculties), + // if (session != null) + // NetworkRouter.killSigarraAuthentication(session.faculties), PreferencesController.removeSavedSession(), ]); diff --git a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart index f9565c9ca..bf9f5f598 100644 --- a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_calendar.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/calendar_event.dart'; +import 'package:uni/session/base/session.dart'; /// Fetch the school calendar from HTML class CalendarFetcherHtml implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index 03c1245cc..647a237a1 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_units.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; +import 'package:uni/session/base/session.dart'; class AllCourseUnitsFetcher { Future?> getAllCourseUnitsAndCourseAverages( diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart index 73abb394c..e73e6e5c6 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart @@ -2,11 +2,11 @@ import 'package:html/parser.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_unit_info.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; +import 'package:uni/session/base/session.dart'; class CourseUnitsInfoFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart index 487b1de44..10ee0ac03 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart @@ -2,8 +2,8 @@ import 'dart:convert'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; +import 'package:uni/session/base/session.dart'; class CurrentCourseUnitsFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart index b6ad394b5..dea680b85 100644 --- a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart @@ -1,8 +1,8 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; +import 'package:uni/session/base/session.dart'; /// Returns the user's current list of [CourseUnit]. class CoursesFetcher implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart index c3a6828be..b574922a5 100644 --- a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart @@ -1,10 +1,10 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/session/session.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'; +import 'package:uni/session/base/session.dart'; class ExamFetcher implements SessionDependantFetcher { ExamFetcher(this.courses, this.userUcs); diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index b2dbd474f..dc99c0059 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -1,6 +1,6 @@ import 'package:html/parser.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; Future> getStudentFaculties(Session session) async { final response = await NetworkRouter.getWithCookies( diff --git a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart index eb1f5200c..bea9c06b2 100644 --- a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; class FeesFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index a12c913be..2f54e3092 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_library_occupation.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/library_occupation.dart'; +import 'package:uni/session/base/session.dart'; /// Fetch the library occupation from Google Sheets class LibraryOccupationFetcherSheets implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart index 85d93d278..e0b437eb6 100644 --- a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; class PrintFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart index 72ef27f05..df8c7dc31 100644 --- a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart @@ -2,8 +2,8 @@ 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'; import 'package:uni/controller/parsers/parser_courses.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/profile.dart'; +import 'package:uni/session/base/session.dart'; class ProfileFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart index b5a4ad3d9..c860f4350 100644 --- a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; class ReferenceFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart index 3f01421ed..0e1572fdb 100644 --- a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_restaurants.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/restaurant.dart'; +import 'package:uni/session/base/session.dart'; /// Class for fetching the menu class RestaurantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index 3bb01de54..599e50741 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -1,8 +1,8 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; +import 'package:uni/session/base/session.dart'; /// Class for fetching the user's schedule. abstract class ScheduleFetcher extends SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index 3b31ac682..8981cb887 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -2,10 +2,10 @@ import 'package:http/http.dart' as http; 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.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; +import 'package:uni/session/base/session.dart'; /// Class for fetching the user's lectures from the faculties' API. class ScheduleFetcherApi extends ScheduleFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index 01833ce53..be920c026 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -3,10 +3,10 @@ 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'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; +import 'package:uni/session/base/session.dart'; /// Class for fetching the user's lectures from the schedule's HTML page. class ScheduleFetcherHtml extends ScheduleFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart index 5c2d1f317..c87d56dae 100644 --- a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart @@ -1,4 +1,4 @@ -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; abstract class SessionDependantFetcher { List getEndpoints(Session session); diff --git a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart index 2e3da04ad..c0b939852 100644 --- a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart +++ b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart @@ -6,7 +6,7 @@ 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/session/session.dart'; +import 'package:uni/session/base/session.dart'; /// The offline image storage location on the device. Future get _localPath async { diff --git a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart index 054f1a994..334568eb2 100644 --- a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart +++ b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart @@ -5,9 +5,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/utils/favorite_widget_type.dart'; /// Manages the app's Shared Preferences. diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index ca419d4d6..7e5b0b607 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -1,15 +1,13 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; import 'package:http/http.dart' as http; -import 'package:http/http.dart'; import 'package:logger/logger.dart'; -import 'package:synchronized/synchronized.dart'; +import 'package:uni/http/client/cookie.dart'; +import 'package:uni/http/utils.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/session/credentials/session.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/utils/constants.dart'; -import 'package:uni/view/navigation_service.dart'; extension UriString on String { /// Converts a [String] to an [Uri]. @@ -66,8 +64,6 @@ class NetworkRouter { ); Logger().i('Login successful'); - _lastLoginTime = DateTime.now(); - _cachedSession = session; return session; } @@ -102,4 +98,17 @@ class NetworkRouter { static List getBaseUrlsFromSession(Session session) { return NetworkRouter.getBaseUrls(session.faculties); } + + static Future getWithCookies( + String url, + Map headers, + Session session, + ) async { + final client = CookieClient( + httpClient ?? http.Client(), + cookies: () => session.cookies, + ); + + return client.get(url.toUri(), headers: headers); + } } diff --git a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart index c0a99bc41..ca959c651 100644 --- a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart +++ b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart @@ -3,12 +3,12 @@ import 'dart:convert'; import 'package:html/parser.dart'; import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_file.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; +import 'package:uni/session/base/session.dart'; Future> parseFiles( http.Response response, diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart index ad3b4e354..edf630376 100644 --- a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart +++ b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart @@ -4,10 +4,10 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart' show parse; import 'package:http/http.dart' as http; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/model/utils/time/weekday_mapper.dart'; +import 'package:uni/session/base/session.dart'; Future> getOverlappedClasses( Session session, diff --git a/packages/uni_app/lib/http/client/authenticated.dart b/packages/uni_app/lib/http/client/authenticated.dart new file mode 100644 index 000000000..6fbdbe02d --- /dev/null +++ b/packages/uni_app/lib/http/client/authenticated.dart @@ -0,0 +1,63 @@ +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:http/retry.dart' show RetryClient; +import 'package:logger/logger.dart'; +import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/http/client/cookie.dart'; +import 'package:uni/session/base/session.dart'; +import 'package:uni/session/controller.dart'; + +class AuthenticatedClient extends http.BaseClient { + AuthenticatedClient( + this._inner, { + required AuthenticationController controller, + }) : _controller = controller; + + final http.Client _inner; + final AuthenticationController _controller; + + /// Check if the user is still logged in, + /// performing a health check on the user's personal page. + Future _isUserLoggedIn(Session session) async { + Logger().d('Checking if user is still logged in'); + + final url = '${NetworkRouter.getBaseUrl(session.mainFaculty)}' + 'fest_geral.cursos_list?pv_num_unico=${session.username}'; + + final client = CookieClient(_inner, cookies: () => session.cookies); + final response = await client.get(url.toUri()); + + return response.statusCode == 200; + } + + @override + Future send(http.BaseRequest request) async { + var snapshot = await _controller.snapshot; + + final client = RetryClient.withDelays( + CookieClient( + _inner, + // Send the request with the cookies of the latest snapshot. + cookies: () => snapshot.session.cookies, + ), + [Duration.zero], + when: (response) async => + // We retry if the request is unauthorized + response.statusCode == 403 && + // and, to be sure, if the user is not logged in SIGARRA. + !await _isUserLoggedIn(snapshot.session), + onRetry: (request, response, attempt) async { + // When retrying, the previous session should be invalidated + // and the session should be refreshed. + await snapshot.invalidate(); + snapshot = await _controller.snapshot; + }, + ); + + return client.send(request); + } + + @override + void close() => _inner.close(); +} diff --git a/packages/uni_app/lib/http/client/callback.dart b/packages/uni_app/lib/http/client/callback.dart index 497c892eb..d727701de 100644 --- a/packages/uni_app/lib/http/client/callback.dart +++ b/packages/uni_app/lib/http/client/callback.dart @@ -1,9 +1,10 @@ import 'package:http/http.dart' as http; class CallbackClient extends http.BaseClient { - CallbackClient(http.Client inner, - {required Future Function(http.BaseRequest) send}) - : _inner = inner, + CallbackClient( + http.Client inner, { + required Future Function(http.BaseRequest) send, + }) : _inner = inner, _send = send; final http.Client _inner; diff --git a/packages/uni_app/lib/http/client/cookie.dart b/packages/uni_app/lib/http/client/cookie.dart index eae125ee2..d8560ca19 100644 --- a/packages/uni_app/lib/http/client/cookie.dart +++ b/packages/uni_app/lib/http/client/cookie.dart @@ -6,14 +6,16 @@ import 'package:http/http.dart' as http; class CookieClient extends http.BaseClient { CookieClient( this._inner, { - required this.cookies, - }); + required FutureOr> Function() cookies, + }) : _cookies = cookies; final http.Client _inner; - final List cookies; + final FutureOr> Function() _cookies; @override Future send(http.BaseRequest request) async { + final cookies = await _cookies(); + final initialCookies = request.headers[HttpHeaders.cookieHeader]; final allCookies = [ if (initialCookies != null) initialCookies, diff --git a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart index 3432e75df..0fedd14d4 100644 --- a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart @@ -2,13 +2,13 @@ import 'dart:collection'; import 'package:tuple/tuple.dart'; import 'package:uni/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/session/base/session.dart'; typedef SheetsMap = Map; typedef ClassesMap = Map>; diff --git a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart index 9dd0287e7..7e72ce346 100644 --- a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart @@ -3,12 +3,12 @@ import 'dart:async'; import 'package:uni/controller/fetchers/exam_fetcher.dart'; import 'package:uni/controller/local_storage/database/app_exams_database.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/session/base/session.dart'; class ExamProvider extends StateProviderNotifier> { ExamProvider() : super(cacheDuration: const Duration(days: 1)); diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index c8abc3518..ed67e43c7 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -4,11 +4,11 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart'; import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/session/base/session.dart'; class LectureProvider extends StateProviderNotifier> { LectureProvider() : super(cacheDuration: const Duration(hours: 6)); diff --git a/packages/uni_app/lib/model/providers/startup/profile_provider.dart b/packages/uni_app/lib/model/providers/startup/profile_provider.dart index 622ec1631..8c4f75939 100644 --- a/packages/uni_app/lib/model/providers/startup/profile_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/profile_provider.dart @@ -13,12 +13,12 @@ import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/file_offline_storage.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; import 'package:uni/controller/parsers/parser_print_balance.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/session/base/session.dart'; class ProfileProvider extends StateProviderNotifier { ProfileProvider() diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index a5ddf2b2e..dba89c0be 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -5,12 +5,12 @@ import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/session/federated/request.dart'; -import 'package:uni/session/request.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/session/base/request.dart'; +import 'package:uni/session/base/session.dart'; +import 'package:uni/session/federated/request.dart'; import 'package:uni/utils/constants.dart'; import 'package:url_launcher/url_launcher.dart'; diff --git a/packages/uni_app/lib/session/initiator.dart b/packages/uni_app/lib/session/base/initiator.dart similarity index 91% rename from packages/uni_app/lib/session/initiator.dart rename to packages/uni_app/lib/session/base/initiator.dart index 5ce72604a..bb0522aac 100644 --- a/packages/uni_app/lib/session/initiator.dart +++ b/packages/uni_app/lib/session/base/initiator.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:uni/session/request.dart'; +import 'package:uni/session/base/request.dart'; /// In the authentication flow, the [SessionInitiator] is the component /// responsible for handling the initial intention of the user to authenticate diff --git a/packages/uni_app/lib/session/request.dart b/packages/uni_app/lib/session/base/request.dart similarity index 75% rename from packages/uni_app/lib/session/request.dart rename to packages/uni_app/lib/session/base/request.dart index 03ca89567..40b53c91c 100644 --- a/packages/uni_app/lib/session/request.dart +++ b/packages/uni_app/lib/session/base/request.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'package:http/http.dart' as http; -import 'package:uni/session/authentication_exception.dart'; -import 'package:uni/session/initiator.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/initiator.dart'; +import 'package:uni/session/base/session.dart'; +import 'package:uni/session/exceptions.dart'; /// In the authentication flow, a [SessionRequest] is the component responsible /// for performing the actual authentication of the user. A [SessionRequest] @@ -17,5 +17,5 @@ abstract class SessionRequest { /// /// If the authentication fails, the method will throw an /// [AuthenticationException]. - FutureOr perform([http.Client? client]); + FutureOr perform([http.Client? httpClient]); } diff --git a/packages/uni_app/lib/session/session.dart b/packages/uni_app/lib/session/base/session.dart similarity index 96% rename from packages/uni_app/lib/session/session.dart rename to packages/uni_app/lib/session/base/session.dart index da69d30d6..8b3ee53b8 100644 --- a/packages/uni_app/lib/session/session.dart +++ b/packages/uni_app/lib/session/base/session.dart @@ -1,9 +1,9 @@ import 'dart:io'; import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/session/base/request.dart'; import 'package:uni/session/credentials/session.dart'; import 'package:uni/session/federated/session.dart'; -import 'package:uni/session/request.dart'; const _sessionsFromJson = [ FederatedSession.fromJson, diff --git a/packages/uni_app/lib/session/authentication_controller.dart b/packages/uni_app/lib/session/controller.dart similarity index 78% rename from packages/uni_app/lib/session/authentication_controller.dart rename to packages/uni_app/lib/session/controller.dart index 748cc16ec..633f5f5f5 100644 --- a/packages/uni_app/lib/session/authentication_controller.dart +++ b/packages/uni_app/lib/session/controller.dart @@ -1,18 +1,18 @@ import 'dart:async'; import 'package:synchronized/synchronized.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; class AuthenticationSnapshot { AuthenticationSnapshot( this.session, { - required void Function(AuthenticationSnapshot snapshot) onInvalidate, - }) : _onInvalidate = onInvalidate; + required Future Function(AuthenticationSnapshot) invalidate, + }) : _invalidate = invalidate; final Session session; - final FutureOr Function(AuthenticationSnapshot) _onInvalidate; + final Future Function(AuthenticationSnapshot) _invalidate; - FutureOr invalidate() => _onInvalidate(this); + Future invalidate() => _invalidate(this); } class AuthenticationController { @@ -31,17 +31,10 @@ class AuthenticationController { return AuthenticationSnapshot( _session, - onInvalidate: (snapshot) => _invalidate(snapshot.session), + invalidate: (snapshot) => _invalidate(snapshot.session), ); } - Future _reauthenticate() async { - final refreshRequest = _session.createRefreshRequest(); - _session = await refreshRequest.perform(); - - await _authenticationLock.synchronized(() => _nextAuthentication = null); - } - Future _invalidate(Session session) async { // This check is intentionally used twice to avoid unnecessary lock // acquisitions. @@ -57,4 +50,11 @@ class AuthenticationController { _nextAuthentication = _reauthenticate(); }); } + + Future _reauthenticate() async { + final refreshRequest = _session.createRefreshRequest(); + _session = await refreshRequest.perform(); + + await _authenticationLock.synchronized(() => _nextAuthentication = null); + } } diff --git a/packages/uni_app/lib/session/credentials/initiator.dart b/packages/uni_app/lib/session/credentials/initiator.dart index 1b457917a..f39b0764a 100644 --- a/packages/uni_app/lib/session/credentials/initiator.dart +++ b/packages/uni_app/lib/session/credentials/initiator.dart @@ -1,5 +1,5 @@ +import 'package:uni/session/base/initiator.dart'; import 'package:uni/session/credentials/request.dart'; -import 'package:uni/session/initiator.dart'; class CredentialsSessionInitiator extends SessionInitiator { CredentialsSessionInitiator({ diff --git a/packages/uni_app/lib/session/credentials/request.dart b/packages/uni_app/lib/session/credentials/request.dart index 168b07ed4..1e5c498b3 100644 --- a/packages/uni_app/lib/session/credentials/request.dart +++ b/packages/uni_app/lib/session/credentials/request.dart @@ -4,8 +4,8 @@ import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/model/entities/login_exceptions.dart'; +import 'package:uni/session/base/request.dart'; import 'package:uni/session/credentials/session.dart'; -import 'package:uni/session/request.dart'; part '../../generated/session/credentials/request.g.dart'; @@ -20,7 +20,7 @@ class CredentialsSessionRequest extends SessionRequest { final String password; @override - Future perform([http.Client? client]) async { + Future perform([http.Client? httpClient]) async { // TODO (limwa): Use client // We need to login to fetch the faculties, so perform a temporary login. final tempSession = await NetworkRouter.login(username, password); diff --git a/packages/uni_app/lib/session/credentials/session.dart b/packages/uni_app/lib/session/credentials/session.dart index a834ab764..17c099b6b 100644 --- a/packages/uni_app/lib/session/credentials/session.dart +++ b/packages/uni_app/lib/session/credentials/session.dart @@ -1,6 +1,6 @@ import 'package:json_annotation/json_annotation.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/session/credentials/request.dart'; -import 'package:uni/session/session.dart'; part '../../generated/session/credentials/session.g.dart'; diff --git a/packages/uni_app/lib/session/authentication_exception.dart b/packages/uni_app/lib/session/exceptions.dart similarity index 100% rename from packages/uni_app/lib/session/authentication_exception.dart rename to packages/uni_app/lib/session/exceptions.dart diff --git a/packages/uni_app/lib/session/federated/initiator.dart b/packages/uni_app/lib/session/federated/initiator.dart index ed7e7d30c..363830a3c 100644 --- a/packages/uni_app/lib/session/federated/initiator.dart +++ b/packages/uni_app/lib/session/federated/initiator.dart @@ -1,28 +1,26 @@ +import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; +import 'package:uni/session/base/initiator.dart'; +import 'package:uni/session/base/request.dart'; import 'package:uni/session/federated/request.dart'; -import 'package:uni/session/initiator.dart'; -import 'package:uni/session/request.dart'; class FederatedSessionInitiator extends SessionInitiator { FederatedSessionInitiator({ required this.realm, required this.clientId, required this.redirectUri, - required this.delegateAuthentication, + required this.performAuthentication, }); final Uri realm; final String clientId; final Uri redirectUri; - final Future Function(Flow flow) delegateAuthentication; + final Future Function(Flow flow) performAuthentication; @override - Future initiate() async { + Future initiate([http.Client? httpClient]) async { final issuer = await Issuer.discover(realm); - final client = Client( - issuer, - clientId, - ); + final client = Client(issuer, clientId, httpClient: httpClient); final flow = Flow.authorizationCodeWithPKCE( client, @@ -36,7 +34,7 @@ class FederatedSessionInitiator extends SessionInitiator { ], )..redirectUri = redirectUri; - final uri = await delegateAuthentication(flow); + final uri = await performAuthentication(flow); final credential = await flow.callback(uri.queryParameters); return FederatedSessionRequest(credential: credential); diff --git a/packages/uni_app/lib/session/federated/request.dart b/packages/uni_app/lib/session/federated/request.dart index 09de66c50..844af32b3 100644 --- a/packages/uni_app/lib/session/federated/request.dart +++ b/packages/uni_app/lib/session/federated/request.dart @@ -1,22 +1,25 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; +import 'package:openid_client/openid_client_browser.dart'; +import 'package:uni/session/base/request.dart'; import 'package:uni/session/federated/session.dart'; -import 'package:uni/session/request.dart'; import 'package:uni/sigarra/endpoints/oidc.dart' as oidc; import 'package:uni/sigarra/options.dart'; -class FederatedSessionRequest extends SessionRequest { - FederatedSessionRequest({ - required this.credential, - }); +class FederatedSessionUserInfo { + FederatedSessionUserInfo( + UserInfo userInfo, + ) : username = _extractUsername(userInfo), + faculties = _extractFaculties(userInfo); - final Credential credential; + final String username; + final List faculties; - String _getUsername(UserInfo userInfo) { + static String _extractUsername(UserInfo userInfo) { return userInfo.getTyped('nmec')!; } - List _getFaculties(UserInfo userInfo) { + static List _extractFaculties(UserInfo userInfo) { final faculties = userInfo .getTyped>('ous')! .cast() @@ -25,16 +28,20 @@ class FederatedSessionRequest extends SessionRequest { return faculties; } +} + +class FederatedSessionRequest extends SessionRequest { + FederatedSessionRequest({ + required this.credential, + }); + + final Credential credential; @override - Future perform([ - http.Client? client, - ]) async { - final userInfo = await credential.getUserInfo(); - final username = _getUsername(userInfo); - final faculties = _getFaculties(userInfo); - - final authorizedClient = credential.createHttpClient(client); + Future perform([http.Client? httpClient]) async { + final userInfo = FederatedSessionUserInfo(await credential.getUserInfo()); + + final authorizedClient = credential.createHttpClient(httpClient); final cookies = await oidc.getCookies( options: BaseRequestOptions( client: authorizedClient, @@ -42,9 +49,9 @@ class FederatedSessionRequest extends SessionRequest { ); return FederatedSession( - username: username, + username: userInfo.username, + faculties: userInfo.faculties, cookies: cookies, - faculties: faculties, credential: credential, ); } diff --git a/packages/uni_app/lib/session/federated/session.dart b/packages/uni_app/lib/session/federated/session.dart index f3e78a4cb..ac383b85e 100644 --- a/packages/uni_app/lib/session/federated/session.dart +++ b/packages/uni_app/lib/session/federated/session.dart @@ -1,8 +1,7 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:openid_client/openid_client.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/session/federated/request.dart'; -import 'package:uni/session/session.dart'; -import 'package:url_launcher/url_launcher.dart'; part '../../generated/session/federated/session.g.dart'; diff --git a/packages/uni_app/lib/session/http.dart b/packages/uni_app/lib/session/http.dart deleted file mode 100644 index 2be05d0d2..000000000 --- a/packages/uni_app/lib/session/http.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'dart:async'; - -import 'package:http/http.dart' as http; -import 'package:http/retry.dart' show RetryClient; -import 'package:logger/logger.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/authentication_controller.dart'; -import 'package:uni/session/session.dart'; -/* -class AuthenticatedClient extends http.BaseClient { - AuthenticatedClient( - http.Client inner, { - required AuthenticationController authenticationController, - }) : _authenticationController = authenticationController { - _innerWithoutReauthentication = - _createInnerClientWithoutReauthentication(inner); - _inner = RetryClient.withDelays( - _innerWithoutReauthentication, - [Duration.zero], - when: shouldReauthenticate, - onRetry: (request, response, attempt) => - _authenticationController.invalidate(), - ); - } - - late final http.Client _inner; - late final http.Client _innerWithoutReauthentication; - - final AuthenticationController _authenticationController; - final FutureOr Function(Session) _shouldInvalidateSession; - - http.Client _createInnerClientWithoutReauthentication(http.Client inner) => - CookieClient( - inner, - getCookies: () => _authenticationController.session - .then((session) => session.cookies), - ); - - Future shouldReauthenticate(http.BaseResponse response) async => - response.statusCode == 403 && !await _isUserLoggedIn(); - - /// Check if the user is still logged in, - /// performing a health check on the user's personal page. - Future _isUserLoggedIn() async { - Logger().d('Checking if user is still logged in'); - - final session = await _authenticationController.session; - - final url = '${NetworkRouter.getBaseUrl(session.mainFaculty)}' - 'fest_geral.cursos_list?pv_num_unico=${session.username}'; - - final response = await _innerWithoutReauthentication.get(url.toUri()); - return response.statusCode == 200; - } - - @override - Future send(http.BaseRequest request) async { - final response = await _inner.send(request); - if (response.statusCode == 200) { - return response; - } - - // If it should still be reauthenticated, even after the retry, - // then the session should be invalidated. - if (await shouldReauthenticate(response)) { - // TODO(limwa): maybe throw exception instead? - final session = await _authenticationController.session; - await session.close(); - // NavigationService.logoutAndPopHistory(); - } - - return Future.error('HTTP Error: ${response.statusCode}'); - } - - @override - void close() => _inner.close(); -} -*/ diff --git a/packages/uni_app/lib/session/rejection.dart b/packages/uni_app/lib/session/rejection.dart index 57eaaa0aa..968ec67a2 100644 --- a/packages/uni_app/lib/session/rejection.dart +++ b/packages/uni_app/lib/session/rejection.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:uni/session/request.dart'; +import 'package:uni/session/base/request.dart'; abstract interface class SessionRejectionHandler { FutureOr onSessionRejected(SessionRequest request); diff --git a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart index e1eb8b5bf..5843166cf 100644 --- a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart +++ b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/session/session.dart'; +import 'package:uni/session/base/session.dart'; class FacultyFilter extends StatelessWidget { const FacultyFilter({ diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart index 2469f1b1c..9333c370b 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/session/base/session.dart'; class CourseUnitStudentRow extends StatelessWidget { const CourseUnitStudentRow(this.student, this.session, {super.key}); diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index a35e84421..5d0bcec89 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.dart @@ -8,11 +8,11 @@ import 'package:logger/logger.dart'; import 'package:provider/provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/controller/networking/url_launcher.dart'; -import 'package:uni/session/credentials/request.dart'; 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/session/credentials/request.dart'; import 'package:uni/utils/navigation_items.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; import 'package:uni/view/home/widgets/exit_app_dialog.dart'; diff --git a/packages/uni_app/test/integration/src/exams2_page_test.dart b/packages/uni_app/test/integration/src/exams2_page_test.dart index e7aaf4593..e67e74a55 100644 --- a/packages/uni_app/test/integration/src/exams2_page_test.dart +++ b/packages/uni_app/test/integration/src/exams2_page_test.dart @@ -9,12 +9,12 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/session/session.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'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/view/exams/exams.dart'; import '../../mocks/integration/src/exams_page_test.mocks.dart'; diff --git a/packages/uni_app/test/integration/src/exams_page_test.dart b/packages/uni_app/test/integration/src/exams_page_test.dart index dd092cd1d..7ed5057ba 100644 --- a/packages/uni_app/test/integration/src/exams_page_test.dart +++ b/packages/uni_app/test/integration/src/exams_page_test.dart @@ -8,12 +8,12 @@ import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/session/session.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'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/view/exams/exams.dart'; import '../../mocks/integration/src/exams_page_test.mocks.dart'; diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart index adb99a3b9..82f788309 100644 --- a/packages/uni_app/test/integration/src/schedule_page_test.dart +++ b/packages/uni_app/test/integration/src/schedule_page_test.dart @@ -8,11 +8,11 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; +import 'package:uni/session/base/session.dart'; import 'package:uni/view/schedule/schedule.dart'; import '../../mocks/integration/src/schedule_page_test.mocks.dart'; diff --git a/packages/uni_app/test/unit/providers/exams_provider_test.dart b/packages/uni_app/test/unit/providers/exams_provider_test.dart index 2205ff8b9..b39382980 100644 --- a/packages/uni_app/test/unit/providers/exams_provider_test.dart +++ b/packages/uni_app/test/unit/providers/exams_provider_test.dart @@ -4,13 +4,13 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_exams.dart'; -import 'package:uni/session/session.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'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/session/base/session.dart'; import '../../mocks/unit/providers/exams_provider_test.mocks.dart'; import '../../test_widget.dart'; diff --git a/packages/uni_app/test/unit/providers/lecture_provider_test.dart b/packages/uni_app/test/unit/providers/lecture_provider_test.dart index 0859f164b..d1aeed512 100644 --- a/packages/uni_app/test/unit/providers/lecture_provider_test.dart +++ b/packages/uni_app/test/unit/providers/lecture_provider_test.dart @@ -4,12 +4,12 @@ import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/session.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/session/base/session.dart'; import '../../mocks/unit/providers/lecture_provider_test.mocks.dart'; import '../../test_widget.dart'; From f48cf01755ea55035ec997e887a5cb80e23fbfb4 Mon Sep 17 00:00:00 2001 From: vitormpp Date: Fri, 19 Jul 2024 18:48:19 +0100 Subject: [PATCH 17/99] Removed SQLite reserved keywords from sql scripts --- .../local_storage/database/app_exams_database.dart | 6 +++--- .../local_storage/database/app_user_database.dart | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart index 26d6b7dc2..ddc5b8372 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart @@ -13,7 +13,7 @@ class AppExamsDatabase extends AppDatabase> { : super('exams.db', [_createScript], onUpgrade: migrate, version: 6); static const _createScript = ''' -CREATE TABLE exams(id TEXT, subject TEXT, begin TEXT, end TEXT, +CREATE TABLE exams(id TEXT, subject TEXT, start TEXT, finish TEXT, rooms TEXT, examType TEXT, faculty TEXT, PRIMARY KEY (id,faculty)) '''; /// Returns a list containing all of the exams stored in this database. @@ -25,8 +25,8 @@ CREATE TABLE exams(id TEXT, subject TEXT, begin TEXT, end TEXT, return Exam.secConstructor( maps[i]['id'] as String, maps[i]['subject'] as String, - DateTime.parse(maps[i]['begin'] as String), - DateTime.parse(maps[i]['end'] as String), + DateTime.parse(maps[i]['start'] as String), + DateTime.parse(maps[i]['finish'] as String), maps[i]['rooms'] as String, maps[i]['examType'] as String, maps[i]['faculty'] as String, diff --git a/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart index fca077922..b22ba17d7 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart @@ -9,7 +9,7 @@ import 'package:uni/model/entities/profile.dart'; /// This database stores information about the user's university profile. class AppUserDataDatabase extends AppDatabase { AppUserDataDatabase() - : super('userdata.db', ['CREATE TABLE userdata(key TEXT, value TEXT)']); + : super('userdata.db', ['CREATE TABLE userdata(name TEXT, value TEXT)']); /// Adds [data] (profile) to this database. @override @@ -17,7 +17,7 @@ class AppUserDataDatabase extends AppDatabase { for (final keymap in data.keymapValues()) { await insertInDatabase( 'userdata', - {'key': keymap.item1, 'value': keymap.item2}, + {'name': keymap.item1, 'value': keymap.item2}, ); } } @@ -37,19 +37,19 @@ class AppUserDataDatabase extends AppDatabase { String? feesBalance; DateTime? feesLimit; for (final entry in maps) { - if (entry['key'] == 'name') { + if (entry['name'] == 'name') { name = entry['value'] as String; } - if (entry['key'] == 'email') { + if (entry['name'] == 'email') { email = entry['value'] as String; } - if (entry['key'] == 'printBalance') { + if (entry['name'] == 'printBalance') { printBalance = entry['value'] as String; } - if (entry['key'] == 'feesBalance') { + if (entry['name'] == 'feesBalance') { feesBalance = entry['value'] as String; } - if (entry['key'] == 'feesLimit') { + if (entry['name'] == 'feesLimit') { feesLimit = DateTime.tryParse(entry['value'] as String); } } From 3bb35dac0b9e7eeab773c410c8263070404069b1 Mon Sep 17 00:00:00 2001 From: vitormpp Date: Fri, 19 Jul 2024 18:49:53 +0100 Subject: [PATCH 18/99] Updated the exam model to ensure consistency. --- packages/uni_app/lib/model/entities/exam.dart | 26 +++++++++---------- .../model/providers/lazy/exam_provider.dart | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/uni_app/lib/model/entities/exam.dart b/packages/uni_app/lib/model/entities/exam.dart index e8134c3bc..280661e2d 100644 --- a/packages/uni_app/lib/model/entities/exam.dart +++ b/packages/uni_app/lib/model/entities/exam.dart @@ -9,7 +9,7 @@ part '../../generated/model/entities/exam.g.dart'; /// Manages a generic Exam. /// /// The information stored is: -/// - The `begin` and `end` times of the Exam +/// - The `start` and `finish` times of the Exam /// - The Exam `subject` /// - A List with the `rooms` in which the Exam takes place /// - The Exam `type` @@ -19,8 +19,8 @@ part '../../generated/model/entities/exam.g.dart'; class Exam { Exam( this.id, - this.begin, - this.end, + this.start, + this.finish, this.subject, this.rooms, this.examType, @@ -32,15 +32,15 @@ class Exam { Exam.secConstructor( this.id, this.subject, - this.begin, - this.end, + this.start, + this.finish, String rooms, this.examType, this.faculty, ) : rooms = rooms.split(','); - final DateTime begin; - final DateTime end; + final DateTime start; + final DateTime finish; final String id; final String subject; final List rooms; @@ -59,29 +59,29 @@ class Exam { Map toJson() => _$ExamToJson(this); /// Returns whether or not this exam has already ended. - bool hasEnded() => DateTime.now().compareTo(end) >= 0; + bool hasEnded() => DateTime.now().compareTo(finish) >= 0; String weekDay(AppLocale locale) { return DateFormat.EEEE(locale.localeCode.languageCode) .dateSymbols - .WEEKDAYS[begin.weekday % 7]; + .WEEKDAYS[start.weekday % 7]; } String month(AppLocale locale) { return DateFormat.EEEE(locale.localeCode.languageCode) .dateSymbols - .MONTHS[begin.month - 1]; + .MONTHS[start.month - 1]; } - String get beginTime => formatTime(begin); + String get startTime => formatTime(start); - String get endTime => formatTime(end); + String get finishTime => formatTime(finish); String formatTime(DateTime time) => DateFormat('HH:mm').format(time); @override String toString() { - return '''$id - $subject - ${begin.year} - $month - ${begin.day} - $beginTime-$endTime - $examType - $rooms - $weekDay'''; + return '''$id - $subject - ${start.year} - $month - ${start.day} - $startTime-$finishTime - $examType - $rooms - $weekDay'''; } /// Prints the data in this exam to the [Logger] with an INFO level. diff --git a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart index e8d6d3209..6cdcc6abe 100644 --- a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart @@ -41,7 +41,7 @@ class ExamProvider extends StateProviderNotifier> { final exams = await ExamFetcher(profile.courses, userUcs) .extractExams(session, parserExams); - exams.sort((exam1, exam2) => exam1.begin.compareTo(exam2.begin)); + exams.sort((exam1, exam2) => exam1.start.compareTo(exam2.start)); final db = AppExamsDatabase(); await db.saveIfPersistentSession(exams); From 74a9d03687d90866e853b70234d675324805192a Mon Sep 17 00:00:00 2001 From: vitormpp Date: Fri, 19 Jul 2024 18:51:55 +0100 Subject: [PATCH 19/99] Updated exam widgets to align with the changes. --- packages/uni_app/lib/view/exams/exams.dart | 10 +++++----- .../uni_app/lib/view/exams/widgets/exam_row.dart | 12 ++++++------ .../uni_app/lib/view/home/widgets/exam_card.dart | 2 +- .../lib/view/home/widgets/next_exams_card.dart | 2 +- .../lib/view/home/widgets/remaining_exams_card.dart | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/uni_app/lib/view/exams/exams.dart b/packages/uni_app/lib/view/exams/exams.dart index 0db5edd98..207b0fa55 100644 --- a/packages/uni_app/lib/view/exams/exams.dart +++ b/packages/uni_app/lib/view/exams/exams.dart @@ -77,8 +77,8 @@ class ExamsPageViewState extends SecondaryPageViewState { for (var i = 0; i < exams.length; i++) { if (i + 1 >= exams.length) { - if (exams[i].begin.day == exams[i - 1].begin.day && - exams[i].begin.month == exams[i - 1].begin.month) { + if (exams[i].start.day == exams[i - 1].start.day && + exams[i].start.month == exams[i - 1].start.month) { currentDayExams.add(exams[i]); } else { if (currentDayExams.isNotEmpty) { @@ -91,8 +91,8 @@ class ExamsPageViewState extends SecondaryPageViewState { columns.add(createExamCard(context, currentDayExams)); break; } - if (exams[i].begin.day == exams[i + 1].begin.day && - exams[i].begin.month == exams[i + 1].begin.month) { + if (exams[i].start.day == exams[i + 1].start.day && + exams[i].start.month == exams[i + 1].start.month) { currentDayExams.add(exams[i]); } else { currentDayExams.add(exams[i]); @@ -122,7 +122,7 @@ class ExamsPageViewState extends SecondaryPageViewState { alignment: Alignment.center, child: Text( '${exams.first.weekDay(locale)}, ' - '${exams.first.begin.formattedDate(locale)}', + '${exams.first.start.formattedDate(locale)}', style: Theme.of(context).textTheme.titleLarge, ), ), diff --git a/packages/uni_app/lib/view/exams/widgets/exam_row.dart b/packages/uni_app/lib/view/exams/widgets/exam_row.dart index 176752202..c47e6c0bd 100644 --- a/packages/uni_app/lib/view/exams/widgets/exam_row.dart +++ b/packages/uni_app/lib/view/exams/widgets/exam_row.dart @@ -39,8 +39,8 @@ class _ExamRowState extends State { @override Widget build(BuildContext context) { final roomsKey = - '${widget.exam.subject}-${widget.exam.rooms}-${widget.exam.beginTime}-' - '${widget.exam.endTime}'; + '${widget.exam.subject}-${widget.exam.rooms}-${widget.exam.startTime}-' + '${widget.exam.startTime}'; return Center( child: Container( padding: const EdgeInsets.only(left: 12, bottom: 8, right: 12), @@ -54,10 +54,10 @@ class _ExamRowState extends State { children: [ Column( mainAxisAlignment: MainAxisAlignment.center, - children: widget.exam.beginTime != '00:00' + children: widget.exam.startTime != '00:00' ? [ ExamTime( - begin: widget.exam.beginTime, + begin: widget.exam.startTime, ), ] : [], @@ -146,8 +146,8 @@ class _ExamRowState extends State { return Event( title: '${widget.exam.examType} ${widget.exam.subject}', location: widget.exam.rooms.toString(), - startDate: widget.exam.begin, - endDate: widget.exam.end, + startDate: widget.exam.start, + endDate: widget.exam.finish, ); } } diff --git a/packages/uni_app/lib/view/home/widgets/exam_card.dart b/packages/uni_app/lib/view/home/widgets/exam_card.dart index 3c0bb83b9..aa5295613 100644 --- a/packages/uni_app/lib/view/home/widgets/exam_card.dart +++ b/packages/uni_app/lib/view/home/widgets/exam_card.dart @@ -111,7 +111,7 @@ class ExamCard extends GenericCard { List getPrimaryExams(List visibleExams) { return visibleExams - .where((exam) => isSameDay(visibleExams[0].begin, exam.begin)) + .where((exam) => isSameDay(visibleExams[0].start, exam.start)) .toList(); } diff --git a/packages/uni_app/lib/view/home/widgets/next_exams_card.dart b/packages/uni_app/lib/view/home/widgets/next_exams_card.dart index 88d99a672..45d8d3259 100644 --- a/packages/uni_app/lib/view/home/widgets/next_exams_card.dart +++ b/packages/uni_app/lib/view/home/widgets/next_exams_card.dart @@ -19,7 +19,7 @@ class NextExamsWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ DateRectangle( - date: exams.isNotEmpty ? exams.first.begin.formattedDate(locale) : '', + date: exams.isNotEmpty ? exams.first.start.formattedDate(locale) : '', ), Column( children: exams.map((exam) { diff --git a/packages/uni_app/lib/view/home/widgets/remaining_exams_card.dart b/packages/uni_app/lib/view/home/widgets/remaining_exams_card.dart index ee8549221..56f1f0180 100644 --- a/packages/uni_app/lib/view/home/widgets/remaining_exams_card.dart +++ b/packages/uni_app/lib/view/home/widgets/remaining_exams_card.dart @@ -26,7 +26,7 @@ class RemainingExamsWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - exam.begin.formattedDate(locale), + exam.start.formattedDate(locale), style: Theme.of(context).textTheme.bodyLarge, ), ExamTitle( From 753156d1412c04d0c31513c19e4e35da4f48203c Mon Sep 17 00:00:00 2001 From: vitormpp Date: Fri, 19 Jul 2024 22:21:50 +0100 Subject: [PATCH 20/99] Updated generated file --- packages/uni_app/lib/generated/model/entities/exam.g.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/generated/model/entities/exam.g.dart b/packages/uni_app/lib/generated/model/entities/exam.g.dart index 7d0b8fe2a..837cd7646 100644 --- a/packages/uni_app/lib/generated/model/entities/exam.g.dart +++ b/packages/uni_app/lib/generated/model/entities/exam.g.dart @@ -8,8 +8,8 @@ part of '../../../model/entities/exam.dart'; Exam _$ExamFromJson(Map json) => Exam( json['id'] as String, - const DateTimeConverter().fromJson(json['begin'] as String), - const DateTimeConverter().fromJson(json['end'] as String), + const DateTimeConverter().fromJson(json['start'] as String), + const DateTimeConverter().fromJson(json['finish'] as String), json['subject'] as String, (json['rooms'] as List).map((e) => e as String).toList(), json['examType'] as String, @@ -17,8 +17,8 @@ Exam _$ExamFromJson(Map json) => Exam( ); Map _$ExamToJson(Exam instance) => { - 'begin': const DateTimeConverter().toJson(instance.begin), - 'end': const DateTimeConverter().toJson(instance.end), + 'start': const DateTimeConverter().toJson(instance.start), + 'finish': const DateTimeConverter().toJson(instance.finish), 'id': instance.id, 'subject': instance.subject, 'rooms': instance.rooms, From f9bbdf26461c8d1823d9b2e2e8b611a95b2eb6d6 Mon Sep 17 00:00:00 2001 From: vitormpp Date: Wed, 7 Aug 2024 21:51:42 +0100 Subject: [PATCH 21/99] fix(database): update version and add migration logic for version update --- .../database/app_exams_database.dart | 2 +- .../database/app_user_database.dart | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart index ddc5b8372..b628ddcf0 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_exams_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/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: 6); + : super('exams.db', [_createScript], onUpgrade: migrate, version: 7); static const _createScript = ''' CREATE TABLE exams(id TEXT, subject TEXT, start TEXT, finish TEXT, diff --git a/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart index b22ba17d7..51be2348b 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_user_database.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:sqflite/sqlite_api.dart'; import 'package:uni/controller/local_storage/database/app_database.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; @@ -9,7 +10,12 @@ import 'package:uni/model/entities/profile.dart'; /// This database stores information about the user's university profile. class AppUserDataDatabase extends AppDatabase { AppUserDataDatabase() - : super('userdata.db', ['CREATE TABLE userdata(name TEXT, value TEXT)']); + : super( + 'userdata.db', + ['CREATE TABLE userdata(name TEXT, value TEXT)'], + onUpgrade: migrate, + version: 2, + ); /// Adds [data] (profile) to this database. @override @@ -71,4 +77,15 @@ class AppUserDataDatabase extends AppDatabase { await db.delete('userdata'); } + + static FutureOr migrate( + Database db, + int oldVersion, + int newVersion, + ) async { + final batch = db.batch() + ..execute('DROP TABLE IF EXISTS userdata') + ..execute('CREATE TABLE userdata(name TEXT, value TEXT)'); + await batch.commit(); + } } From d460c0679b7bf575ce2c839a767119f77f5345d0 Mon Sep 17 00:00:00 2001 From: vitormpp Date: Thu, 8 Aug 2024 18:50:12 +0100 Subject: [PATCH 22/99] fix: correct mistake by changing startTime to finishTime --- .../uni_app/lib/view/exams/widgets/exam_row.dart | 2 +- .../test/unit/view/Widgets/exam_row_test.dart | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/uni_app/lib/view/exams/widgets/exam_row.dart b/packages/uni_app/lib/view/exams/widgets/exam_row.dart index c47e6c0bd..abacd5686 100644 --- a/packages/uni_app/lib/view/exams/widgets/exam_row.dart +++ b/packages/uni_app/lib/view/exams/widgets/exam_row.dart @@ -40,7 +40,7 @@ class _ExamRowState extends State { Widget build(BuildContext context) { final roomsKey = '${widget.exam.subject}-${widget.exam.rooms}-${widget.exam.startTime}-' - '${widget.exam.startTime}'; + '${widget.exam.finishTime}'; return Center( child: Container( padding: const EdgeInsets.only(left: 12, bottom: 8, right: 12), diff --git a/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart b/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart index 379512ad1..be4483997 100644 --- a/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart +++ b/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart @@ -13,24 +13,24 @@ void main() async { group('Exam Row', () { const subject = 'SOPE'; - final begin = DateTime( + final start = DateTime( DateTime.now().year, DateTime.now().month, DateTime.now().day, 10, ); - final end = DateTime( + final finish = DateTime( DateTime.now().year, DateTime.now().month, DateTime.now().day, 12, ); - final beginTime = DateFormat('HH:mm').format(begin); - final endTime = DateFormat('HH:mm').format(end); + final startTime = DateFormat('HH:mm').format(start); + final finishTime = DateFormat('HH:mm').format(finish); testWidgets('When given a single room', (tester) async { final rooms = ['B315']; - final exam = Exam('1230', begin, end, subject, rooms, '', 'feup'); + final exam = Exam('1230', start, finish, subject, rooms, '', 'feup'); final widget = ExamRow( exam: exam, teacher: '', @@ -44,7 +44,7 @@ void main() async { await tester.pumpWidget(testableWidget(widget, providers: providers)); await tester.pump(); - final roomsKey = '$subject-$rooms-$beginTime-$endTime'; + final roomsKey = '$subject-$rooms-$startTime-$finishTime'; expect( find.descendant( @@ -57,7 +57,7 @@ void main() async { testWidgets('When multiple rooms', (tester) async { final rooms = ['B315', 'B316', 'B330']; - final exam = Exam('1230', begin, end, subject, rooms, '', 'feup'); + final exam = Exam('1230', start, finish, subject, rooms, '', 'feup'); final widget = ExamRow( exam: exam, teacher: '', @@ -72,7 +72,7 @@ void main() async { await tester.pumpWidget(testableWidget(widget, providers: providers)); await tester.pump(); - final roomsKey = '$subject-$rooms-$beginTime-$endTime'; + final roomsKey = '$subject-$rooms-$startTime-$finishTime'; expect( find.descendant( From e20681e364d0b042a50ee89d0a081b0ca8dedab7 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 2 Sep 2024 19:02:26 +0000 Subject: [PATCH 23/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 339705b9a..608caaff6 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.24+287 +1.9.0-beta.25+288 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index df57cc422..ec16b61d5 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.24+287 +version: 1.9.0-beta.25+288 environment: sdk: ">=3.4.0 <4.0.0" From 649dc963e626071e7c0b23df68e56ce242276087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 2 Sep 2024 23:10:00 +0100 Subject: [PATCH 24/99] feat: some more progress --- .../lib/http/client/authenticated.dart | 16 ++++++++--- .../uni_app/lib/session/base/initiator.dart | 3 +- .../uni_app/lib/session/base/request.dart | 2 +- .../uni_app/lib/session/base/session.dart | 27 ++++++++++++++++++ .../lib/session/credentials/initiator.dart | 4 ++- .../lib/session/credentials/session.dart | 14 ---------- .../{exceptions.dart => exception.dart} | 0 .../lib/session/federated/session.dart | 14 ---------- ...troller.dart => freshness_controller.dart} | 16 +++++------ .../uni_app/lib/session/logout_handler.dart | 20 +++++++++++++ packages/uni_app/lib/session/rejection.dart | 7 ----- .../lib/session/uni_logout_handler.dart | 28 +++++++++++++++++++ 12 files changed, 101 insertions(+), 50 deletions(-) rename packages/uni_app/lib/session/{exceptions.dart => exception.dart} (100%) rename packages/uni_app/lib/session/{controller.dart => freshness_controller.dart} (77%) create mode 100644 packages/uni_app/lib/session/logout_handler.dart delete mode 100644 packages/uni_app/lib/session/rejection.dart create mode 100644 packages/uni_app/lib/session/uni_logout_handler.dart diff --git a/packages/uni_app/lib/http/client/authenticated.dart b/packages/uni_app/lib/http/client/authenticated.dart index 6fbdbe02d..f55909d02 100644 --- a/packages/uni_app/lib/http/client/authenticated.dart +++ b/packages/uni_app/lib/http/client/authenticated.dart @@ -6,16 +6,17 @@ import 'package:logger/logger.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/http/client/cookie.dart'; import 'package:uni/session/base/session.dart'; -import 'package:uni/session/controller.dart'; +import 'package:uni/session/exception.dart'; +import 'package:uni/session/freshness_controller.dart'; class AuthenticatedClient extends http.BaseClient { AuthenticatedClient( this._inner, { - required AuthenticationController controller, + required SessionFreshnessController controller, }) : _controller = controller; final http.Client _inner; - final AuthenticationController _controller; + final SessionFreshnessController _controller; /// Check if the user is still logged in, /// performing a health check on the user's personal page. @@ -55,7 +56,14 @@ class AuthenticatedClient extends http.BaseClient { }, ); - return client.send(request); + final response = await client.send(request); + + if (response.statusCode == 403 && + !await _isUserLoggedIn(snapshot.session)) { + throw const AuthenticationException('User is not logged in SIGARRA'); + } + + return response; } @override diff --git a/packages/uni_app/lib/session/base/initiator.dart b/packages/uni_app/lib/session/base/initiator.dart index bb0522aac..19a592fa4 100644 --- a/packages/uni_app/lib/session/base/initiator.dart +++ b/packages/uni_app/lib/session/base/initiator.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:http/http.dart' as http; import 'package:uni/session/base/request.dart'; /// In the authentication flow, the [SessionInitiator] is the component @@ -10,5 +11,5 @@ import 'package:uni/session/base/request.dart'; /// initiator. An initiator only needs to be able to create a [SessionRequest] /// and is not responsible for the actual authentication of the user. abstract class SessionInitiator { - FutureOr initiate(); + FutureOr initiate([http.Client? httpClient]); } diff --git a/packages/uni_app/lib/session/base/request.dart b/packages/uni_app/lib/session/base/request.dart index 40b53c91c..a20fd5762 100644 --- a/packages/uni_app/lib/session/base/request.dart +++ b/packages/uni_app/lib/session/base/request.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:http/http.dart' as http; import 'package:uni/session/base/initiator.dart'; import 'package:uni/session/base/session.dart'; -import 'package:uni/session/exceptions.dart'; +import 'package:uni/session/exception.dart'; /// In the authentication flow, a [SessionRequest] is the component responsible /// for performing the actual authentication of the user. A [SessionRequest] diff --git a/packages/uni_app/lib/session/base/session.dart b/packages/uni_app/lib/session/base/session.dart index 8b3ee53b8..75400863f 100644 --- a/packages/uni_app/lib/session/base/session.dart +++ b/packages/uni_app/lib/session/base/session.dart @@ -1,9 +1,17 @@ +import 'dart:async'; import 'dart:io'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; import 'package:json_annotation/json_annotation.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:uni/http/client/cookie.dart'; import 'package:uni/session/base/request.dart'; import 'package:uni/session/credentials/session.dart'; import 'package:uni/session/federated/session.dart'; +import 'package:uni/sigarra/endpoints/html/authentication.dart' + as authentication; +import 'package:uni/sigarra/options.dart'; const _sessionsFromJson = [ FederatedSession.fromJson, @@ -43,6 +51,25 @@ abstract class Session { String get mainFaculty => faculties.first; SessionRequest createRefreshRequest(); + + /// Executed when the authorization provided by this session is rejected. + /// + /// This is useful for performing cleanup operations, such as invalidating + /// session cookies, since they will no longer be used. + @mustCallSuper + FutureOr onRejection([http.Client? httpClient]) async { + final client = httpClient ?? http.Client(); + + try { + await authentication.logout( + options: FacultyRequestOptions( + client: CookieClient(client, cookies: () => cookies), + ), + ); + } catch (err, st) { + unawaited(Sentry.captureException(err, stackTrace: st)); + } + } } class CookieConverter implements JsonConverter { diff --git a/packages/uni_app/lib/session/credentials/initiator.dart b/packages/uni_app/lib/session/credentials/initiator.dart index f39b0764a..2523bb22e 100644 --- a/packages/uni_app/lib/session/credentials/initiator.dart +++ b/packages/uni_app/lib/session/credentials/initiator.dart @@ -1,3 +1,4 @@ +import 'package:http/http.dart' as http; import 'package:uni/session/base/initiator.dart'; import 'package:uni/session/credentials/request.dart'; @@ -11,7 +12,8 @@ class CredentialsSessionInitiator extends SessionInitiator { final String password; @override - CredentialsSessionRequest initiate() => CredentialsSessionRequest( + CredentialsSessionRequest initiate([http.Client? httpClient]) => + CredentialsSessionRequest( username: username, password: password, ); diff --git a/packages/uni_app/lib/session/credentials/session.dart b/packages/uni_app/lib/session/credentials/session.dart index 17c099b6b..3437352ff 100644 --- a/packages/uni_app/lib/session/credentials/session.dart +++ b/packages/uni_app/lib/session/credentials/session.dart @@ -30,18 +30,4 @@ class CredentialsSession extends Session { username: username, password: password, ); - - // @override - // Future close() async { - // await super.close(); - - // final url = '${NetworkRouter.getBaseUrl(faculties[0])}vld_validacao.sair'; - // final response = await http.get(url.toUri()); // TODO: make use of UniClient - - // if (response.statusCode == 200) { - // Logger().i('Logout Successful'); - // } else { - // Logger().i('Logout Failed'); - // } - // } } diff --git a/packages/uni_app/lib/session/exceptions.dart b/packages/uni_app/lib/session/exception.dart similarity index 100% rename from packages/uni_app/lib/session/exceptions.dart rename to packages/uni_app/lib/session/exception.dart diff --git a/packages/uni_app/lib/session/federated/session.dart b/packages/uni_app/lib/session/federated/session.dart index ac383b85e..fa0e786a4 100644 --- a/packages/uni_app/lib/session/federated/session.dart +++ b/packages/uni_app/lib/session/federated/session.dart @@ -28,18 +28,4 @@ class FederatedSession extends Session { FederatedSessionRequest createRefreshRequest() => FederatedSessionRequest( credential: credential, ); - - // @override - // Future close() async { - // await super.close(); - - // final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); - // final logoutUri = credential.generateLogoutUrl(redirectUri: homeUri); - - // if (logoutUri == null) { - // throw Exception('Failed to generate logout url'); - // } - - // await launchUrl(logoutUri); - // } } diff --git a/packages/uni_app/lib/session/controller.dart b/packages/uni_app/lib/session/freshness_controller.dart similarity index 77% rename from packages/uni_app/lib/session/controller.dart rename to packages/uni_app/lib/session/freshness_controller.dart index 633f5f5f5..d6f297fe2 100644 --- a/packages/uni_app/lib/session/controller.dart +++ b/packages/uni_app/lib/session/freshness_controller.dart @@ -3,33 +3,33 @@ import 'dart:async'; import 'package:synchronized/synchronized.dart'; import 'package:uni/session/base/session.dart'; -class AuthenticationSnapshot { - AuthenticationSnapshot( +class SessionSnapshot { + SessionSnapshot( this.session, { - required Future Function(AuthenticationSnapshot) invalidate, + required Future Function(SessionSnapshot) invalidate, }) : _invalidate = invalidate; final Session session; - final Future Function(AuthenticationSnapshot) _invalidate; + final Future Function(SessionSnapshot) _invalidate; Future invalidate() => _invalidate(this); } -class AuthenticationController { - AuthenticationController(this._session); +class SessionFreshnessController { + SessionFreshnessController(this._session); Session _session; final Lock _authenticationLock = Lock(); Future? _nextAuthentication; - Future get snapshot async { + Future get snapshot async { final nextAuthentication = _nextAuthentication; if (nextAuthentication != null) { await nextAuthentication; } - return AuthenticationSnapshot( + return SessionSnapshot( _session, invalidate: (snapshot) => _invalidate(snapshot.session), ); diff --git a/packages/uni_app/lib/session/logout_handler.dart b/packages/uni_app/lib/session/logout_handler.dart new file mode 100644 index 000000000..9d6e7d8ce --- /dev/null +++ b/packages/uni_app/lib/session/logout_handler.dart @@ -0,0 +1,20 @@ +import 'dart:async'; + +import 'package:uni/session/base/session.dart'; +import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/federated/session.dart'; + +abstract class LogoutHandler { + FutureOr closeCredentialsSession(CredentialsSession session) {} + FutureOr closeFederatedSession(FederatedSession session) {} + + FutureOr close(Session session) { + if (session is FederatedSession) { + return closeFederatedSession(session); + } else if (session is CredentialsSession) { + return closeCredentialsSession(session); + } else { + throw Exception('Unknown session type'); + } + } +} diff --git a/packages/uni_app/lib/session/rejection.dart b/packages/uni_app/lib/session/rejection.dart deleted file mode 100644 index 968ec67a2..000000000 --- a/packages/uni_app/lib/session/rejection.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'dart:async'; - -import 'package:uni/session/base/request.dart'; - -abstract interface class SessionRejectionHandler { - FutureOr onSessionRejected(SessionRequest request); -} diff --git a/packages/uni_app/lib/session/uni_logout_handler.dart b/packages/uni_app/lib/session/uni_logout_handler.dart new file mode 100644 index 000000000..0ab3d7f14 --- /dev/null +++ b/packages/uni_app/lib/session/uni_logout_handler.dart @@ -0,0 +1,28 @@ +import 'dart:async'; + +import 'package:uni/session/base/session.dart'; +import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/logout_handler.dart'; +import 'package:uni/view/navigation_service.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class UniLogoutHandler extends LogoutHandler { + @override + FutureOr closeFederatedSession(FederatedSession session) async { + final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); + final logoutUri = + session.credential.generateLogoutUrl(redirectUri: homeUri); + + if (logoutUri == null) { + throw Exception('Failed to generate logout url'); + } + + await launchUrl(logoutUri); + } + + @override + FutureOr close(Session session) { + NavigationService.logoutAndPopHistory(); + return super.close(session); + } +} From f9f52fb984fdad6234e3784a09bf84b136945cc5 Mon Sep 17 00:00:00 2001 From: thePeras Date: Wed, 4 Sep 2024 15:27:42 +0100 Subject: [PATCH 25/99] chore: upgrade download-artifact --- .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 10027b6a0..792f41516 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -147,7 +147,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Get App Bundle - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: appbundle From 7b8a4d65ffd7dc083a609d716b384c37a6cd3f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 00:31:43 +0100 Subject: [PATCH 26/99] feat: some more stuff --- packages/uni_app/lib/controller/cleanup.dart | 1 - .../fetchers/faculties_fetcher.dart | 8 +-- .../lib/http/client/authenticated.dart | 1 + .../providers/startup/session_provider.dart | 51 ++----------------- .../lib/session/federated/request.dart | 1 - .../lib/sigarra/endpoints/oidc/token.dart | 2 +- packages/uni_app/lib/view/login/login.dart | 28 +++++++--- 7 files changed, 33 insertions(+), 59 deletions(-) diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index ea7b1cd8d..d831d9cb2 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -13,7 +13,6 @@ import 'package:uni/controller/local_storage/database/app_last_user_info_update_ import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_providers.dart'; Future cleanupStoredData(BuildContext context) async { diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index dc99c0059..61a4fe9e8 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -4,8 +4,8 @@ import 'package:uni/session/base/session.dart'; Future> getStudentFaculties(Session session) async { final response = await NetworkRouter.getWithCookies( - 'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina', - {'pct_codigo': session.username}, + 'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina?pct_codigo=${session.username}', + {}, session, ); @@ -18,7 +18,9 @@ Future> getStudentFaculties(Session session) async { // The user is enrolled in a single faculty, // and the selection page is skipped. // We can extract the faculty from any anchor. - final singleFaculty = document.querySelector('a')!.attributes['href']!; + final singleFaculty = document + .querySelector('head link[rel="canonical"]')! + .attributes['href']!; final uri = Uri.parse(singleFaculty); final faculty = uri.pathSegments[0]; return [faculty.toLowerCase()]; diff --git a/packages/uni_app/lib/http/client/authenticated.dart b/packages/uni_app/lib/http/client/authenticated.dart index f55909d02..f16b262cb 100644 --- a/packages/uni_app/lib/http/client/authenticated.dart +++ b/packages/uni_app/lib/http/client/authenticated.dart @@ -58,6 +58,7 @@ class AuthenticatedClient extends http.BaseClient { final response = await client.send(request); + // TODO(limwa): extract this logic to a method if (response.statusCode == 403 && !await _isUserLoggedIn(snapshot.session)) { throw const AuthenticationException('User is not logged in SIGARRA'); diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index dba89c0be..4ecadf130 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -1,18 +1,13 @@ import 'dart:async'; -import 'package:logger/logger.dart'; -import 'package:openid_client/openid_client.dart'; import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/session/base/request.dart'; +import 'package:uni/session/base/initiator.dart'; import 'package:uni/session/base/session.dart'; -import 'package:uni/session/federated/request.dart'; -import 'package:uni/utils/constants.dart'; -import 'package:url_launcher/url_launcher.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() @@ -35,21 +30,16 @@ class SessionProvider extends StateProviderNotifier { } final request = state!.createRefreshRequest(); - return request.perform(); - } + final newState = await request.perform(); - static Future _invoke(Uri uri) async { - if (await canLaunchUrl(uri)) { - await launchUrl(uri, mode: LaunchMode.inAppBrowserView); - } else { - Logger().e('Could not launch $uri'); - } + return newState; } Future login( - SessionRequest request, { + SessionInitiator initiator, { required bool persistentSession, }) async { + final request = await initiator.initiate(); final session = await request.perform(); setState(session); @@ -65,35 +55,4 @@ class SessionProvider extends StateProviderNotifier { await acceptTermsAndConditions(); } - - Future federatedAuthentication({ - required Future onAuthentication, - required bool persistentSession, - }) async { - final issuer = await Issuer.discover(Uri.parse(realm)); - final client = Client( - issuer, - clientId, - ); - - final flow = Flow.authorizationCodeWithPKCE( - client, - scopes: [ - 'openid', - 'profile', - 'email', - 'offline_access', - 'audience', - 'uporto_data', - ], - )..redirectUri = Uri.parse('pt.up.fe.ni.uni://auth'); - - await _invoke(flow.authenticationUri); - final uri = await onAuthentication; - - final credential = await flow.callback(uri.queryParameters); - - final request = FederatedSessionRequest(credential: credential); - await login(request, persistentSession: persistentSession); - } } diff --git a/packages/uni_app/lib/session/federated/request.dart b/packages/uni_app/lib/session/federated/request.dart index 844af32b3..da6a3b9ea 100644 --- a/packages/uni_app/lib/session/federated/request.dart +++ b/packages/uni_app/lib/session/federated/request.dart @@ -1,6 +1,5 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; -import 'package:openid_client/openid_client_browser.dart'; import 'package:uni/session/base/request.dart'; import 'package:uni/session/federated/session.dart'; import 'package:uni/sigarra/endpoints/oidc.dart' as oidc; diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart index 7a2ca5991..0e9a09d04 100644 --- a/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart +++ b/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart @@ -13,7 +13,7 @@ Future> getCookies({ options = options ?? BaseRequestOptions(); final tokenUrl = options.baseUrl.resolve('auth/oidc/token'); - final response = await options.client.post( + final response = await options.client.get( tokenUrl, headers: { 'Content-Type': 'application/json', diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index 5d0bcec89..272063c7c 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.dart @@ -12,7 +12,9 @@ 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/session/credentials/request.dart'; +import 'package:uni/session/credentials/initiator.dart'; +import 'package:uni/session/federated/initiator.dart'; +import 'package:uni/utils/constants.dart'; import 'package:uni/utils/navigation_items.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; import 'package:uni/view/home/widgets/exit_app_dialog.dart'; @@ -89,9 +91,10 @@ class LoginPageViewState extends State _loggingIn = true; }); - final request = - CredentialsSessionRequest(username: user, password: pass); - await sessionProvider.login(request, persistentSession: _keepSignedIn); + final initiator = + CredentialsSessionInitiator(username: user, password: pass); + await sessionProvider.login(initiator, + persistentSession: _keepSignedIn); usernameController.clear(); passwordController.clear(); @@ -151,9 +154,20 @@ class LoginPageViewState extends State _loggingIn = true; }); - final uri = getInterceptedUri(); - await sessionProvider.federatedAuthentication( - onAuthentication: uri, + await sessionProvider.login( + FederatedSessionInitiator( + clientId: clientId, + realm: Uri.parse(realm), + redirectUri: Uri.parse('pt.up.fe.ni.uni://auth'), + performAuthentication: (flow) async { + final interceptedUri = getInterceptedUri(); + + final authenticationUri = flow.authenticationUri; + await launchUrl(authenticationUri); + + return interceptedUri; + }, + ), persistentSession: _keepSignedIn, ); From 806179d54ddc72f9478a593f25fd9eab35e673cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:37:20 +0100 Subject: [PATCH 27/99] feat: some more work --- .../background_workers/notifications.dart | 2 +- .../notifications/tuition_notification.dart | 2 +- packages/uni_app/lib/controller/cleanup.dart | 12 +-- .../fetchers/calendar_fetcher_html.dart | 2 +- .../all_course_units_fetcher.dart | 2 +- .../course_units_info_fetcher.dart | 2 +- .../current_course_units_fetcher.dart | 2 +- .../controller/fetchers/courses_fetcher.dart | 2 +- .../lib/controller/fetchers/exam_fetcher.dart | 2 +- .../fetchers/faculties_fetcher.dart | 10 +-- .../lib/controller/fetchers/fees_fetcher.dart | 2 +- .../fetchers/library_occupation_fetcher.dart | 2 +- .../controller/fetchers/print_fetcher.dart | 2 +- .../controller/fetchers/profile_fetcher.dart | 2 +- .../fetchers/reference_fetcher.dart | 2 +- .../fetchers/restaurant_fetcher.dart | 2 +- .../schedule_fetcher/schedule_fetcher.dart | 2 +- .../schedule_fetcher_api.dart | 2 +- .../schedule_fetcher_html.dart | 2 +- .../fetchers/session_dependant_fetcher.dart | 2 +- .../local_storage/database/app_database.dart | 3 +- .../local_storage/file_offline_storage.dart | 2 +- .../local_storage/preferences_controller.dart | 2 +- .../controller/networking/network_router.dart | 19 ++++- .../parsers/parser_course_unit_info.dart | 2 +- .../parsers/parser_schedule_html.dart | 2 +- .../entities/course_units/course_unit.g.dart | 2 +- .../session/credentials/request.g.dart | 21 ----- .../{ => flows}/credentials/session.g.dart | 2 +- .../{ => flows}/federated/session.g.dart | 2 +- .../lib/http/client/authenticated.dart | 8 +- .../entities/course_units/course_unit.dart | 4 +- .../lazy/course_units_info_provider.dart | 25 ++++-- .../model/providers/lazy/exam_provider.dart | 2 +- .../providers/lazy/lecture_provider.dart | 2 +- .../providers/startup/profile_provider.dart | 2 +- .../providers/startup/session_provider.dart | 4 +- .../controller/authentication_controller.dart | 17 +++++ .../idle_authentication_controller.dart | 16 ++++ .../refreshing_authentication_controller.dart | 76 +++++++++++++++++++ .../throwing_authentication_controller.dart | 10 +++ .../session/{ => flows}/base/initiator.dart | 2 +- .../lib/session/{ => flows}/base/request.dart | 4 +- .../lib/session/{ => flows}/base/session.dart | 6 +- .../{ => flows}/credentials/initiator.dart | 4 +- .../{ => flows}/credentials/request.dart | 8 +- .../{ => flows}/credentials/session.dart | 6 +- .../{ => flows}/federated/initiator.dart | 6 +- .../{ => flows}/federated/request.dart | 4 +- .../{ => flows}/federated/session.dart | 6 +- .../lib/session/freshness_controller.dart | 60 --------------- .../session/{ => logout}/logout_handler.dart | 6 +- .../{ => logout}/uni_logout_handler.dart | 14 ++-- .../view/common_widgets/faculty_filter.dart | 2 +- .../widgets/course_unit_student_row.dart | 2 +- packages/uni_app/lib/view/login/login.dart | 10 ++- .../integration/src/exams2_page_test.dart | 2 +- .../test/integration/src/exams_page_test.dart | 2 +- .../integration/src/schedule_page_test.dart | 2 +- .../src/schedule_page_test.mocks.dart | 26 +------ .../lecture_provider_test.mocks.dart | 2 +- .../unit/providers/exams_provider_test.dart | 2 +- .../unit/providers/lecture_provider_test.dart | 2 +- 63 files changed, 248 insertions(+), 211 deletions(-) delete mode 100644 packages/uni_app/lib/generated/session/credentials/request.g.dart rename packages/uni_app/lib/generated/session/{ => flows}/credentials/session.g.dart (93%) rename packages/uni_app/lib/generated/session/{ => flows}/federated/session.g.dart (94%) create mode 100644 packages/uni_app/lib/session/controller/authentication_controller.dart create mode 100644 packages/uni_app/lib/session/controller/idle_authentication_controller.dart create mode 100644 packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart create mode 100644 packages/uni_app/lib/session/controller/throwing_authentication_controller.dart rename packages/uni_app/lib/session/{ => flows}/base/initiator.dart (91%) rename packages/uni_app/lib/session/{ => flows}/base/request.dart (86%) rename packages/uni_app/lib/session/{ => flows}/base/session.dart (92%) rename packages/uni_app/lib/session/{ => flows}/credentials/initiator.dart (78%) rename packages/uni_app/lib/session/{ => flows}/credentials/request.dart (83%) rename packages/uni_app/lib/session/{ => flows}/credentials/session.dart (79%) rename packages/uni_app/lib/session/{ => flows}/federated/initiator.dart (86%) rename packages/uni_app/lib/session/{ => flows}/federated/request.dart (92%) rename packages/uni_app/lib/session/{ => flows}/federated/session.dart (79%) delete mode 100644 packages/uni_app/lib/session/freshness_controller.dart rename packages/uni_app/lib/session/{ => logout}/logout_handler.dart (73%) rename packages/uni_app/lib/session/{ => logout}/uni_logout_handler.dart (51%) diff --git a/packages/uni_app/lib/controller/background_workers/notifications.dart b/packages/uni_app/lib/controller/background_workers/notifications.dart index 4adf48fad..5b8fa88c1 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications.dart @@ -10,7 +10,7 @@ import 'package:tuple/tuple.dart'; import 'package:uni/controller/background_workers/notifications/tuition_notification.dart'; import 'package:uni/controller/local_storage/notification_timeout_storage.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:workmanager/workmanager.dart'; /// diff --git a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart index 30a8bc636..076fe5dff 100644 --- a/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart +++ b/packages/uni_app/lib/controller/background_workers/notifications/tuition_notification.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/fees_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/controller/parsers/parser_fees.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:uni/utils/duration_string_formatter.dart'; class TuitionNotification extends Notification { diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index d831d9cb2..39135a3cf 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -14,13 +14,15 @@ import 'package:uni/controller/local_storage/database/app_lectures_database.dart import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/model/providers/state_providers.dart'; +import 'package:uni/session/logout/uni_logout_handler.dart'; Future cleanupStoredData(BuildContext context) async { final providers = StateProviders.fromContext(context); - // final session = providers.sessionProvider.state; - // if (session != null) { - // unawaited(session.close()); - // } + + final session = providers.sessionProvider.state; + if (session != null) { + await UniLogoutHandler().close(session); + } providers.invalidate(); @@ -35,8 +37,6 @@ Future cleanupStoredData(BuildContext context) async { AppLastUserInfoUpdateDatabase().deleteLastUpdate(), AppBusStopDatabase().deleteBusStops(), AppCourseUnitsDatabase().deleteCourseUnits(), - // if (session != null) - // NetworkRouter.killSigarraAuthentication(session.faculties), PreferencesController.removeSavedSession(), ]); diff --git a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart index bf9f5f598..e83a29ba9 100644 --- a/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/calendar_fetcher_html.dart @@ -2,7 +2,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_calendar.dart'; import 'package:uni/model/entities/calendar_event.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Fetch the school calendar from HTML class CalendarFetcherHtml implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart index 647a237a1..a018b55f6 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/all_course_units_fetcher.dart @@ -2,7 +2,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_course_units.dart'; import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class AllCourseUnitsFetcher { Future?> getAllCourseUnitsAndCourseAverages( diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart index e73e6e5c6..6e43e026d 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/course_units_info_fetcher.dart @@ -6,7 +6,7 @@ import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class CourseUnitsInfoFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart index 10ee0ac03..4fc1fb48e 100644 --- a/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/course_units_fetcher/current_course_units_fetcher.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class CurrentCourseUnitsFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart index dea680b85..88b5eae7b 100644 --- a/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/courses_fetcher.dart @@ -2,7 +2,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/course_units/course_unit.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Returns the user's current list of [CourseUnit]. class CoursesFetcher implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart index b574922a5..8d79b3ece 100644 --- a/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/exam_fetcher.dart @@ -4,7 +4,7 @@ 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'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class ExamFetcher implements SessionDependantFetcher { ExamFetcher(this.courses, this.userUcs); diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index 61a4fe9e8..d5666b237 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -1,11 +1,11 @@ import 'package:html/parser.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; Future> getStudentFaculties(Session session) async { final response = await NetworkRouter.getWithCookies( - 'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina?pct_codigo=${session.username}', - {}, + 'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina', + {'pct_codigo': session.username}, session, ); @@ -18,9 +18,7 @@ Future> getStudentFaculties(Session session) async { // The user is enrolled in a single faculty, // and the selection page is skipped. // We can extract the faculty from any anchor. - final singleFaculty = document - .querySelector('head link[rel="canonical"]')! - .attributes['href']!; + final singleFaculty = document.querySelector('a')!.attributes['href']!; final uri = Uri.parse(singleFaculty); final faculty = uri.pathSegments[0]; return [faculty.toLowerCase()]; diff --git a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart index bea9c06b2..15bd4a43d 100644 --- a/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/fees_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class FeesFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 2f54e3092..494358eed 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -2,7 +2,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_library_occupation.dart'; import 'package:uni/model/entities/library_occupation.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Fetch the library occupation from Google Sheets class LibraryOccupationFetcherSheets implements SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart index e0b437eb6..92df3e9ea 100644 --- a/packages/uni_app/lib/controller/fetchers/print_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/print_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class PrintFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart index df8c7dc31..9ef6d85fa 100644 --- a/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/profile_fetcher.dart @@ -3,7 +3,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_courses.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class ProfileFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart index c860f4350..841b82735 100644 --- a/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/reference_fetcher.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart'; import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class ReferenceFetcher implements SessionDependantFetcher { @override diff --git a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart index 0e1572fdb..979759046 100644 --- a/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/restaurant_fetcher.dart @@ -1,7 +1,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_restaurants.dart'; import 'package:uni/model/entities/restaurant.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the menu class RestaurantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index 599e50741..a9b943430 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -2,7 +2,7 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's schedule. abstract class ScheduleFetcher extends SessionDependantFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index 8981cb887..79abe0af6 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -5,7 +5,7 @@ import 'package:uni/controller/parsers/parser_schedule.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's lectures from the faculties' API. class ScheduleFetcherApi extends ScheduleFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart index be920c026..ca1cda491 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_html.dart @@ -6,7 +6,7 @@ import 'package:uni/controller/parsers/parser_schedule_html.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's lectures from the schedule's HTML page. class ScheduleFetcherHtml extends ScheduleFetcher { diff --git a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart index c87d56dae..727f59e79 100644 --- a/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/session_dependant_fetcher.dart @@ -1,4 +1,4 @@ -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; abstract class SessionDependantFetcher { List getEndpoints(Session session); diff --git a/packages/uni_app/lib/controller/local_storage/database/app_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_database.dart index ab0916ea2..15c683b22 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_database.dart @@ -41,8 +41,7 @@ abstract class AppDatabase { /// Getter to determine if the session is persistent. Future get persistentSession async { - _persistentSession ??= - await PreferencesController.getSavedSession() != null; + _persistentSession ??= await PreferencesController.isSessionPersistent(); return _persistentSession!; } diff --git a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart index c0b939852..2835afece 100644 --- a/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart +++ b/packages/uni_app/lib/controller/local_storage/file_offline_storage.dart @@ -6,7 +6,7 @@ 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/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// The offline image storage location on the device. Future get _localPath async { diff --git a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart index 334568eb2..5c54bcef2 100644 --- a/packages/uni_app/lib/controller/local_storage/preferences_controller.dart +++ b/packages/uni_app/lib/controller/local_storage/preferences_controller.dart @@ -7,7 +7,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/exam.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:uni/utils/favorite_widget_type.dart'; /// Manages the app's Shared Preferences. diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 7e5b0b607..5bba7a445 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -5,8 +5,8 @@ import 'package:http/http.dart' as http; import 'package:logger/logger.dart'; import 'package:uni/http/client/cookie.dart'; import 'package:uni/http/utils.dart'; -import 'package:uni/session/base/session.dart'; -import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/flows/credentials/session.dart'; import 'package:uni/utils/constants.dart'; extension UriString on String { @@ -101,7 +101,7 @@ class NetworkRouter { static Future getWithCookies( String url, - Map headers, + Map query, Session session, ) async { final client = CookieClient( @@ -109,6 +109,17 @@ class NetworkRouter { cookies: () => session.cookies, ); - return client.get(url.toUri(), headers: headers); + final parsedUrl = url.toUri(); + + final allQueryParameters = {...parsedUrl.queryParametersAll}; + for (final entry in query.entries) { + final existingValue = allQueryParameters[entry.key]; + allQueryParameters[entry.key] = [ + if (existingValue != null) ...existingValue, + entry.value, + ]; + } + + return client.get(parsedUrl.replace(queryParameters: allQueryParameters)); } } diff --git a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart index ca959c651..5e121ae2d 100644 --- a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart +++ b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart @@ -8,7 +8,7 @@ import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/course_unit_file.dart'; import 'package:uni/model/entities/course_units/course_unit_sheet.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; Future> parseFiles( http.Response response, diff --git a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart index edf630376..3bf55fe44 100644 --- a/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart +++ b/packages/uni_app/lib/controller/parsers/parser_schedule_html.dart @@ -7,7 +7,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/model/utils/time/weekday_mapper.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; Future> getOverlappedClasses( Session session, diff --git a/packages/uni_app/lib/generated/model/entities/course_units/course_unit.g.dart b/packages/uni_app/lib/generated/model/entities/course_units/course_unit.g.dart index 7244397de..dba0cfd22 100644 --- a/packages/uni_app/lib/generated/model/entities/course_units/course_unit.g.dart +++ b/packages/uni_app/lib/generated/model/entities/course_units/course_unit.g.dart @@ -9,7 +9,7 @@ part of '../../../../model/entities/course_units/course_unit.dart'; CourseUnit _$CourseUnitFromJson(Map json) => CourseUnit( abbreviation: json['ucurr_sigla'] as String, name: json['ucurr_nome'] as String, - occurrId: json['ocorr_id'] as int, + occurrId: json['ocorr_id'] as int?, id: json['ucurr_id'] as int? ?? 0, code: json['ucurr_codigo'] as String? ?? '', curricularYear: json['ano'] as int?, diff --git a/packages/uni_app/lib/generated/session/credentials/request.g.dart b/packages/uni_app/lib/generated/session/credentials/request.g.dart deleted file mode 100644 index 8d489640e..000000000 --- a/packages/uni_app/lib/generated/session/credentials/request.g.dart +++ /dev/null @@ -1,21 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../../../session/credentials/request.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -CredentialsSessionRequest _$CredentialsSessionRequestFromJson( - Map json) => - CredentialsSessionRequest( - username: json['username'] as String, - password: json['password'] as String, - ); - -Map _$CredentialsSessionRequestToJson( - CredentialsSessionRequest instance) => - { - 'username': instance.username, - 'password': instance.password, - }; diff --git a/packages/uni_app/lib/generated/session/credentials/session.g.dart b/packages/uni_app/lib/generated/session/flows/credentials/session.g.dart similarity index 93% rename from packages/uni_app/lib/generated/session/credentials/session.g.dart rename to packages/uni_app/lib/generated/session/flows/credentials/session.g.dart index f27b7036f..33f843bf5 100644 --- a/packages/uni_app/lib/generated/session/credentials/session.g.dart +++ b/packages/uni_app/lib/generated/session/flows/credentials/session.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of '../../../session/credentials/session.dart'; +part of '../../../../session/flows/credentials/session.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/packages/uni_app/lib/generated/session/federated/session.g.dart b/packages/uni_app/lib/generated/session/flows/federated/session.g.dart similarity index 94% rename from packages/uni_app/lib/generated/session/federated/session.g.dart rename to packages/uni_app/lib/generated/session/flows/federated/session.g.dart index 60f67726d..985164762 100644 --- a/packages/uni_app/lib/generated/session/federated/session.g.dart +++ b/packages/uni_app/lib/generated/session/flows/federated/session.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of '../../../session/federated/session.dart'; +part of '../../../../session/flows/federated/session.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/packages/uni_app/lib/http/client/authenticated.dart b/packages/uni_app/lib/http/client/authenticated.dart index f16b262cb..55db7ae1c 100644 --- a/packages/uni_app/lib/http/client/authenticated.dart +++ b/packages/uni_app/lib/http/client/authenticated.dart @@ -5,18 +5,18 @@ import 'package:http/retry.dart' show RetryClient; import 'package:logger/logger.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/http/client/cookie.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/controller/authentication_controller.dart'; import 'package:uni/session/exception.dart'; -import 'package:uni/session/freshness_controller.dart'; +import 'package:uni/session/flows/base/session.dart'; class AuthenticatedClient extends http.BaseClient { AuthenticatedClient( this._inner, { - required SessionFreshnessController controller, + required AuthenticationController controller, }) : _controller = controller; final http.Client _inner; - final SessionFreshnessController _controller; + final AuthenticationController _controller; /// Check if the user is still logged in, /// performing a health check on the user's personal page. diff --git a/packages/uni_app/lib/model/entities/course_units/course_unit.dart b/packages/uni_app/lib/model/entities/course_units/course_unit.dart index 82846fc79..6d3d4a8ec 100644 --- a/packages/uni_app/lib/model/entities/course_units/course_unit.dart +++ b/packages/uni_app/lib/model/entities/course_units/course_unit.dart @@ -27,7 +27,7 @@ class CourseUnit { _$CourseUnitFromJson(json); @JsonKey(name: 'ucurr_id') - int id; + int? id; @JsonKey(name: 'ucurr_codigo') String code; @JsonKey(name: 'ucurr_sigla') @@ -37,7 +37,7 @@ class CourseUnit { @JsonKey(name: 'ano') int? curricularYear; @JsonKey(name: 'ocorr_id') - int occurrId; + int? occurrId; @JsonKey(name: 'per_codigo') String? semesterCode; @JsonKey(name: 'per_nome') diff --git a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart index 0fedd14d4..37665631a 100644 --- a/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/course_units_info_provider.dart @@ -8,7 +8,7 @@ import 'package:uni/model/entities/course_units/course_unit_directory.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; typedef SheetsMap = Map; typedef ClassesMap = Map>; @@ -38,16 +38,26 @@ class CourseUnitsInfoProvider CourseUnit courseUnit, Session session, ) async { + final occurrId = courseUnit.occurrId; + if (occurrId == null) { + return; + } + state!.item1[courseUnit] = - await CourseUnitsInfoFetcher().fetchSheet(session, courseUnit.occurrId); + await CourseUnitsInfoFetcher().fetchSheet(session, occurrId); } Future fetchCourseUnitClasses( CourseUnit courseUnit, Session session, ) async { + final occurrId = courseUnit.occurrId; + if (occurrId == null) { + return; + } + state!.item2[courseUnit] = await CourseUnitsInfoFetcher() - .fetchCourseUnitClasses(session, courseUnit.occurrId); + .fetchCourseUnitClasses(session, occurrId); notifyListeners(); } @@ -55,8 +65,13 @@ class CourseUnitsInfoProvider CourseUnit courseUnit, Session session, ) async { - state!.item3[courseUnit] = await CourseUnitsInfoFetcher() - .fetchCourseUnitFiles(session, courseUnit.occurrId); + final occurrId = courseUnit.occurrId; + if (occurrId == null) { + return; + } + + state!.item3[courseUnit] = + await CourseUnitsInfoFetcher().fetchCourseUnitFiles(session, occurrId); notifyListeners(); } diff --git a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart index 7e72ce346..b85eed4fc 100644 --- a/packages/uni_app/lib/model/providers/lazy/exam_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/exam_provider.dart @@ -8,7 +8,7 @@ import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class ExamProvider extends StateProviderNotifier> { ExamProvider() : super(cacheDuration: const Duration(days: 1)); diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index ed67e43c7..7fea2e42e 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -8,7 +8,7 @@ import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class LectureProvider extends StateProviderNotifier> { LectureProvider() : super(cacheDuration: const Duration(hours: 6)); diff --git a/packages/uni_app/lib/model/providers/startup/profile_provider.dart b/packages/uni_app/lib/model/providers/startup/profile_provider.dart index 8c4f75939..ad4ef1b02 100644 --- a/packages/uni_app/lib/model/providers/startup/profile_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/profile_provider.dart @@ -18,7 +18,7 @@ import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class ProfileProvider extends StateProviderNotifier { ProfileProvider() diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 4ecadf130..23d528f9b 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -6,8 +6,8 @@ import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/session/base/initiator.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/initiator.dart'; +import 'package:uni/session/flows/base/session.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() diff --git a/packages/uni_app/lib/session/controller/authentication_controller.dart b/packages/uni_app/lib/session/controller/authentication_controller.dart new file mode 100644 index 000000000..5e60bb74e --- /dev/null +++ b/packages/uni_app/lib/session/controller/authentication_controller.dart @@ -0,0 +1,17 @@ +import 'package:uni/session/flows/base/session.dart'; + +class AuthenticationSnapshot { + AuthenticationSnapshot( + this.session, { + required Future Function() invalidate, + }) : _invalidate = invalidate; + + final Session session; + final Future Function() _invalidate; + + Future invalidate() => _invalidate(); +} + +abstract class AuthenticationController { + Future get snapshot; +} diff --git a/packages/uni_app/lib/session/controller/idle_authentication_controller.dart b/packages/uni_app/lib/session/controller/idle_authentication_controller.dart new file mode 100644 index 000000000..40358ca6c --- /dev/null +++ b/packages/uni_app/lib/session/controller/idle_authentication_controller.dart @@ -0,0 +1,16 @@ +import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/flows/base/session.dart'; + +class IdleAuthenticationController extends AuthenticationController { + IdleAuthenticationController(this._session); + + final Session _session; + + @override + Future get snapshot => Future.value( + AuthenticationSnapshot( + _session, + invalidate: () async {}, + ), + ); +} diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart new file mode 100644 index 000000000..966f42d5e --- /dev/null +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -0,0 +1,76 @@ +import 'package:synchronized/synchronized.dart'; +import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/exception.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/logout/logout_handler.dart'; + +class RefreshingAuthenticationController extends AuthenticationController { + RefreshingAuthenticationController( + Session initialSession, { + this.logoutHandler, + }) : _currentSession = initialSession; + + final LogoutHandler? logoutHandler; + final Lock _authenticationLock = Lock(); + + Future? _nextAuthentication; + Session _currentSession; + + @override + Future get snapshot async { + final nextAuthentication = _nextAuthentication; + if (nextAuthentication != null) { + await nextAuthentication; + } + + final snapshottedSession = _currentSession; + return AuthenticationSnapshot( + snapshottedSession, + invalidate: () => _invalidate(snapshottedSession), + ); + } + + Future invalidate() async { + final currentSnapshot = await snapshot; + await currentSnapshot.invalidate(); + } + + bool _shouldInvalidate(Session session) { + // We invalidate if the is not an invalidation in progress already + // and the session is the same as the current one. + return _nextAuthentication == null && _currentSession == session; + } + + Future _invalidate(Session session) async { + // This check is intentionally used twice to avoid unnecessary lock + // acquisitions. + if (!_shouldInvalidate(session)) { + return; + } + + await _authenticationLock.synchronized(() { + // After the lock is acquired, the condition could have changed if + // another thread has already invalidated the session. + if (!_shouldInvalidate(session)) { + return; + } + + _nextAuthentication = _reauthenticate(); + }); + } + + Future _reauthenticate() async { + try { + final request = _currentSession.createRefreshRequest(); + _currentSession = await request.perform(); + + // If the reauthentication is successful, we indicate that the + // invalidation is no longer in progress and another one can be + // performed. + await _authenticationLock.synchronized(() => _nextAuthentication = null); + } on AuthenticationException { + await logoutHandler?.close(_currentSession); + rethrow; + } catch (_) {} + } +} diff --git a/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart b/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart new file mode 100644 index 000000000..a34ed2bd9 --- /dev/null +++ b/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart @@ -0,0 +1,10 @@ +import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/exception.dart'; + +class ThrowingAuthenticationController extends AuthenticationController { + @override + Future get snapshot => + throw const AuthenticationException( + 'AuthenticationController is in idle', + ); +} diff --git a/packages/uni_app/lib/session/base/initiator.dart b/packages/uni_app/lib/session/flows/base/initiator.dart similarity index 91% rename from packages/uni_app/lib/session/base/initiator.dart rename to packages/uni_app/lib/session/flows/base/initiator.dart index 19a592fa4..76b636007 100644 --- a/packages/uni_app/lib/session/base/initiator.dart +++ b/packages/uni_app/lib/session/flows/base/initiator.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:http/http.dart' as http; -import 'package:uni/session/base/request.dart'; +import 'package:uni/session/flows/base/request.dart'; /// In the authentication flow, the [SessionInitiator] is the component /// responsible for handling the initial intention of the user to authenticate diff --git a/packages/uni_app/lib/session/base/request.dart b/packages/uni_app/lib/session/flows/base/request.dart similarity index 86% rename from packages/uni_app/lib/session/base/request.dart rename to packages/uni_app/lib/session/flows/base/request.dart index a20fd5762..597da13e5 100644 --- a/packages/uni_app/lib/session/base/request.dart +++ b/packages/uni_app/lib/session/flows/base/request.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'package:http/http.dart' as http; -import 'package:uni/session/base/initiator.dart'; -import 'package:uni/session/base/session.dart'; import 'package:uni/session/exception.dart'; +import 'package:uni/session/flows/base/initiator.dart'; +import 'package:uni/session/flows/base/session.dart'; /// In the authentication flow, a [SessionRequest] is the component responsible /// for performing the actual authentication of the user. A [SessionRequest] diff --git a/packages/uni_app/lib/session/base/session.dart b/packages/uni_app/lib/session/flows/base/session.dart similarity index 92% rename from packages/uni_app/lib/session/base/session.dart rename to packages/uni_app/lib/session/flows/base/session.dart index 75400863f..c442adf16 100644 --- a/packages/uni_app/lib/session/base/session.dart +++ b/packages/uni_app/lib/session/flows/base/session.dart @@ -6,9 +6,9 @@ import 'package:http/http.dart' as http; import 'package:json_annotation/json_annotation.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:uni/http/client/cookie.dart'; -import 'package:uni/session/base/request.dart'; -import 'package:uni/session/credentials/session.dart'; -import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/flows/base/request.dart'; +import 'package:uni/session/flows/credentials/session.dart'; +import 'package:uni/session/flows/federated/session.dart'; import 'package:uni/sigarra/endpoints/html/authentication.dart' as authentication; import 'package:uni/sigarra/options.dart'; diff --git a/packages/uni_app/lib/session/credentials/initiator.dart b/packages/uni_app/lib/session/flows/credentials/initiator.dart similarity index 78% rename from packages/uni_app/lib/session/credentials/initiator.dart rename to packages/uni_app/lib/session/flows/credentials/initiator.dart index 2523bb22e..0ce329d11 100644 --- a/packages/uni_app/lib/session/credentials/initiator.dart +++ b/packages/uni_app/lib/session/flows/credentials/initiator.dart @@ -1,6 +1,6 @@ import 'package:http/http.dart' as http; -import 'package:uni/session/base/initiator.dart'; -import 'package:uni/session/credentials/request.dart'; +import 'package:uni/session/flows/base/initiator.dart'; +import 'package:uni/session/flows/credentials/request.dart'; class CredentialsSessionInitiator extends SessionInitiator { CredentialsSessionInitiator({ diff --git a/packages/uni_app/lib/session/credentials/request.dart b/packages/uni_app/lib/session/flows/credentials/request.dart similarity index 83% rename from packages/uni_app/lib/session/credentials/request.dart rename to packages/uni_app/lib/session/flows/credentials/request.dart index 1e5c498b3..cf58254b8 100644 --- a/packages/uni_app/lib/session/credentials/request.dart +++ b/packages/uni_app/lib/session/flows/credentials/request.dart @@ -1,15 +1,11 @@ import 'package:http/http.dart' as http; -import 'package:json_annotation/json_annotation.dart'; import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/model/entities/login_exceptions.dart'; -import 'package:uni/session/base/request.dart'; -import 'package:uni/session/credentials/session.dart'; +import 'package:uni/session/flows/base/request.dart'; +import 'package:uni/session/flows/credentials/session.dart'; -part '../../generated/session/credentials/request.g.dart'; - -@JsonSerializable(explicitToJson: true) class CredentialsSessionRequest extends SessionRequest { CredentialsSessionRequest({ required this.username, diff --git a/packages/uni_app/lib/session/credentials/session.dart b/packages/uni_app/lib/session/flows/credentials/session.dart similarity index 79% rename from packages/uni_app/lib/session/credentials/session.dart rename to packages/uni_app/lib/session/flows/credentials/session.dart index 3437352ff..f3f3cffce 100644 --- a/packages/uni_app/lib/session/credentials/session.dart +++ b/packages/uni_app/lib/session/flows/credentials/session.dart @@ -1,8 +1,8 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:uni/session/base/session.dart'; -import 'package:uni/session/credentials/request.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/flows/credentials/request.dart'; -part '../../generated/session/credentials/session.g.dart'; +part '../../../generated/session/flows/credentials/session.g.dart'; @JsonSerializable(explicitToJson: true) class CredentialsSession extends Session { diff --git a/packages/uni_app/lib/session/federated/initiator.dart b/packages/uni_app/lib/session/flows/federated/initiator.dart similarity index 86% rename from packages/uni_app/lib/session/federated/initiator.dart rename to packages/uni_app/lib/session/flows/federated/initiator.dart index 363830a3c..6e7aff5fb 100644 --- a/packages/uni_app/lib/session/federated/initiator.dart +++ b/packages/uni_app/lib/session/flows/federated/initiator.dart @@ -1,8 +1,8 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; -import 'package:uni/session/base/initiator.dart'; -import 'package:uni/session/base/request.dart'; -import 'package:uni/session/federated/request.dart'; +import 'package:uni/session/flows/base/initiator.dart'; +import 'package:uni/session/flows/base/request.dart'; +import 'package:uni/session/flows/federated/request.dart'; class FederatedSessionInitiator extends SessionInitiator { FederatedSessionInitiator({ diff --git a/packages/uni_app/lib/session/federated/request.dart b/packages/uni_app/lib/session/flows/federated/request.dart similarity index 92% rename from packages/uni_app/lib/session/federated/request.dart rename to packages/uni_app/lib/session/flows/federated/request.dart index da6a3b9ea..1d4c255d7 100644 --- a/packages/uni_app/lib/session/federated/request.dart +++ b/packages/uni_app/lib/session/flows/federated/request.dart @@ -1,7 +1,7 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; -import 'package:uni/session/base/request.dart'; -import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/flows/base/request.dart'; +import 'package:uni/session/flows/federated/session.dart'; import 'package:uni/sigarra/endpoints/oidc.dart' as oidc; import 'package:uni/sigarra/options.dart'; diff --git a/packages/uni_app/lib/session/federated/session.dart b/packages/uni_app/lib/session/flows/federated/session.dart similarity index 79% rename from packages/uni_app/lib/session/federated/session.dart rename to packages/uni_app/lib/session/flows/federated/session.dart index fa0e786a4..e99c7cd4c 100644 --- a/packages/uni_app/lib/session/federated/session.dart +++ b/packages/uni_app/lib/session/flows/federated/session.dart @@ -1,9 +1,9 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:openid_client/openid_client.dart'; -import 'package:uni/session/base/session.dart'; -import 'package:uni/session/federated/request.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/flows/federated/request.dart'; -part '../../generated/session/federated/session.g.dart'; +part '../../../generated/session/flows/federated/session.g.dart'; @JsonSerializable(explicitToJson: true) class FederatedSession extends Session { diff --git a/packages/uni_app/lib/session/freshness_controller.dart b/packages/uni_app/lib/session/freshness_controller.dart deleted file mode 100644 index d6f297fe2..000000000 --- a/packages/uni_app/lib/session/freshness_controller.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'dart:async'; - -import 'package:synchronized/synchronized.dart'; -import 'package:uni/session/base/session.dart'; - -class SessionSnapshot { - SessionSnapshot( - this.session, { - required Future Function(SessionSnapshot) invalidate, - }) : _invalidate = invalidate; - - final Session session; - final Future Function(SessionSnapshot) _invalidate; - - Future invalidate() => _invalidate(this); -} - -class SessionFreshnessController { - SessionFreshnessController(this._session); - - Session _session; - - final Lock _authenticationLock = Lock(); - Future? _nextAuthentication; - - Future get snapshot async { - final nextAuthentication = _nextAuthentication; - if (nextAuthentication != null) { - await nextAuthentication; - } - - return SessionSnapshot( - _session, - invalidate: (snapshot) => _invalidate(snapshot.session), - ); - } - - Future _invalidate(Session session) async { - // This check is intentionally used twice to avoid unnecessary lock - // acquisitions. - if (_nextAuthentication != null || _session != session) { - return; - } - - await _authenticationLock.synchronized(() { - if (_nextAuthentication != null || _session != session) { - return; - } - - _nextAuthentication = _reauthenticate(); - }); - } - - Future _reauthenticate() async { - final refreshRequest = _session.createRefreshRequest(); - _session = await refreshRequest.perform(); - - await _authenticationLock.synchronized(() => _nextAuthentication = null); - } -} diff --git a/packages/uni_app/lib/session/logout_handler.dart b/packages/uni_app/lib/session/logout/logout_handler.dart similarity index 73% rename from packages/uni_app/lib/session/logout_handler.dart rename to packages/uni_app/lib/session/logout/logout_handler.dart index 9d6e7d8ce..05eb75fa5 100644 --- a/packages/uni_app/lib/session/logout_handler.dart +++ b/packages/uni_app/lib/session/logout/logout_handler.dart @@ -1,8 +1,8 @@ import 'dart:async'; -import 'package:uni/session/base/session.dart'; -import 'package:uni/session/credentials/session.dart'; -import 'package:uni/session/federated/session.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/flows/credentials/session.dart'; +import 'package:uni/session/flows/federated/session.dart'; abstract class LogoutHandler { FutureOr closeCredentialsSession(CredentialsSession session) {} diff --git a/packages/uni_app/lib/session/uni_logout_handler.dart b/packages/uni_app/lib/session/logout/uni_logout_handler.dart similarity index 51% rename from packages/uni_app/lib/session/uni_logout_handler.dart rename to packages/uni_app/lib/session/logout/uni_logout_handler.dart index 0ab3d7f14..b06960639 100644 --- a/packages/uni_app/lib/session/uni_logout_handler.dart +++ b/packages/uni_app/lib/session/logout/uni_logout_handler.dart @@ -1,18 +1,14 @@ import 'dart:async'; -import 'package:uni/session/base/session.dart'; -import 'package:uni/session/federated/session.dart'; -import 'package:uni/session/logout_handler.dart'; -import 'package:uni/view/navigation_service.dart'; +import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/flows/federated/session.dart'; +import 'package:uni/session/logout/logout_handler.dart'; import 'package:url_launcher/url_launcher.dart'; class UniLogoutHandler extends LogoutHandler { @override FutureOr closeFederatedSession(FederatedSession session) async { - final homeUri = Uri.parse('pt.up.fe.ni.uni://home'); - final logoutUri = - session.credential.generateLogoutUrl(redirectUri: homeUri); - + final logoutUri = session.credential.generateLogoutUrl(); if (logoutUri == null) { throw Exception('Failed to generate logout url'); } @@ -22,7 +18,7 @@ class UniLogoutHandler extends LogoutHandler { @override FutureOr close(Session session) { - NavigationService.logoutAndPopHistory(); + // NavigationService.logoutAndPopHistory(); return super.close(session); } } diff --git a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart index 5843166cf..bc2d50ecb 100644 --- a/packages/uni_app/lib/view/common_widgets/faculty_filter.dart +++ b/packages/uni_app/lib/view/common_widgets/faculty_filter.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class FacultyFilter extends StatelessWidget { const FacultyFilter({ diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart index 9333c370b..c50a2f297 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_student_row.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:uni/model/entities/course_units/course_unit_class.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; class CourseUnitStudentRow extends StatelessWidget { const CourseUnitStudentRow(this.student, this.session, {super.key}); diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index 272063c7c..32dff3968 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.dart @@ -12,8 +12,8 @@ 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/session/credentials/initiator.dart'; -import 'package:uni/session/federated/initiator.dart'; +import 'package:uni/session/flows/credentials/initiator.dart'; +import 'package:uni/session/flows/federated/initiator.dart'; import 'package:uni/utils/constants.dart'; import 'package:uni/utils/navigation_items.dart'; import 'package:uni/view/common_widgets/toast_message.dart'; @@ -93,8 +93,10 @@ class LoginPageViewState extends State final initiator = CredentialsSessionInitiator(username: user, password: pass); - await sessionProvider.login(initiator, - persistentSession: _keepSignedIn); + await sessionProvider.login( + initiator, + persistentSession: _keepSignedIn, + ); usernameController.clear(); passwordController.clear(); diff --git a/packages/uni_app/test/integration/src/exams2_page_test.dart b/packages/uni_app/test/integration/src/exams2_page_test.dart index e67e74a55..b51a9feb6 100644 --- a/packages/uni_app/test/integration/src/exams2_page_test.dart +++ b/packages/uni_app/test/integration/src/exams2_page_test.dart @@ -14,7 +14,7 @@ import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:uni/view/exams/exams.dart'; import '../../mocks/integration/src/exams_page_test.mocks.dart'; diff --git a/packages/uni_app/test/integration/src/exams_page_test.dart b/packages/uni_app/test/integration/src/exams_page_test.dart index 7ed5057ba..d50a6382e 100644 --- a/packages/uni_app/test/integration/src/exams_page_test.dart +++ b/packages/uni_app/test/integration/src/exams_page_test.dart @@ -13,7 +13,7 @@ import 'package:uni/model/entities/course_units/course_unit.dart'; import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:uni/view/exams/exams.dart'; import '../../mocks/integration/src/exams_page_test.mocks.dart'; diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart index 82f788309..dea0a258a 100644 --- a/packages/uni_app/test/integration/src/schedule_page_test.dart +++ b/packages/uni_app/test/integration/src/schedule_page_test.dart @@ -12,7 +12,7 @@ import 'package:uni/model/entities/course.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import 'package:uni/view/schedule/schedule.dart'; import '../../mocks/integration/src/schedule_page_test.mocks.dart'; diff --git a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart index 4166b8def..fa380a0db 100644 --- a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart +++ b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart @@ -15,8 +15,8 @@ import 'package:mockito/src/dummies.dart' as _i5; import 'package:uni/model/providers/startup/session_provider.dart' as _i7; import 'package:uni/model/providers/state_providers.dart' as _i10; import 'package:uni/model/request_status.dart' as _i8; -import 'package:uni/session/request.dart' as _i11; -import 'package:uni/session/session.dart' as _i9; +import 'package:uni/session/flows/base/initiator.dart' as _i11; +import 'package:uni/session/flows/base/session.dart' as _i9; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -495,37 +495,19 @@ class MockSessionProvider extends _i1.Mock implements _i7.SessionProvider { @override _i3.Future login( - _i11.SessionRequest? request, { + _i11.SessionInitiator? initiator, { required bool? persistentSession, }) => (super.noSuchMethod( Invocation.method( #login, - [request], + [initiator], {#persistentSession: persistentSession}, ), returnValue: _i3.Future.value(), returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); - @override - _i3.Future federatedAuthentication({ - required _i3.Future? onAuthentication, - required bool? persistentSession, - }) => - (super.noSuchMethod( - Invocation.method( - #federatedAuthentication, - [], - { - #onAuthentication: onAuthentication, - #persistentSession: persistentSession, - }, - ), - returnValue: _i3.Future.value(), - returnValueForMissingStub: _i3.Future.value(), - ) as _i3.Future); - @override void setState(_i9.Session? newState) => super.noSuchMethod( Invocation.method( diff --git a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart index 32fb701a4..2eaa1d40f 100644 --- a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart +++ b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart @@ -15,7 +15,7 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart' import 'package:uni/model/entities/lecture.dart' as _i5; import 'package:uni/model/entities/profile.dart' as _i7; import 'package:uni/model/utils/time/week.dart' as _i8; -import 'package:uni/session/session.dart' as _i6; +import 'package:uni/session/flows/base/session.dart' as _i6; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values diff --git a/packages/uni_app/test/unit/providers/exams_provider_test.dart b/packages/uni_app/test/unit/providers/exams_provider_test.dart index b39382980..d11f72ecd 100644 --- a/packages/uni_app/test/unit/providers/exams_provider_test.dart +++ b/packages/uni_app/test/unit/providers/exams_provider_test.dart @@ -10,7 +10,7 @@ import 'package:uni/model/entities/exam.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/exam_provider.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import '../../mocks/unit/providers/exams_provider_test.mocks.dart'; import '../../test_widget.dart'; diff --git a/packages/uni_app/test/unit/providers/lecture_provider_test.dart b/packages/uni_app/test/unit/providers/lecture_provider_test.dart index d1aeed512..03fe4dc5a 100644 --- a/packages/uni_app/test/unit/providers/lecture_provider_test.dart +++ b/packages/uni_app/test/unit/providers/lecture_provider_test.dart @@ -9,7 +9,7 @@ import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/lazy/lecture_provider.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/session/base/session.dart'; +import 'package:uni/session/flows/base/session.dart'; import '../../mocks/unit/providers/lecture_provider_test.mocks.dart'; import '../../test_widget.dart'; From 5ba3985a4524a81a0b1d5e683a95e4db81c02999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:47:30 +0100 Subject: [PATCH 28/99] fix: indefinite waiting with no internet --- .../refreshing_authentication_controller.dart | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index 966f42d5e..c6a8c2c8c 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -60,17 +60,30 @@ class RefreshingAuthenticationController extends AuthenticationController { } Future _reauthenticate() async { + Future releaseLock() => + _authenticationLock.synchronized(() => _nextAuthentication = null); + + final currentSession = _currentSession; try { - final request = _currentSession.createRefreshRequest(); + final request = currentSession.createRefreshRequest(); _currentSession = await request.perform(); // If the reauthentication is successful, we indicate that the // invalidation is no longer in progress and another one can be // performed. - await _authenticationLock.synchronized(() => _nextAuthentication = null); - } on AuthenticationException { - await logoutHandler?.close(_currentSession); + await releaseLock(); + } catch (err) { + if (err is! AuthenticationException) { + // If the error thrown is not an authentication exception, + // for instance, a network error, we need to release the lock to + // ensure that future accesses to a snapshot will not block + // indefinitely. + await releaseLock(); + rethrow; + } + + await logoutHandler?.close(currentSession); rethrow; - } catch (_) {} + } } } From f1e3b8601903fffefea23da84cb29acebd2fc3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:50:44 +0100 Subject: [PATCH 29/99] docs: explain controller behavior --- .../controller/refreshing_authentication_controller.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index c6a8c2c8c..70f64f2da 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -82,6 +82,11 @@ class RefreshingAuthenticationController extends AuthenticationController { rethrow; } + // After the authentication attempt fails due to invalid credentials, + // we don't allow this authentication controller to create any other + // snapshots. + // Futhermore, we use the logout handler to signal to the app that the + // user must be logged out. await logoutHandler?.close(currentSession); rethrow; } From 43657738a6ae660d949a3283c0bd447ccad5b74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:51:21 +0100 Subject: [PATCH 30/99] style: reorder lines --- .../controller/refreshing_authentication_controller.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index 70f64f2da..3807394b5 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -60,10 +60,11 @@ class RefreshingAuthenticationController extends AuthenticationController { } Future _reauthenticate() async { + final currentSession = _currentSession; + Future releaseLock() => _authenticationLock.synchronized(() => _nextAuthentication = null); - final currentSession = _currentSession; try { final request = currentSession.createRefreshRequest(); _currentSession = await request.perform(); From 8c9a2781326697abd0c76036b23d1ea46b356524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:53:21 +0100 Subject: [PATCH 31/99] refactor: make message more accurate --- .../controller/throwing_authentication_controller.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart b/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart index a34ed2bd9..e4da44cfa 100644 --- a/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart @@ -4,7 +4,5 @@ import 'package:uni/session/exception.dart'; class ThrowingAuthenticationController extends AuthenticationController { @override Future get snapshot => - throw const AuthenticationException( - 'AuthenticationController is in idle', - ); + throw const AuthenticationException('ThrowingAuthenticationController'); } From 1a6876e28a82c9c7733c1ac0aa475ed8cfb82b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:54:28 +0100 Subject: [PATCH 32/99] refactor: clean up login --- packages/uni_app/lib/controller/cleanup.dart | 9 +-------- .../uni_app/lib/session/logout/uni_logout_handler.dart | 3 ++- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index 39135a3cf..bcfd77747 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -17,14 +17,7 @@ import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/session/logout/uni_logout_handler.dart'; Future cleanupStoredData(BuildContext context) async { - final providers = StateProviders.fromContext(context); - - final session = providers.sessionProvider.state; - if (session != null) { - await UniLogoutHandler().close(session); - } - - providers.invalidate(); + StateProviders.fromContext(context).invalidate(); final prefs = await SharedPreferences.getInstance(); await prefs.clear(); diff --git a/packages/uni_app/lib/session/logout/uni_logout_handler.dart b/packages/uni_app/lib/session/logout/uni_logout_handler.dart index b06960639..4aa53dd58 100644 --- a/packages/uni_app/lib/session/logout/uni_logout_handler.dart +++ b/packages/uni_app/lib/session/logout/uni_logout_handler.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:uni/session/flows/base/session.dart'; import 'package:uni/session/flows/federated/session.dart'; import 'package:uni/session/logout/logout_handler.dart'; +import 'package:uni/view/navigation_service.dart'; import 'package:url_launcher/url_launcher.dart'; class UniLogoutHandler extends LogoutHandler { @@ -18,7 +19,7 @@ class UniLogoutHandler extends LogoutHandler { @override FutureOr close(Session session) { - // NavigationService.logoutAndPopHistory(); + NavigationService.logoutAndPopHistory(); return super.close(session); } } From 52586cddeddfd7bea71f0c13c480c92ed030341a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 5 Sep 2024 23:56:10 +0100 Subject: [PATCH 33/99] fix: bug reports for non-persisted sessions --- packages/uni_app/lib/controller/cleanup.dart | 1 - packages/uni_app/lib/view/bug_report/widgets/form.dart | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/controller/cleanup.dart b/packages/uni_app/lib/controller/cleanup.dart index bcfd77747..aba2c1e01 100644 --- a/packages/uni_app/lib/controller/cleanup.dart +++ b/packages/uni_app/lib/controller/cleanup.dart @@ -14,7 +14,6 @@ import 'package:uni/controller/local_storage/database/app_lectures_database.dart import 'package:uni/controller/local_storage/database/app_user_database.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/model/providers/state_providers.dart'; -import 'package:uni/session/logout/uni_logout_handler.dart'; Future cleanupStoredData(BuildContext context) async { StateProviders.fromContext(context).invalidate(); diff --git a/packages/uni_app/lib/view/bug_report/widgets/form.dart b/packages/uni_app/lib/view/bug_report/widgets/form.dart index 10bcc9b0a..a6b42abc3 100644 --- a/packages/uni_app/lib/view/bug_report/widgets/form.dart +++ b/packages/uni_app/lib/view/bug_report/widgets/form.dart @@ -8,6 +8,7 @@ import 'package:uni/controller/local_storage/preferences_controller.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; +import 'package:uni/model/providers/startup/session_provider.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'; @@ -245,9 +246,9 @@ class BugReportFormState extends State { setState(() { _isButtonTapped = true; }); - final savedSession = await PreferencesController.getSavedSession(); - final faculties = savedSession?.faculties ?? - []; // FIXME: get session from provider so that even non-persisted sessions can be used + + final session = Provider.of(context, listen: false).state; + final faculties = session?.faculties ?? []; final bugReport = BugReport( titleController.text, From 73798c18d51c1dcc693bfab24808499ce218a162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 6 Sep 2024 08:48:31 +0100 Subject: [PATCH 34/99] fix: don't throw on network errors --- .../refreshing_authentication_controller.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index 3807394b5..0502b353e 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -1,3 +1,7 @@ +import 'dart:async'; + +import 'package:logger/logger.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:synchronized/synchronized.dart'; import 'package:uni/session/controller/authentication_controller.dart'; import 'package:uni/session/exception.dart'; @@ -73,14 +77,19 @@ class RefreshingAuthenticationController extends AuthenticationController { // invalidation is no longer in progress and another one can be // performed. await releaseLock(); - } catch (err) { + } catch (err, st) { if (err is! AuthenticationException) { // If the error thrown is not an authentication exception, // for instance, a network error, we need to release the lock to // ensure that future accesses to a snapshot will not block // indefinitely. await releaseLock(); - rethrow; + + // Report the exception as it will not be thrown when + // awaiting a snapshot. + Logger().e('Failed to reauthenticate', error: err, stackTrace: st); + unawaited(Sentry.captureException(err, stackTrace: st)); + return; } // After the authentication attempt fails due to invalid credentials, From 8cbeba26a034a53e404a59804b08c6fcc5a35bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 6 Sep 2024 19:47:32 +0100 Subject: [PATCH 35/99] fix: schedule loading from storage --- .../local_storage/database/app_lectures_database.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart index 353e7e518..a7c1c7362 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart @@ -20,7 +20,7 @@ class AppLecturesDatabase extends AppDatabase> { ); static const createScript = ''' CREATE TABLE lectures(subject TEXT, typeClass TEXT, - startTime TEXT,endTime TEXT, blocks INTEGER, room TEXT, teacher TEXT, classNumber TEXT, occurrId INTEGER)'''; + startTime TEXT, endTime TEXT, blocks INTEGER, room TEXT, teacher TEXT, classNumber TEXT, occurrId INTEGER)'''; /// Returns a list containing all of the lectures stored in this database. Future> lectures() async { @@ -31,7 +31,7 @@ CREATE TABLE lectures(subject TEXT, typeClass TEXT, return Lecture.fromApi( maps[i]['subject'] as String, maps[i]['typeClass'] as String, - DateTime.parse(maps[i]['startDateTime'] as String), + DateTime.parse(maps[i]['startTime'] as String), maps[i]['blocks'] as int, maps[i]['room'] as String, maps[i]['teacher'] as String, From f2cb0593d0ceaf5e3c8b19f7ae71b42d44136683 Mon Sep 17 00:00:00 2001 From: limwa Date: Fri, 6 Sep 2024 19:09:41 +0000 Subject: [PATCH 36/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 608caaff6..aecea47fa 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.25+288 +1.9.0-beta.26+289 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index ec16b61d5..4c553a770 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.25+288 +version: 1.9.0-beta.26+289 environment: sdk: ">=3.4.0 <4.0.0" From 8e4372389da498f59952ff64194198023ebfe223 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sat, 7 Sep 2024 20:39:41 +0100 Subject: [PATCH 37/99] removing unecessary filter --- .../lib/controller/parsers/schedule/new_api/parser.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart index aaca33f16..2c8d06a71 100644 --- a/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart +++ b/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart @@ -29,12 +29,9 @@ List getLecturesFromApiResponse( final json = jsonDecode(response.body) as Map; final data = json['data'] as List; - final now = DateTime.now(); - return data .cast>() .map(ResponseLecture.fromJson) - .where((lecture) => lecture.end.isAfter(now)) .map( (lecture) => Lecture( lecture.units.first.acronym, From 5c2936be30cb5b7bd9bb0c21b7631394dbecbdc3 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 10 Sep 2024 15:47:37 +0000 Subject: [PATCH 38/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index aecea47fa..13f1d2736 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.26+289 +1.9.0-beta.27+290 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 4c553a770..7b4caec09 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.26+289 +version: 1.9.0-beta.27+290 environment: sdk: ">=3.4.0 <4.0.0" From 593a4cdd1c95ef8d99e85419a66294dec88b575f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 10 Sep 2024 17:16:26 +0100 Subject: [PATCH 39/99] dealing with a possible null url --- .../fetchers/schedule_fetcher/schedule_fetcher_new_api.dart | 4 ++++ .../lib/controller/parsers/schedule/new_api/parser.dart | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index 55b678836..2d8d38fb7 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -34,6 +34,10 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { final scheduleApiUrl = getScheduleApiUrlFromHtml(scheduleResponse); + if (scheduleApiUrl == null) { + return []; + } + final scheduleApiResponse = await NetworkRouter.getWithCookies( scheduleApiUrl, {}, diff --git a/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart b/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart index 2c8d06a71..2ce159628 100644 --- a/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart +++ b/packages/uni_app/lib/controller/parsers/schedule/new_api/parser.dart @@ -8,7 +8,7 @@ import 'package:uni/model/entities/lecture.dart'; /// Extracts the user's lecture API URL. /// /// This function parses the schedule's HTML page. -String getScheduleApiUrlFromHtml( +String? getScheduleApiUrlFromHtml( http.Response response, ) { final document = parse(response.body); @@ -16,10 +16,6 @@ String getScheduleApiUrlFromHtml( final scheduleElement = document.querySelector('#cal-shadow-container'); final apiUrl = scheduleElement?.attributes['data-evt-source-url']; - if (apiUrl == null) { - throw Exception('Could not find schedule API URL in schedule page'); - } - return apiUrl; } From 91a100b6cacb787e23bdbd0ab2405457b5c9e46f Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 10 Sep 2024 16:24:53 +0000 Subject: [PATCH 40/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 13f1d2736..0d582b7de 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.27+290 +1.9.0-beta.28+291 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 7b4caec09..50d15b612 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.27+290 +version: 1.9.0-beta.28+291 environment: sdk: ">=3.4.0 <4.0.0" From c73170c99d88045547263c0a4de1d90db4785c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Tue, 10 Sep 2024 20:26:29 +0100 Subject: [PATCH 41/99] refactor: some more work --- .../controller/networking/network_router.dart | 85 +++----------- .../api/authentication/login/json.g.dart | 13 +++ .../providers/startup/session_provider.dart | 26 ++++- .../controller/authentication_controller.dart | 2 + .../refreshing_authentication_controller.dart | 23 +++- .../lib/session/flows/base/session.dart | 36 +++--- .../session/flows/credentials/request.dart | 60 ++++++++-- .../lib/session/flows/federated/request.dart | 14 ++- .../uni_app/lib/sigarra/endpoints/api.dart | 8 +- .../sigarra/endpoints/api/authentication.dart | 23 +--- .../endpoints/api/authentication/login.dart | 54 +++++++++ .../api/authentication/login/json.dart | 19 +++ .../api/authentication/login/response.dart | 32 +++++ .../uni_app/lib/sigarra/endpoints/html.dart | 7 ++ .../endpoints/html/authentication.dart | 21 ++-- .../endpoints/html/authentication/login.dart | 110 ++++++++++++++++++ .../html/authentication/login/response.dart | 25 ++++ .../endpoints/html/authentication/logout.dart | 17 +++ .../uni_app/lib/sigarra/endpoints/oidc.dart | 8 +- .../lib/sigarra/endpoints/oidc/token.dart | 45 ++++--- .../endpoints/oidc/token/response.dart | 20 ++++ packages/uni_app/lib/sigarra/response.dart | 5 + packages/uni_app/lib/utils/derived.dart | 3 +- 23 files changed, 491 insertions(+), 165 deletions(-) create mode 100644 packages/uni_app/lib/generated/sigarra/endpoints/api/authentication/login/json.g.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/api/authentication/login/json.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/html.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart create mode 100644 packages/uni_app/lib/sigarra/endpoints/oidc/token/response.dart create mode 100644 packages/uni_app/lib/sigarra/response.dart diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 5bba7a445..cf70ebd0c 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -1,13 +1,10 @@ import 'dart:async'; -import 'dart:convert'; import 'package:http/http.dart' as http; -import 'package:logger/logger.dart'; -import 'package:uni/http/client/cookie.dart'; -import 'package:uni/http/utils.dart'; +import 'package:uni/http/client/authenticated.dart'; +import 'package:uni/http/client/timeout.dart'; +import 'package:uni/session/controller/authentication_controller.dart'; import 'package:uni/session/flows/base/session.dart'; -import 'package:uni/session/flows/credentials/session.dart'; -import 'package:uni/utils/constants.dart'; extension UriString on String { /// Converts a [String] to an [Uri]. @@ -21,69 +18,11 @@ class NetworkRouter { /// This is useful for testing. static http.Client? httpClient; + static AuthenticationController? authenticationController; + /// The timeout for Sigarra login requests. static const Duration _requestTimeout = Duration(seconds: 30); - /// Re-authenticates the user via the Sigarra API - /// using data stored in [session], - /// returning an updated Session if successful. - static Future reLoginFromSession(Session session) async { - final request = session.createRefreshRequest(); - try { - return request.perform(); - } catch (err, st) { - Logger().e(err, stackTrace: st); - return null; - } - } - - static Future login(String username, String password) async { - final url = '${getBaseUrl('feup')}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; - } - - final responseBody = json.decode(response.body) as Map; - if (!(responseBody['authenticated'] as bool)) { - Logger().e('Login failed: user not authenticated'); - return null; - } - - final realUsername = responseBody['codigo'] as String; - final session = CredentialsSession( - username: realUsername, - cookies: extractCookies(response), - faculties: faculties, - password: password, - ); - - Logger().i('Login successful'); - - return session; - } - - /// Returns the response body of the login in Sigarra - /// given username [user] and password [pass]. - static Future loginInSigarra( - String user, - String pass, - List faculties, - ) async { - 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; - } - /// Returns the base url of the user's faculties. static List getBaseUrls(List faculties) { return faculties.map(getBaseUrl).toList(); @@ -104,9 +43,17 @@ class NetworkRouter { Map query, Session session, ) async { - final client = CookieClient( - httpClient ?? http.Client(), - cookies: () => session.cookies, + final controller = authenticationController; + if (controller == null) { + throw Exception('Authentication controller not initialized'); + } + + final client = AuthenticatedClient( + TimeoutClient( + httpClient ?? http.Client(), + timeout: _requestTimeout, + ), + controller: controller, ); final parsedUrl = url.toUri(); diff --git a/packages/uni_app/lib/generated/sigarra/endpoints/api/authentication/login/json.g.dart b/packages/uni_app/lib/generated/sigarra/endpoints/api/authentication/login/json.g.dart new file mode 100644 index 000000000..b79f18918 --- /dev/null +++ b/packages/uni_app/lib/generated/sigarra/endpoints/api/authentication/login/json.g.dart @@ -0,0 +1,13 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../../../../../../sigarra/endpoints/api/authentication/login/json.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LoginJsonResponse _$LoginJsonResponseFromJson(Map json) => + LoginJsonResponse( + authenticated: json['authenticated'] as bool, + username: json['codigo'] as String, + ); diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index 23d528f9b..f795467c1 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -3,11 +3,15 @@ import 'dart:async'; import 'package:uni/controller/background_workers/notifications.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; import 'package:uni/controller/local_storage/preferences_controller.dart'; +import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; +import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/controller/refreshing_authentication_controller.dart'; import 'package:uni/session/flows/base/initiator.dart'; import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/logout/uni_logout_handler.dart'; class SessionProvider extends StateProviderNotifier { SessionProvider() @@ -17,9 +21,23 @@ class SessionProvider extends StateProviderNotifier { dependsOnSession: false, ); + AuthenticationController get controller => + NetworkRouter.authenticationController!; + + void initController(Session session) { + NetworkRouter.authenticationController = RefreshingAuthenticationController( + session, + logoutHandler: UniLogoutHandler(), + ); + } + @override Future loadFromStorage(StateProviders stateProviders) async { final session = await PreferencesController.getSavedSession(); + if (session != null) { + initController(session); + } + return session; } @@ -29,8 +47,11 @@ class SessionProvider extends StateProviderNotifier { return null; } - final request = state!.createRefreshRequest(); - final newState = await request.perform(); + final oldSnapshot = await controller.snapshot; + await oldSnapshot.invalidate(); + + final newSnapshot = await controller.snapshot; + final newState = newSnapshot.session; return newState; } @@ -42,6 +63,7 @@ class SessionProvider extends StateProviderNotifier { final request = await initiator.initiate(); final session = await request.perform(); + initController(session); setState(session); if (persistentSession) { diff --git a/packages/uni_app/lib/session/controller/authentication_controller.dart b/packages/uni_app/lib/session/controller/authentication_controller.dart index 5e60bb74e..50b768516 100644 --- a/packages/uni_app/lib/session/controller/authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/authentication_controller.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:uni/session/flows/base/session.dart'; class AuthenticationSnapshot { diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index 0502b353e..2ca9e0253 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -20,6 +20,10 @@ class RefreshingAuthenticationController extends AuthenticationController { Future? _nextAuthentication; Session _currentSession; + final _snapshotsController = + StreamController.broadcast(); + Stream get snapshots => _snapshotsController.stream; + @override Future get snapshot async { final nextAuthentication = _nextAuthentication; @@ -27,11 +31,7 @@ class RefreshingAuthenticationController extends AuthenticationController { await nextAuthentication; } - final snapshottedSession = _currentSession; - return AuthenticationSnapshot( - snapshottedSession, - invalidate: () => _invalidate(snapshottedSession), - ); + return _createSnapshot(_currentSession); } Future invalidate() async { @@ -39,6 +39,13 @@ class RefreshingAuthenticationController extends AuthenticationController { await currentSnapshot.invalidate(); } + AuthenticationSnapshot _createSnapshot(Session session) { + return AuthenticationSnapshot( + session, + invalidate: () => _invalidate(session), + ); + } + bool _shouldInvalidate(Session session) { // We invalidate if the is not an invalidation in progress already // and the session is the same as the current one. @@ -73,6 +80,8 @@ class RefreshingAuthenticationController extends AuthenticationController { final request = currentSession.createRefreshRequest(); _currentSession = await request.perform(); + _snapshotsController.add(_createSnapshot(_currentSession)); + // If the reauthentication is successful, we indicate that the // invalidation is no longer in progress and another one can be // performed. @@ -98,6 +107,10 @@ class RefreshingAuthenticationController extends AuthenticationController { // Futhermore, we use the logout handler to signal to the app that the // user must be logged out. await logoutHandler?.close(currentSession); + + _snapshotsController.addError(err, st); + unawaited(_snapshotsController.close()); + rethrow; } } diff --git a/packages/uni_app/lib/session/flows/base/session.dart b/packages/uni_app/lib/session/flows/base/session.dart index c442adf16..c670c9647 100644 --- a/packages/uni_app/lib/session/flows/base/session.dart +++ b/packages/uni_app/lib/session/flows/base/session.dart @@ -1,17 +1,9 @@ -import 'dart:async'; import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:http/http.dart' as http; import 'package:json_annotation/json_annotation.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:uni/http/client/cookie.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/credentials/session.dart'; import 'package:uni/session/flows/federated/session.dart'; -import 'package:uni/sigarra/endpoints/html/authentication.dart' - as authentication; -import 'package:uni/sigarra/options.dart'; const _sessionsFromJson = [ FederatedSession.fromJson, @@ -56,20 +48,20 @@ abstract class Session { /// /// This is useful for performing cleanup operations, such as invalidating /// session cookies, since they will no longer be used. - @mustCallSuper - FutureOr onRejection([http.Client? httpClient]) async { - final client = httpClient ?? http.Client(); - - try { - await authentication.logout( - options: FacultyRequestOptions( - client: CookieClient(client, cookies: () => cookies), - ), - ); - } catch (err, st) { - unawaited(Sentry.captureException(err, stackTrace: st)); - } - } + // @mustCallSuper + // FutureOr onRejection([http.Client? httpClient]) async { + // final client = httpClient ?? http.Client(); + + // try { + // await authentication.logout( + // options: FacultyRequestOptions( + // client: CookieClient(client, cookies: () => cookies), + // ), + // ); + // } catch (err, st) { + // unawaited(Sentry.captureException(err, stackTrace: st)); + // } + // } } class CookieConverter implements JsonConverter { diff --git a/packages/uni_app/lib/session/flows/credentials/request.dart b/packages/uni_app/lib/session/flows/credentials/request.dart index cf58254b8..44e3c5d47 100644 --- a/packages/uni_app/lib/session/flows/credentials/request.dart +++ b/packages/uni_app/lib/session/flows/credentials/request.dart @@ -1,10 +1,12 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/faculties_fetcher.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/parsers/parser_session.dart'; import 'package:uni/model/entities/login_exceptions.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/credentials/session.dart'; +import 'package:uni/sigarra/endpoints/api.dart'; +import 'package:uni/sigarra/endpoints/html.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/login/response.dart'; +import 'package:uni/sigarra/options.dart'; class CredentialsSessionRequest extends SessionRequest { CredentialsSessionRequest({ @@ -17,16 +19,18 @@ class CredentialsSessionRequest extends SessionRequest { @override Future perform([http.Client? httpClient]) async { - // TODO (limwa): Use client + final client = httpClient ?? http.Client(); + // We need to login to fetch the faculties, so perform a temporary login. - final tempSession = await NetworkRouter.login(username, password); + final tempSession = await _loginWithApi(username, password, client); if (tempSession == null) { // Get the fail reason. - final responseHtml = - await NetworkRouter.loginInSigarra(username, password, ['feup']); + final failureReason = + await _getLoginFailureReason(username, password, client); - if (isPasswordExpired(responseHtml)) { + // FIXME(limwa): convey the reason to the user + if (failureReason == LoginFailureReason.expiredCredentials) { throw ExpiredCredentialsException(); } else { throw WrongCredentialsException(); @@ -44,4 +48,46 @@ class CredentialsSessionRequest extends SessionRequest { return session; } + + Future _loginWithApi( + String username, + String password, + http.Client httpClient, + ) async { + final api = SigarraApi(); + + final loginResponse = await api.authentication.login.call( + username: username, + password: password, + options: FacultyRequestOptions(client: httpClient), + ); + + if (!loginResponse.success) { + return null; + } + + final info = loginResponse.asSuccessful(); + return CredentialsSession( + username: info.username, + password: password, + cookies: info.cookies, + faculties: ['up'], + ); + } + + Future _getLoginFailureReason( + String username, + String password, + http.Client httpClient, + ) async { + final html = SigarraHtml(); + final response = await html.authentication.login.call( + username: username, + password: password, + options: FacultyRequestOptions(client: httpClient), + ); + + final error = response.asFailed(); + return error.reason; + } } diff --git a/packages/uni_app/lib/session/flows/federated/request.dart b/packages/uni_app/lib/session/flows/federated/request.dart index 1d4c255d7..141583d84 100644 --- a/packages/uni_app/lib/session/flows/federated/request.dart +++ b/packages/uni_app/lib/session/flows/federated/request.dart @@ -1,8 +1,9 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; +import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/federated/session.dart'; -import 'package:uni/sigarra/endpoints/oidc.dart' as oidc; +import 'package:uni/sigarra/endpoints/oidc.dart'; import 'package:uni/sigarra/options.dart'; class FederatedSessionUserInfo { @@ -41,16 +42,23 @@ class FederatedSessionRequest extends SessionRequest { final userInfo = FederatedSessionUserInfo(await credential.getUserInfo()); final authorizedClient = credential.createHttpClient(httpClient); - final cookies = await oidc.getCookies( + + final oidc = SigarraOidc(); + final response = await oidc.token.call( options: BaseRequestOptions( client: authorizedClient, ), ); + if (!response.success) { + throw const AuthenticationException('Failed to get OIDC token'); + } + + final successfulResponse = response.asSuccessful(); return FederatedSession( username: userInfo.username, faculties: userInfo.faculties, - cookies: cookies, + cookies: successfulResponse.cookies, credential: credential, ); } diff --git a/packages/uni_app/lib/sigarra/endpoints/api.dart b/packages/uni_app/lib/sigarra/endpoints/api.dart index 36e7041a9..b0dbf53ad 100644 --- a/packages/uni_app/lib/sigarra/endpoints/api.dart +++ b/packages/uni_app/lib/sigarra/endpoints/api.dart @@ -1 +1,7 @@ -export 'api/authentication.dart'; +import 'package:uni/sigarra/endpoints/api/authentication.dart'; +import 'package:uni/utils/lazy.dart'; + +class SigarraApi { + final _authentication = Lazy(SigarraApiAuthentication.new); + SigarraApiAuthentication get authentication => _authentication.value; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart index 5cadfea6e..5bdc1f223 100644 --- a/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart @@ -1,20 +1,7 @@ -import 'package:http/http.dart' as http; -import 'package:uni/sigarra/options.dart'; +import 'package:uni/sigarra/endpoints/api/authentication/login.dart'; +import 'package:uni/utils/lazy.dart'; -Future login({ - required String username, - required String password, - FacultyRequestOptions? options, -}) { - options = options ?? FacultyRequestOptions(); - - final loginUrl = options.baseUrl.resolve('mob_val_geral.autentica'); - - return options.client.post( - loginUrl, - body: { - 'pv_login': username, - 'pv_password': password, - }, - ); +class SigarraApiAuthentication { + final _login = Lazy(() => const Login()); + Login get login => _login.value; } diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart new file mode 100644 index 000000000..a8e179203 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:uni/http/utils.dart'; +import 'package:uni/sigarra/endpoints/api/authentication/login/json.dart'; +import 'package:uni/sigarra/endpoints/api/authentication/login/response.dart'; +import 'package:uni/sigarra/options.dart'; + +class Login { + const Login(); + + Future call({ + required String username, + required String password, + required FacultyRequestOptions? options, + }) async { + options = options ?? FacultyRequestOptions(); + + final loginUrl = options.baseUrl.resolve('mob_val_geral.autentica'); + + final response = await options.client.post( + loginUrl, + body: { + 'pv_login': username, + 'pv_password': password, + }, + ); + + return _parse(response); + } + + Future _parse(http.Response response) async { + if (response.statusCode != 200) { + return const LoginFailedResponse( + reason: LoginFailureReason.serverError, + ); + } + + final responseBody = LoginJsonResponse.fromJson( + json.decode(response.body) as Map, + ); + + if (responseBody.authenticated) { + return LoginSuccessfulResponse( + username: responseBody.username, + cookies: extractCookies(response), + ); + } + + return const LoginFailedResponse( + reason: LoginFailureReason.unknown, + ); + } +} diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/json.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/json.dart new file mode 100644 index 000000000..7c907424e --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/json.dart @@ -0,0 +1,19 @@ +import 'package:json_annotation/json_annotation.dart'; + +part '../../../../../generated/sigarra/endpoints/api/authentication/login/json.g.dart'; + +@JsonSerializable(createToJson: false) +class LoginJsonResponse { + const LoginJsonResponse({ + required this.authenticated, + required this.username, + }); + + factory LoginJsonResponse.fromJson(Map json) => + _$LoginJsonResponseFromJson(json); + + final bool authenticated; + + @JsonKey(name: 'codigo') + final String username; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart new file mode 100644 index 000000000..e2f871e33 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart @@ -0,0 +1,32 @@ +import 'dart:io'; + +import 'package:uni/sigarra/response.dart'; + +abstract class LoginResponse extends SigarraResponse { + const LoginResponse({required super.success}); + + LoginSuccessfulResponse asSuccessful() => this as LoginSuccessfulResponse; + LoginFailedResponse asFailed() => this as LoginFailedResponse; +} + +class LoginSuccessfulResponse extends LoginResponse { + const LoginSuccessfulResponse({required this.username, required this.cookies}) + : super(success: true); + + final String username; + final List cookies; +} + +enum LoginFailureReason { + serverError, + unknown, +} + +class LoginFailedResponse extends LoginResponse { + const LoginFailedResponse({required this.reason}) : super(success: false); + + @override + bool get success => false; + + final LoginFailureReason reason; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/html.dart b/packages/uni_app/lib/sigarra/endpoints/html.dart new file mode 100644 index 000000000..9f92ce067 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/html.dart @@ -0,0 +1,7 @@ +import 'package:uni/sigarra/endpoints/html/authentication.dart'; +import 'package:uni/utils/lazy.dart'; + +class SigarraHtml { + final _authentication = Lazy(SigarraHtmlAuthentication.new); + SigarraHtmlAuthentication get authentication => _authentication.value; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart index cecac1649..90069160c 100644 --- a/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart @@ -1,16 +1,11 @@ -import 'package:uni/sigarra/options.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/login.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/logout.dart'; +import 'package:uni/utils/lazy.dart'; -Future logout({ - FacultyRequestOptions? options, -}) async { - options = options ?? FacultyRequestOptions(); +class SigarraHtmlAuthentication { + final _logout = Lazy(() => const Logout()); + Logout get logout => _logout.value; - final logoutUrl = options.baseUrl.resolve('vld_validacao.sair'); - final response = await options.client.get(logoutUrl); - - if (response.statusCode == 200) { - return; - } - - throw Exception('Failed to logout from SIGARRA'); + final _login = Lazy(() => const Login()); + Login get login => _login.value; } diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart new file mode 100644 index 000000000..a2760a4e2 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart @@ -0,0 +1,110 @@ +import 'dart:async'; + +import 'package:html/dom.dart' as html; +import 'package:html/parser.dart' as html_parser; +import 'package:http/http.dart' as http; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/login/response.dart'; +import 'package:uni/sigarra/options.dart'; + +class Login { + const Login(); + + Future call({ + required String username, + required String password, + FacultyRequestOptions? options, + }) async { + options = options ?? FacultyRequestOptions(); + + final loginUrl = options.baseUrl.resolve('vld_validacao.validacao'); + + final response = await options.client.post( + loginUrl, + body: { + 'p_user': username, + 'p_pass': password, + }, + ); + + return _parse(response); + } + + Future _parse(http.Response response) async { + if (response.statusCode != 200) { + return const LoginFailedResponse( + reason: LoginFailureReason.serverError, + ); + } + + final document = html_parser.parse(response.body); + + if (_isSucessfulResponse(document)) { + return const LoginResponse(success: true); + } + + final failureReason = _parseFailureReason(document); + return LoginFailedResponse(reason: failureReason); + } + + bool _isSucessfulResponse(html.Document document) { + final refresh = document.head?.querySelector("meta[http-equiv='refresh']"); + return refresh != null; + } + + LoginFailureReason _parseFailureReason(html.Document document) { + try { + final alert = document.body?.querySelector('p.aviso-invalidado')?.text; + if (alert != null) { + return _parseFailureReasonFromInvalidatedWarning(alert); + } + + final error = document.body?.querySelector('p.erro-nota')?.text; + if (error != null) { + return _parseFailureReasonFromErrorNote(error); + } + + throw Exception('Could not find failure reason'); + } catch (err, st) { + unawaited( + Sentry.captureException( + SentryEvent( + throwable: err, + request: SentryRequest( + data: document.outerHtml, + ), + ), + stackTrace: st, + ), + ); + + return LoginFailureReason.unknown; + } + } + + LoginFailureReason _parseFailureReasonFromInvalidatedWarning(String warning) { + if (warning.contains('expirad')) { + unawaited( + Sentry.captureMessage( + 'Invalidated warning: expired credentials -> "$warning"', + ), + ); + return LoginFailureReason.expiredCredentials; + } + + return switch (warning) { + 'O conjunto utilizador/senha não é válido.' => + LoginFailureReason.wrongCredentials, + 'A sua conta encontra-se bloqueada.' => LoginFailureReason.blockedAccount, + _ => throw Exception('Unknown invalidated warning: "$warning"'), + }; + } + + LoginFailureReason _parseFailureReasonFromErrorNote(String error) { + if (error.startsWith('Já se encontra autenticado com o utilizador')) { + return LoginFailureReason.alreadyLoggedIn; + } + + throw Exception('Unknown error note: "$error"'); + } +} diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart new file mode 100644 index 000000000..c5e436175 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart @@ -0,0 +1,25 @@ +import 'package:uni/sigarra/response.dart'; + +class LoginResponse extends SigarraResponse { + const LoginResponse({required super.success}); + + LoginFailedResponse asFailed() => this as LoginFailedResponse; +} + +enum LoginFailureReason { + serverError, + wrongCredentials, + expiredCredentials, + blockedAccount, + alreadyLoggedIn, + unknown, +} + +class LoginFailedResponse extends LoginResponse { + const LoginFailedResponse({required this.reason}) : super(success: false); + + @override + bool get success => false; + + final LoginFailureReason reason; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart new file mode 100644 index 000000000..f52fa1039 --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart @@ -0,0 +1,17 @@ +import 'package:uni/sigarra/options.dart'; +import 'package:uni/sigarra/response.dart'; + +class Logout { + const Logout(); + + Future call({ + FacultyRequestOptions? options, + }) async { + options = options ?? FacultyRequestOptions(); + + final logoutUrl = options.baseUrl.resolve('vld_validacao.sair'); + final response = await options.client.get(logoutUrl); + + return SigarraResponse(success: response.statusCode == 200); + } +} diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc.dart b/packages/uni_app/lib/sigarra/endpoints/oidc.dart index c298d4659..3f9792644 100644 --- a/packages/uni_app/lib/sigarra/endpoints/oidc.dart +++ b/packages/uni_app/lib/sigarra/endpoints/oidc.dart @@ -1 +1,7 @@ -export 'oidc/token.dart'; +import 'package:uni/sigarra/endpoints/oidc/token.dart'; +import 'package:uni/utils/lazy.dart'; + +class SigarraOidc { + final _token = Lazy(Token.new); + Token get token => _token.value; +} diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart index 0e9a09d04..309dd1de2 100644 --- a/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart +++ b/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart @@ -1,31 +1,30 @@ -import 'dart:convert'; -import 'dart:io'; - import 'package:uni/http/utils.dart'; +import 'package:uni/sigarra/endpoints/oidc/token/response.dart'; import 'package:uni/sigarra/options.dart'; -/// Returns the cookies for SIGARRA using the OIDC token. -/// -/// The client must be authorized to make this request. -Future> getCookies({ - BaseRequestOptions? options, -}) async { - options = options ?? BaseRequestOptions(); +class Token { + const Token(); + + /// Returns the cookies for SIGARRA using the OIDC token. + /// + /// The client must be authorized to make this request. + Future call({ + BaseRequestOptions? options, + }) async { + options = options ?? BaseRequestOptions(); - final tokenUrl = options.baseUrl.resolve('auth/oidc/token'); - final response = await options.client.get( - tokenUrl, - headers: { - 'Content-Type': 'application/json', - }, - ); + final tokenUrl = options.baseUrl.resolve('auth/oidc/token'); + final response = await options.client.get( + tokenUrl, + headers: { + 'Content-Type': 'application/json', + }, + ); - if (response.statusCode == 200) { - final body = jsonDecode(response.body) as Map; - if (body['result'] == 'OK') { - return extractCookies(response); + if (response.statusCode == 200) { + return TokenSuccessfulResponse(cookies: extractCookies(response)); } - } - throw Exception('Failed to get token from SIGARRA'); + return const TokenFailedResponse(); + } } diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc/token/response.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/token/response.dart new file mode 100644 index 000000000..b549e321d --- /dev/null +++ b/packages/uni_app/lib/sigarra/endpoints/oidc/token/response.dart @@ -0,0 +1,20 @@ +import 'dart:io'; + +import 'package:uni/sigarra/response.dart'; + +class TokenResponse extends SigarraResponse { + const TokenResponse({required super.success}); + + TokenSuccessfulResponse asSuccessful() => this as TokenSuccessfulResponse; + TokenFailedResponse asFailed() => this as TokenFailedResponse; +} + +class TokenFailedResponse extends TokenResponse { + const TokenFailedResponse() : super(success: false); +} + +class TokenSuccessfulResponse extends TokenResponse { + const TokenSuccessfulResponse({required this.cookies}) : super(success: true); + + final List cookies; +} diff --git a/packages/uni_app/lib/sigarra/response.dart b/packages/uni_app/lib/sigarra/response.dart new file mode 100644 index 000000000..cfe91f221 --- /dev/null +++ b/packages/uni_app/lib/sigarra/response.dart @@ -0,0 +1,5 @@ +class SigarraResponse { + const SigarraResponse({required this.success}); + + final bool success; +} diff --git a/packages/uni_app/lib/utils/derived.dart b/packages/uni_app/lib/utils/derived.dart index 9e5055d4c..a499d18ac 100644 --- a/packages/uni_app/lib/utils/derived.dart +++ b/packages/uni_app/lib/utils/derived.dart @@ -8,7 +8,8 @@ class Derived { } } - final StreamController _controller = StreamController.broadcast(); + final StreamController _controller = + StreamController.broadcast(sync: true); Stream get stream => _controller.stream; final O Function(I) compute; From fb4dd70ab1b72d1f5b01bdb81317d5db5d2c8130 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Tue, 10 Sep 2024 23:43:47 +0100 Subject: [PATCH 42/99] adding new library api --- .../fetchers/library_occupation_fetcher.dart | 66 +++++++++++++------ .../parsers/parser_library_occupation.dart | 36 ---------- .../lazy/library_occupation_provider.dart | 5 +- 3 files changed, 48 insertions(+), 59 deletions(-) delete mode 100644 packages/uni_app/lib/controller/parsers/parser_library_occupation.dart diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 1c7efae69..180ac1f5f 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -1,26 +1,54 @@ -import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; -import 'package:uni/controller/networking/network_router.dart'; -import 'package:uni/controller/parsers/parser_library_occupation.dart'; +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:http/http.dart'; import 'package:uni/model/entities/library_occupation.dart'; -import 'package:uni/model/entities/session.dart'; /// Fetch the library occupation from Google Sheets -class LibraryOccupationFetcherSheets implements SessionDependantFetcher { - @override - List getEndpoints(Session session) { - const baseUrl = 'https://docs.google.com/spreadsheets/d/'; - const sheetId = '1gZRbEX4y8vNW7vrl15FCdAQ3pVNRJw_uRZtVL6ORP0g'; - const url = - '$baseUrl$sheetId/gviz/tq?tqx=out:json&sheet=MANUAL&range=C2:E7&tq=SELECT+C,E'; - return [url]; +class LibraryOccupationFetcher { + String baseUrl = 'https://webapi.affluences.com/api/fillRate?'; + + Map floorMaxSeats = { + 'BruV6IlujdwAe1': 72, + 'cEhyzJZvC5nHSr': 114, + 'iceVfgwZWaZRhV': 114, + '1yLPz9X0CNsg27': 114, + 'keu1j5zERlQn90': 40, + 'bY7K1v43HiAq55': 90, + }; + + Future getLibraryOccupation() async { + final libraryOccupation = LibraryOccupation(0, 0); + + for (var i = 0; i < floorMaxSeats.entries.length; i++) { + final floor = floorMaxSeats.entries.elementAt(i); + + final url = Uri.parse(baseUrl).replace( + queryParameters: { + 'token': floor.key, + }, + ); + + final response = await http.get(url); + + final floorOccupation = processFloorOccupation(response, i); + + libraryOccupation.addFloor(floorOccupation); + } + + return libraryOccupation; } - Future getLibraryOccupationFromSheets( - Session session, - ) async { - final url = getEndpoints(session)[0]; - final response = NetworkRouter.getWithCookies(url, {}, session); - final occupation = await response.then(parseLibraryOccupationFromSheets); - return occupation; + FloorOccupation processFloorOccupation(Response response, int floor) { + final responseBody = jsonDecode(response.body) as Map; + + final floorOccupation = int.parse(responseBody['progress'].toString()); + final floorCapacity = floorMaxSeats.entries.elementAt(floor).value; + + return FloorOccupation( + floor + 1, + (floorOccupation * floorCapacity / 100).round(), + floorCapacity, + ); } } diff --git a/packages/uni_app/lib/controller/parsers/parser_library_occupation.dart b/packages/uni_app/lib/controller/parsers/parser_library_occupation.dart deleted file mode 100644 index e2abae3f1..000000000 --- a/packages/uni_app/lib/controller/parsers/parser_library_occupation.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart'; -import 'package:uni/model/entities/library_occupation.dart'; - -// ignore_for_file: avoid_dynamic_calls - -Future parseLibraryOccupationFromSheets( - Response response, -) async { - final json = response.body.split('\n')[1]; // ignore first line - const toSkip = 'google.visualization.Query.setResponse('; // should be ignored - const numFloors = 6; - final occupation = LibraryOccupation(0, 0); - - final jsonDecoded = - jsonDecode(json.substring(toSkip.length, json.length - 2)); - - for (var i = 0; i < numFloors; i++) { - int floor; - int max; - try { - floor = (jsonDecoded['table']['rows'][i]['c'][0]['v'] as double).toInt(); - } catch (err) { - floor = 0; - } - try { - max = (jsonDecoded['table']['rows'][i]['c'][1]['v'] as double).toInt(); - } catch (err) { - max = 0; - } - occupation.addFloor(FloorOccupation(i + 1, floor, max)); - } - - return occupation; -} diff --git a/packages/uni_app/lib/model/providers/lazy/library_occupation_provider.dart b/packages/uni_app/lib/model/providers/lazy/library_occupation_provider.dart index 702ffa1ed..5e03f3916 100644 --- a/packages/uni_app/lib/model/providers/lazy/library_occupation_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/library_occupation_provider.dart @@ -22,10 +22,7 @@ class LibraryOccupationProvider Future loadFromRemote( StateProviders stateProviders, ) async { - final session = stateProviders.sessionProvider.state!; - final occupation = await LibraryOccupationFetcherSheets() - .getLibraryOccupationFromSheets(session); - + final occupation = await LibraryOccupationFetcher().getLibraryOccupation(); final db = LibraryOccupationDatabase(); unawaited(db.saveIfPersistentSession(occupation)); From 64a4651411791f73fa0922115ca1760368d592e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 11 Sep 2024 02:42:51 +0100 Subject: [PATCH 43/99] refactor: finish session refactor --- .../controller/fetchers/faculties_fetcher.dart | 15 +++++++++------ .../controller/networking/network_router.dart | 7 +++---- .../controller/authentication_controller.dart | 12 ++++++++++++ .../refreshing_authentication_controller.dart | 4 +--- packages/uni_app/lib/session/exception.dart | 15 ++++++++++++++- .../lib/session/flows/credentials/request.dart | 18 ++++++++++++------ .../lib/session/flows/federated/initiator.dart | 3 +-- .../lib/session/flows/federated/request.dart | 3 +-- .../view/common_widgets/page_transition.dart | 4 ++-- .../uni_app/lib/view/navigation_service.dart | 1 - .../uni_app/lib/view/settings/settings.dart | 4 ++-- 11 files changed, 57 insertions(+), 29 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index d5666b237..e4b6d03c2 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -1,12 +1,15 @@ import 'package:html/parser.dart'; -import 'package:uni/controller/networking/network_router.dart'; +import 'package:http/http.dart' as http; +import 'package:uni/http/client/cookie.dart'; import 'package:uni/session/flows/base/session.dart'; -Future> getStudentFaculties(Session session) async { - final response = await NetworkRouter.getWithCookies( - 'https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina', - {'pct_codigo': session.username}, - session, +Future> getStudentFaculties( + Session session, http.Client httpClient) async { + final client = CookieClient(httpClient, cookies: () => session.cookies); + + final response = await client.get( + Uri.parse('https://sigarra.up.pt/up/pt/vld_entidades_geral.entidade_pagina') + .replace(queryParameters: {'pct_codigo': session.username}), ); final document = parse(response.body); diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index cf70ebd0c..7383fd7b5 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -4,6 +4,7 @@ import 'package:http/http.dart' as http; import 'package:uni/http/client/authenticated.dart'; import 'package:uni/http/client/timeout.dart'; import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/controller/refreshing_authentication_controller.dart'; import 'package:uni/session/flows/base/session.dart'; extension UriString on String { @@ -43,10 +44,8 @@ class NetworkRouter { Map query, Session session, ) async { - final controller = authenticationController; - if (controller == null) { - throw Exception('Authentication controller not initialized'); - } + final controller = + authenticationController ?? RefreshingAuthenticationController(session); final client = AuthenticatedClient( TimeoutClient( diff --git a/packages/uni_app/lib/session/controller/authentication_controller.dart b/packages/uni_app/lib/session/controller/authentication_controller.dart index 50b768516..844112766 100644 --- a/packages/uni_app/lib/session/controller/authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/authentication_controller.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/logout/logout_handler.dart'; class AuthenticationSnapshot { AuthenticationSnapshot( @@ -15,5 +16,16 @@ class AuthenticationSnapshot { } abstract class AuthenticationController { + AuthenticationController({this.logoutHandler}); + Future get snapshot; + + final LogoutHandler? logoutHandler; + + Future close() async { + final currentSnapshot = await snapshot; + final session = currentSnapshot.session; + + return logoutHandler?.close(session); + } } diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart index 2ca9e0253..be715cdd3 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart @@ -6,15 +6,13 @@ import 'package:synchronized/synchronized.dart'; import 'package:uni/session/controller/authentication_controller.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/session.dart'; -import 'package:uni/session/logout/logout_handler.dart'; class RefreshingAuthenticationController extends AuthenticationController { RefreshingAuthenticationController( Session initialSession, { - this.logoutHandler, + super.logoutHandler, }) : _currentSession = initialSession; - final LogoutHandler? logoutHandler; final Lock _authenticationLock = Lock(); Future? _nextAuthentication; diff --git a/packages/uni_app/lib/session/exception.dart b/packages/uni_app/lib/session/exception.dart index 654b9444d..712ceae75 100644 --- a/packages/uni_app/lib/session/exception.dart +++ b/packages/uni_app/lib/session/exception.dart @@ -1,5 +1,18 @@ +enum AuthenticationExceptionType { + wrongCredentials, + expiredCredentials, + other, +} + class AuthenticationException implements Exception { - const AuthenticationException(this.message); + const AuthenticationException( + this.message, [ + this.type = AuthenticationExceptionType.other, + ]); final String message; + final AuthenticationExceptionType type; + + @override + String toString() => 'AuthenticationException($message, $type)'; } diff --git a/packages/uni_app/lib/session/flows/credentials/request.dart b/packages/uni_app/lib/session/flows/credentials/request.dart index 44e3c5d47..0b4c68578 100644 --- a/packages/uni_app/lib/session/flows/credentials/request.dart +++ b/packages/uni_app/lib/session/flows/credentials/request.dart @@ -1,6 +1,6 @@ import 'package:http/http.dart' as http; import 'package:uni/controller/fetchers/faculties_fetcher.dart'; -import 'package:uni/model/entities/login_exceptions.dart'; +import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/credentials/session.dart'; import 'package:uni/sigarra/endpoints/api.dart'; @@ -31,13 +31,19 @@ class CredentialsSessionRequest extends SessionRequest { // FIXME(limwa): convey the reason to the user if (failureReason == LoginFailureReason.expiredCredentials) { - throw ExpiredCredentialsException(); + throw const AuthenticationException( + 'Failed to authenticate user', + AuthenticationExceptionType.expiredCredentials, + ); } else { - throw WrongCredentialsException(); + throw const AuthenticationException( + 'Failed to authenticate user', + AuthenticationExceptionType.wrongCredentials, + ); } } - final faculties = await getStudentFaculties(tempSession); + final faculties = await getStudentFaculties(tempSession, client); final session = CredentialsSession( username: tempSession.username, @@ -59,7 +65,7 @@ class CredentialsSessionRequest extends SessionRequest { final loginResponse = await api.authentication.login.call( username: username, password: password, - options: FacultyRequestOptions(client: httpClient), + options: FacultyRequestOptions(faculty: 'feup', client: httpClient), ); if (!loginResponse.success) { @@ -71,7 +77,7 @@ class CredentialsSessionRequest extends SessionRequest { username: info.username, password: password, cookies: info.cookies, - faculties: ['up'], + faculties: ['feup'], ); } diff --git a/packages/uni_app/lib/session/flows/federated/initiator.dart b/packages/uni_app/lib/session/flows/federated/initiator.dart index 6e7aff5fb..8da7a280c 100644 --- a/packages/uni_app/lib/session/flows/federated/initiator.dart +++ b/packages/uni_app/lib/session/flows/federated/initiator.dart @@ -1,7 +1,6 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; import 'package:uni/session/flows/base/initiator.dart'; -import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/federated/request.dart'; class FederatedSessionInitiator extends SessionInitiator { @@ -18,7 +17,7 @@ class FederatedSessionInitiator extends SessionInitiator { final Future Function(Flow flow) performAuthentication; @override - Future initiate([http.Client? httpClient]) async { + Future initiate([http.Client? httpClient]) async { final issuer = await Issuer.discover(realm); final client = Client(issuer, clientId, httpClient: httpClient); diff --git a/packages/uni_app/lib/session/flows/federated/request.dart b/packages/uni_app/lib/session/flows/federated/request.dart index 141583d84..29e8f46fd 100644 --- a/packages/uni_app/lib/session/flows/federated/request.dart +++ b/packages/uni_app/lib/session/flows/federated/request.dart @@ -39,8 +39,6 @@ class FederatedSessionRequest extends SessionRequest { @override Future perform([http.Client? httpClient]) async { - final userInfo = FederatedSessionUserInfo(await credential.getUserInfo()); - final authorizedClient = credential.createHttpClient(httpClient); final oidc = SigarraOidc(); @@ -54,6 +52,7 @@ class FederatedSessionRequest extends SessionRequest { throw const AuthenticationException('Failed to get OIDC token'); } + final userInfo = FederatedSessionUserInfo(await credential.getUserInfo()); final successfulResponse = response.asSuccessful(); return FederatedSession( username: userInfo.username, diff --git a/packages/uni_app/lib/view/common_widgets/page_transition.dart b/packages/uni_app/lib/view/common_widgets/page_transition.dart index fe39019d6..3ea44480a 100644 --- a/packages/uni_app/lib/view/common_widgets/page_transition.dart +++ b/packages/uni_app/lib/view/common_widgets/page_transition.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:uni/view/navigation_service.dart'; +import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/view/terms_and_condition_dialog.dart'; /// Transition used between pages @@ -51,7 +51,7 @@ class PageTransition { case TermsAndConditionsState.accepted: return; case TermsAndConditionsState.rejected: - NavigationService.logoutAndPopHistory(); + await NetworkRouter.authenticationController?.close(); } } } diff --git a/packages/uni_app/lib/view/navigation_service.dart b/packages/uni_app/lib/view/navigation_service.dart index e896d904d..bd42ae06f 100644 --- a/packages/uni_app/lib/view/navigation_service.dart +++ b/packages/uni_app/lib/view/navigation_service.dart @@ -9,7 +9,6 @@ import 'package:uni/view/login/login.dart'; class NavigationService { static void logoutAndPopHistory() { final context = Application.navigatorKey.currentContext!; - unawaited(cleanupStoredData(context)); Navigator.pushAndRemoveUntil( diff --git a/packages/uni_app/lib/view/settings/settings.dart b/packages/uni_app/lib/view/settings/settings.dart index 0d7dc796f..ba48f5ab7 100644 --- a/packages/uni_app/lib/view/settings/settings.dart +++ b/packages/uni_app/lib/view/settings/settings.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/view/about/about.dart'; import 'package:uni/view/bug_report/bug_report.dart'; import 'package:uni/view/common_widgets/pages_layouts/secondary/secondary.dart'; -import 'package:uni/view/navigation_service.dart'; import 'package:uni/view/settings/widgets/locale_switch_button.dart'; import 'package:uni/view/settings/widgets/notifications_dialog.dart'; import 'package:uni/view/settings/widgets/theme_switch_button.dart'; @@ -78,7 +78,7 @@ class SettingsPageState extends SecondaryPageViewState { ListTile( title: Text(S.of(context).logout), trailing: const Icon(Icons.arrow_forward_ios), - onTap: NavigationService.logoutAndPopHistory, + onTap: NetworkRouter.authenticationController?.close, ), ], ), From 59f471628dae504a974d6e313ca4755929f1f983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 11 Sep 2024 02:43:55 +0100 Subject: [PATCH 44/99] test: remove tests (lol) --- .../{test => test_old}/integration/resources/exam2_example.html | 0 .../{test => test_old}/integration/resources/exam_example.html | 0 .../integration/resources/schedule_example.html | 0 .../integration/resources/schedule_example.json | 0 .../{test => test_old}/integration/src/exams2_page_test.dart | 0 .../{test => test_old}/integration/src/exams_page_test.dart | 0 .../{test => test_old}/integration/src/schedule_page_test.dart | 0 .../mocks/integration/src/exams2_page_test.mocks.dart | 0 .../mocks/integration/src/exams_page_test.mocks.dart | 0 .../mocks/integration/src/schedule_page_test.mocks.dart | 0 .../mocks/unit/providers/exams_provider_test.mocks.dart | 0 .../mocks/unit/providers/lecture_provider_test.mocks.dart | 0 packages/uni_app/{test => test_old}/test_widget.dart | 0 .../{test => test_old}/unit/models/utils/time/week_test.dart | 0 .../unit/models/utils/time/weekday_mapper_test.dart | 0 .../{test => test_old}/unit/providers/exams_provider_test.dart | 0 .../{test => test_old}/unit/providers/lecture_provider_test.dart | 0 .../{test => test_old}/unit/view/Pages/exams_page_view_test.dart | 0 .../unit/view/Pages/schedule_page_view_test.dart | 0 .../{test => test_old}/unit/view/Widgets/exam_row_test.dart | 0 .../{test => test_old}/unit/view/Widgets/schedule_slot_test.dart | 0 21 files changed, 0 insertions(+), 0 deletions(-) rename packages/uni_app/{test => test_old}/integration/resources/exam2_example.html (100%) rename packages/uni_app/{test => test_old}/integration/resources/exam_example.html (100%) rename packages/uni_app/{test => test_old}/integration/resources/schedule_example.html (100%) rename packages/uni_app/{test => test_old}/integration/resources/schedule_example.json (100%) rename packages/uni_app/{test => test_old}/integration/src/exams2_page_test.dart (100%) rename packages/uni_app/{test => test_old}/integration/src/exams_page_test.dart (100%) rename packages/uni_app/{test => test_old}/integration/src/schedule_page_test.dart (100%) rename packages/uni_app/{test => test_old}/mocks/integration/src/exams2_page_test.mocks.dart (100%) rename packages/uni_app/{test => test_old}/mocks/integration/src/exams_page_test.mocks.dart (100%) rename packages/uni_app/{test => test_old}/mocks/integration/src/schedule_page_test.mocks.dart (100%) rename packages/uni_app/{test => test_old}/mocks/unit/providers/exams_provider_test.mocks.dart (100%) rename packages/uni_app/{test => test_old}/mocks/unit/providers/lecture_provider_test.mocks.dart (100%) rename packages/uni_app/{test => test_old}/test_widget.dart (100%) rename packages/uni_app/{test => test_old}/unit/models/utils/time/week_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/models/utils/time/weekday_mapper_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/providers/exams_provider_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/providers/lecture_provider_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/view/Pages/exams_page_view_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/view/Pages/schedule_page_view_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/view/Widgets/exam_row_test.dart (100%) rename packages/uni_app/{test => test_old}/unit/view/Widgets/schedule_slot_test.dart (100%) diff --git a/packages/uni_app/test/integration/resources/exam2_example.html b/packages/uni_app/test_old/integration/resources/exam2_example.html similarity index 100% rename from packages/uni_app/test/integration/resources/exam2_example.html rename to packages/uni_app/test_old/integration/resources/exam2_example.html diff --git a/packages/uni_app/test/integration/resources/exam_example.html b/packages/uni_app/test_old/integration/resources/exam_example.html similarity index 100% rename from packages/uni_app/test/integration/resources/exam_example.html rename to packages/uni_app/test_old/integration/resources/exam_example.html diff --git a/packages/uni_app/test/integration/resources/schedule_example.html b/packages/uni_app/test_old/integration/resources/schedule_example.html similarity index 100% rename from packages/uni_app/test/integration/resources/schedule_example.html rename to packages/uni_app/test_old/integration/resources/schedule_example.html diff --git a/packages/uni_app/test/integration/resources/schedule_example.json b/packages/uni_app/test_old/integration/resources/schedule_example.json similarity index 100% rename from packages/uni_app/test/integration/resources/schedule_example.json rename to packages/uni_app/test_old/integration/resources/schedule_example.json diff --git a/packages/uni_app/test/integration/src/exams2_page_test.dart b/packages/uni_app/test_old/integration/src/exams2_page_test.dart similarity index 100% rename from packages/uni_app/test/integration/src/exams2_page_test.dart rename to packages/uni_app/test_old/integration/src/exams2_page_test.dart diff --git a/packages/uni_app/test/integration/src/exams_page_test.dart b/packages/uni_app/test_old/integration/src/exams_page_test.dart similarity index 100% rename from packages/uni_app/test/integration/src/exams_page_test.dart rename to packages/uni_app/test_old/integration/src/exams_page_test.dart diff --git a/packages/uni_app/test/integration/src/schedule_page_test.dart b/packages/uni_app/test_old/integration/src/schedule_page_test.dart similarity index 100% rename from packages/uni_app/test/integration/src/schedule_page_test.dart rename to packages/uni_app/test_old/integration/src/schedule_page_test.dart diff --git a/packages/uni_app/test/mocks/integration/src/exams2_page_test.mocks.dart b/packages/uni_app/test_old/mocks/integration/src/exams2_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test/mocks/integration/src/exams2_page_test.mocks.dart rename to packages/uni_app/test_old/mocks/integration/src/exams2_page_test.mocks.dart diff --git a/packages/uni_app/test/mocks/integration/src/exams_page_test.mocks.dart b/packages/uni_app/test_old/mocks/integration/src/exams_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test/mocks/integration/src/exams_page_test.mocks.dart rename to packages/uni_app/test_old/mocks/integration/src/exams_page_test.mocks.dart diff --git a/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart b/packages/uni_app/test_old/mocks/integration/src/schedule_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart rename to packages/uni_app/test_old/mocks/integration/src/schedule_page_test.mocks.dart diff --git a/packages/uni_app/test/mocks/unit/providers/exams_provider_test.mocks.dart b/packages/uni_app/test_old/mocks/unit/providers/exams_provider_test.mocks.dart similarity index 100% rename from packages/uni_app/test/mocks/unit/providers/exams_provider_test.mocks.dart rename to packages/uni_app/test_old/mocks/unit/providers/exams_provider_test.mocks.dart diff --git a/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test_old/mocks/unit/providers/lecture_provider_test.mocks.dart similarity index 100% rename from packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart rename to packages/uni_app/test_old/mocks/unit/providers/lecture_provider_test.mocks.dart diff --git a/packages/uni_app/test/test_widget.dart b/packages/uni_app/test_old/test_widget.dart similarity index 100% rename from packages/uni_app/test/test_widget.dart rename to packages/uni_app/test_old/test_widget.dart diff --git a/packages/uni_app/test/unit/models/utils/time/week_test.dart b/packages/uni_app/test_old/unit/models/utils/time/week_test.dart similarity index 100% rename from packages/uni_app/test/unit/models/utils/time/week_test.dart rename to packages/uni_app/test_old/unit/models/utils/time/week_test.dart diff --git a/packages/uni_app/test/unit/models/utils/time/weekday_mapper_test.dart b/packages/uni_app/test_old/unit/models/utils/time/weekday_mapper_test.dart similarity index 100% rename from packages/uni_app/test/unit/models/utils/time/weekday_mapper_test.dart rename to packages/uni_app/test_old/unit/models/utils/time/weekday_mapper_test.dart diff --git a/packages/uni_app/test/unit/providers/exams_provider_test.dart b/packages/uni_app/test_old/unit/providers/exams_provider_test.dart similarity index 100% rename from packages/uni_app/test/unit/providers/exams_provider_test.dart rename to packages/uni_app/test_old/unit/providers/exams_provider_test.dart diff --git a/packages/uni_app/test/unit/providers/lecture_provider_test.dart b/packages/uni_app/test_old/unit/providers/lecture_provider_test.dart similarity index 100% rename from packages/uni_app/test/unit/providers/lecture_provider_test.dart rename to packages/uni_app/test_old/unit/providers/lecture_provider_test.dart diff --git a/packages/uni_app/test/unit/view/Pages/exams_page_view_test.dart b/packages/uni_app/test_old/unit/view/Pages/exams_page_view_test.dart similarity index 100% rename from packages/uni_app/test/unit/view/Pages/exams_page_view_test.dart rename to packages/uni_app/test_old/unit/view/Pages/exams_page_view_test.dart diff --git a/packages/uni_app/test/unit/view/Pages/schedule_page_view_test.dart b/packages/uni_app/test_old/unit/view/Pages/schedule_page_view_test.dart similarity index 100% rename from packages/uni_app/test/unit/view/Pages/schedule_page_view_test.dart rename to packages/uni_app/test_old/unit/view/Pages/schedule_page_view_test.dart diff --git a/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart b/packages/uni_app/test_old/unit/view/Widgets/exam_row_test.dart similarity index 100% rename from packages/uni_app/test/unit/view/Widgets/exam_row_test.dart rename to packages/uni_app/test_old/unit/view/Widgets/exam_row_test.dart diff --git a/packages/uni_app/test/unit/view/Widgets/schedule_slot_test.dart b/packages/uni_app/test_old/unit/view/Widgets/schedule_slot_test.dart similarity index 100% rename from packages/uni_app/test/unit/view/Widgets/schedule_slot_test.dart rename to packages/uni_app/test_old/unit/view/Widgets/schedule_slot_test.dart From 6bb7f16ef851326f66521590dfe3fb449989a641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 11 Sep 2024 02:53:02 +0100 Subject: [PATCH 45/99] fix: minor issues --- .../uni_app/lib/controller/fetchers/faculties_fetcher.dart | 4 +++- .../fetchers/schedule_fetcher/schedule_fetcher_new_api.dart | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart index e4b6d03c2..bf6afaf96 100644 --- a/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/faculties_fetcher.dart @@ -4,7 +4,9 @@ import 'package:uni/http/client/cookie.dart'; import 'package:uni/session/flows/base/session.dart'; Future> getStudentFaculties( - Session session, http.Client httpClient) async { + Session session, + http.Client httpClient, +) async { final client = CookieClient(httpClient, cookies: () => session.cookies); final response = await client.get( diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index 2d8d38fb7..e42f24e30 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -3,7 +3,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/schedule/new_api/parser.dart'; import 'package:uni/model/entities/lecture.dart'; import 'package:uni/model/entities/profile.dart'; -import 'package:uni/model/entities/session.dart'; +import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's lectures from the schedule's HTML page. class ScheduleFetcherNewApi extends ScheduleFetcher { From 24809b72517e39d6ea2b9043007a3a5ad2fb0725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 11 Sep 2024 02:54:06 +0100 Subject: [PATCH 46/99] test: readd some tests --- .../{test_old => test}/integration/resources/exam2_example.html | 0 .../{test_old => test}/integration/resources/exam_example.html | 0 .../integration/resources/schedule_example.json | 0 .../integration/src/exams2_page_test.dart.old} | 0 .../integration/src/exams_page_test.dart.old} | 0 .../integration/src/schedule_page_test.dart.old} | 0 .../mocks/integration/src/exams2_page_test.mocks.dart | 0 .../mocks/integration/src/exams_page_test.mocks.dart | 0 .../mocks/integration/src/schedule_page_test.mocks.dart | 0 .../mocks/unit/providers/exams_provider_test.mocks.dart | 0 .../mocks/unit/providers/lecture_provider_test.mocks.dart | 0 packages/uni_app/{test_old => test}/test_widget.dart | 0 .../{test_old => test}/unit/models/utils/time/week_test.dart | 0 .../unit/models/utils/time/weekday_mapper_test.dart | 0 .../unit/providers/exams_provider_test.dart.old} | 0 .../unit/providers/lecture_provider_test.dart.old} | 0 .../{test_old => test}/unit/view/Pages/exams_page_view_test.dart | 0 .../unit/view/Pages/schedule_page_view_test.dart | 0 .../{test_old => test}/unit/view/Widgets/exam_row_test.dart | 0 .../{test_old => test}/unit/view/Widgets/schedule_slot_test.dart | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename packages/uni_app/{test_old => test}/integration/resources/exam2_example.html (100%) rename packages/uni_app/{test_old => test}/integration/resources/exam_example.html (100%) rename packages/uni_app/{test_old => test}/integration/resources/schedule_example.json (100%) rename packages/uni_app/{test_old/integration/src/exams2_page_test.dart => test/integration/src/exams2_page_test.dart.old} (100%) rename packages/uni_app/{test_old/integration/src/exams_page_test.dart => test/integration/src/exams_page_test.dart.old} (100%) rename packages/uni_app/{test_old/integration/src/schedule_page_test.dart => test/integration/src/schedule_page_test.dart.old} (100%) rename packages/uni_app/{test_old => test}/mocks/integration/src/exams2_page_test.mocks.dart (100%) rename packages/uni_app/{test_old => test}/mocks/integration/src/exams_page_test.mocks.dart (100%) rename packages/uni_app/{test_old => test}/mocks/integration/src/schedule_page_test.mocks.dart (100%) rename packages/uni_app/{test_old => test}/mocks/unit/providers/exams_provider_test.mocks.dart (100%) rename packages/uni_app/{test_old => test}/mocks/unit/providers/lecture_provider_test.mocks.dart (100%) rename packages/uni_app/{test_old => test}/test_widget.dart (100%) rename packages/uni_app/{test_old => test}/unit/models/utils/time/week_test.dart (100%) rename packages/uni_app/{test_old => test}/unit/models/utils/time/weekday_mapper_test.dart (100%) rename packages/uni_app/{test_old/unit/providers/exams_provider_test.dart => test/unit/providers/exams_provider_test.dart.old} (100%) rename packages/uni_app/{test_old/unit/providers/lecture_provider_test.dart => test/unit/providers/lecture_provider_test.dart.old} (100%) rename packages/uni_app/{test_old => test}/unit/view/Pages/exams_page_view_test.dart (100%) rename packages/uni_app/{test_old => test}/unit/view/Pages/schedule_page_view_test.dart (100%) rename packages/uni_app/{test_old => test}/unit/view/Widgets/exam_row_test.dart (100%) rename packages/uni_app/{test_old => test}/unit/view/Widgets/schedule_slot_test.dart (100%) diff --git a/packages/uni_app/test_old/integration/resources/exam2_example.html b/packages/uni_app/test/integration/resources/exam2_example.html similarity index 100% rename from packages/uni_app/test_old/integration/resources/exam2_example.html rename to packages/uni_app/test/integration/resources/exam2_example.html diff --git a/packages/uni_app/test_old/integration/resources/exam_example.html b/packages/uni_app/test/integration/resources/exam_example.html similarity index 100% rename from packages/uni_app/test_old/integration/resources/exam_example.html rename to packages/uni_app/test/integration/resources/exam_example.html diff --git a/packages/uni_app/test_old/integration/resources/schedule_example.json b/packages/uni_app/test/integration/resources/schedule_example.json similarity index 100% rename from packages/uni_app/test_old/integration/resources/schedule_example.json rename to packages/uni_app/test/integration/resources/schedule_example.json diff --git a/packages/uni_app/test_old/integration/src/exams2_page_test.dart b/packages/uni_app/test/integration/src/exams2_page_test.dart.old similarity index 100% rename from packages/uni_app/test_old/integration/src/exams2_page_test.dart rename to packages/uni_app/test/integration/src/exams2_page_test.dart.old diff --git a/packages/uni_app/test_old/integration/src/exams_page_test.dart b/packages/uni_app/test/integration/src/exams_page_test.dart.old similarity index 100% rename from packages/uni_app/test_old/integration/src/exams_page_test.dart rename to packages/uni_app/test/integration/src/exams_page_test.dart.old diff --git a/packages/uni_app/test_old/integration/src/schedule_page_test.dart b/packages/uni_app/test/integration/src/schedule_page_test.dart.old similarity index 100% rename from packages/uni_app/test_old/integration/src/schedule_page_test.dart rename to packages/uni_app/test/integration/src/schedule_page_test.dart.old diff --git a/packages/uni_app/test_old/mocks/integration/src/exams2_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/exams2_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test_old/mocks/integration/src/exams2_page_test.mocks.dart rename to packages/uni_app/test/mocks/integration/src/exams2_page_test.mocks.dart diff --git a/packages/uni_app/test_old/mocks/integration/src/exams_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/exams_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test_old/mocks/integration/src/exams_page_test.mocks.dart rename to packages/uni_app/test/mocks/integration/src/exams_page_test.mocks.dart diff --git a/packages/uni_app/test_old/mocks/integration/src/schedule_page_test.mocks.dart b/packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart similarity index 100% rename from packages/uni_app/test_old/mocks/integration/src/schedule_page_test.mocks.dart rename to packages/uni_app/test/mocks/integration/src/schedule_page_test.mocks.dart diff --git a/packages/uni_app/test_old/mocks/unit/providers/exams_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/exams_provider_test.mocks.dart similarity index 100% rename from packages/uni_app/test_old/mocks/unit/providers/exams_provider_test.mocks.dart rename to packages/uni_app/test/mocks/unit/providers/exams_provider_test.mocks.dart diff --git a/packages/uni_app/test_old/mocks/unit/providers/lecture_provider_test.mocks.dart b/packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart similarity index 100% rename from packages/uni_app/test_old/mocks/unit/providers/lecture_provider_test.mocks.dart rename to packages/uni_app/test/mocks/unit/providers/lecture_provider_test.mocks.dart diff --git a/packages/uni_app/test_old/test_widget.dart b/packages/uni_app/test/test_widget.dart similarity index 100% rename from packages/uni_app/test_old/test_widget.dart rename to packages/uni_app/test/test_widget.dart diff --git a/packages/uni_app/test_old/unit/models/utils/time/week_test.dart b/packages/uni_app/test/unit/models/utils/time/week_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/models/utils/time/week_test.dart rename to packages/uni_app/test/unit/models/utils/time/week_test.dart diff --git a/packages/uni_app/test_old/unit/models/utils/time/weekday_mapper_test.dart b/packages/uni_app/test/unit/models/utils/time/weekday_mapper_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/models/utils/time/weekday_mapper_test.dart rename to packages/uni_app/test/unit/models/utils/time/weekday_mapper_test.dart diff --git a/packages/uni_app/test_old/unit/providers/exams_provider_test.dart b/packages/uni_app/test/unit/providers/exams_provider_test.dart.old similarity index 100% rename from packages/uni_app/test_old/unit/providers/exams_provider_test.dart rename to packages/uni_app/test/unit/providers/exams_provider_test.dart.old diff --git a/packages/uni_app/test_old/unit/providers/lecture_provider_test.dart b/packages/uni_app/test/unit/providers/lecture_provider_test.dart.old similarity index 100% rename from packages/uni_app/test_old/unit/providers/lecture_provider_test.dart rename to packages/uni_app/test/unit/providers/lecture_provider_test.dart.old diff --git a/packages/uni_app/test_old/unit/view/Pages/exams_page_view_test.dart b/packages/uni_app/test/unit/view/Pages/exams_page_view_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/view/Pages/exams_page_view_test.dart rename to packages/uni_app/test/unit/view/Pages/exams_page_view_test.dart diff --git a/packages/uni_app/test_old/unit/view/Pages/schedule_page_view_test.dart b/packages/uni_app/test/unit/view/Pages/schedule_page_view_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/view/Pages/schedule_page_view_test.dart rename to packages/uni_app/test/unit/view/Pages/schedule_page_view_test.dart diff --git a/packages/uni_app/test_old/unit/view/Widgets/exam_row_test.dart b/packages/uni_app/test/unit/view/Widgets/exam_row_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/view/Widgets/exam_row_test.dart rename to packages/uni_app/test/unit/view/Widgets/exam_row_test.dart diff --git a/packages/uni_app/test_old/unit/view/Widgets/schedule_slot_test.dart b/packages/uni_app/test/unit/view/Widgets/schedule_slot_test.dart similarity index 100% rename from packages/uni_app/test_old/unit/view/Widgets/schedule_slot_test.dart rename to packages/uni_app/test/unit/view/Widgets/schedule_slot_test.dart From 5fd57c03bbe636b8b65b49dc0a2484fc99c56063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 11 Sep 2024 02:54:47 +0100 Subject: [PATCH 47/99] refactor: lint code --- packages/uni_app/lib/view/bug_report/widgets/form.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/uni_app/lib/view/bug_report/widgets/form.dart b/packages/uni_app/lib/view/bug_report/widgets/form.dart index a6b42abc3..7f9257e61 100644 --- a/packages/uni_app/lib/view/bug_report/widgets/form.dart +++ b/packages/uni_app/lib/view/bug_report/widgets/form.dart @@ -4,7 +4,6 @@ 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/preferences_controller.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/app_locale.dart'; import 'package:uni/model/entities/bug_report.dart'; From 88df1e97998d6f069d88be200bec69d46e51c0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 01:20:30 +0100 Subject: [PATCH 48/99] refactor: remove useless code --- .../controller/networking/network_router.dart | 4 +-- .../lib/http/client/authenticated.dart | 2 +- .../providers/startup/session_provider.dart | 5 ++- ...er.dart => authentication_controller.dart} | 22 ++++++++++--- .../controller/authentication_controller.dart | 31 ------------------- .../idle_authentication_controller.dart | 16 ---------- .../throwing_authentication_controller.dart | 8 ----- .../lib/session/flows/federated/request.dart | 17 ++++++++-- .../api/authentication/login/response.dart | 3 -- 9 files changed, 37 insertions(+), 71 deletions(-) rename packages/uni_app/lib/session/{controller/refreshing_authentication_controller.dart => authentication_controller.dart} (88%) delete mode 100644 packages/uni_app/lib/session/controller/authentication_controller.dart delete mode 100644 packages/uni_app/lib/session/controller/idle_authentication_controller.dart delete mode 100644 packages/uni_app/lib/session/controller/throwing_authentication_controller.dart diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 7383fd7b5..3545388bd 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -3,8 +3,8 @@ import 'dart:async'; import 'package:http/http.dart' as http; import 'package:uni/http/client/authenticated.dart'; import 'package:uni/http/client/timeout.dart'; -import 'package:uni/session/controller/authentication_controller.dart'; -import 'package:uni/session/controller/refreshing_authentication_controller.dart'; +import 'package:uni/session/authentication_controller.dart'; +import 'package:uni/session/controller/?authentication_controller.dart'; import 'package:uni/session/flows/base/session.dart'; extension UriString on String { diff --git a/packages/uni_app/lib/http/client/authenticated.dart b/packages/uni_app/lib/http/client/authenticated.dart index 55db7ae1c..e9754cee7 100644 --- a/packages/uni_app/lib/http/client/authenticated.dart +++ b/packages/uni_app/lib/http/client/authenticated.dart @@ -5,7 +5,7 @@ import 'package:http/retry.dart' show RetryClient; import 'package:logger/logger.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/http/client/cookie.dart'; -import 'package:uni/session/controller/authentication_controller.dart'; +import 'package:uni/session/authentication_controller.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/session.dart'; diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index f795467c1..e1f9500b9 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -7,8 +7,7 @@ import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/model/request_status.dart'; -import 'package:uni/session/controller/authentication_controller.dart'; -import 'package:uni/session/controller/refreshing_authentication_controller.dart'; +import 'package:uni/session/authentication_controller.dart'; import 'package:uni/session/flows/base/initiator.dart'; import 'package:uni/session/flows/base/session.dart'; import 'package:uni/session/logout/uni_logout_handler.dart'; @@ -25,7 +24,7 @@ class SessionProvider extends StateProviderNotifier { NetworkRouter.authenticationController!; void initController(Session session) { - NetworkRouter.authenticationController = RefreshingAuthenticationController( + NetworkRouter.authenticationController = AuthenticationController( session, logoutHandler: UniLogoutHandler(), ); diff --git a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart b/packages/uni_app/lib/session/authentication_controller.dart similarity index 88% rename from packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart rename to packages/uni_app/lib/session/authentication_controller.dart index be715cdd3..5ccec42f4 100644 --- a/packages/uni_app/lib/session/controller/refreshing_authentication_controller.dart +++ b/packages/uni_app/lib/session/authentication_controller.dart @@ -3,17 +3,30 @@ import 'dart:async'; import 'package:logger/logger.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:synchronized/synchronized.dart'; -import 'package:uni/session/controller/authentication_controller.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/session/logout/logout_handler.dart'; -class RefreshingAuthenticationController extends AuthenticationController { - RefreshingAuthenticationController( +class AuthenticationSnapshot { + AuthenticationSnapshot( + this.session, { + required Future Function() invalidate, + }) : _invalidate = invalidate; + + final Session session; + final Future Function() _invalidate; + + Future invalidate() => _invalidate(); +} + +class AuthenticationController { + AuthenticationController( Session initialSession, { - super.logoutHandler, + this.logoutHandler, }) : _currentSession = initialSession; final Lock _authenticationLock = Lock(); + final LogoutHandler? logoutHandler; Future? _nextAuthentication; Session _currentSession; @@ -22,7 +35,6 @@ class RefreshingAuthenticationController extends AuthenticationController { StreamController.broadcast(); Stream get snapshots => _snapshotsController.stream; - @override Future get snapshot async { final nextAuthentication = _nextAuthentication; if (nextAuthentication != null) { diff --git a/packages/uni_app/lib/session/controller/authentication_controller.dart b/packages/uni_app/lib/session/controller/authentication_controller.dart deleted file mode 100644 index 844112766..000000000 --- a/packages/uni_app/lib/session/controller/authentication_controller.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'dart:async'; - -import 'package:uni/session/flows/base/session.dart'; -import 'package:uni/session/logout/logout_handler.dart'; - -class AuthenticationSnapshot { - AuthenticationSnapshot( - this.session, { - required Future Function() invalidate, - }) : _invalidate = invalidate; - - final Session session; - final Future Function() _invalidate; - - Future invalidate() => _invalidate(); -} - -abstract class AuthenticationController { - AuthenticationController({this.logoutHandler}); - - Future get snapshot; - - final LogoutHandler? logoutHandler; - - Future close() async { - final currentSnapshot = await snapshot; - final session = currentSnapshot.session; - - return logoutHandler?.close(session); - } -} diff --git a/packages/uni_app/lib/session/controller/idle_authentication_controller.dart b/packages/uni_app/lib/session/controller/idle_authentication_controller.dart deleted file mode 100644 index 40358ca6c..000000000 --- a/packages/uni_app/lib/session/controller/idle_authentication_controller.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:uni/session/controller/authentication_controller.dart'; -import 'package:uni/session/flows/base/session.dart'; - -class IdleAuthenticationController extends AuthenticationController { - IdleAuthenticationController(this._session); - - final Session _session; - - @override - Future get snapshot => Future.value( - AuthenticationSnapshot( - _session, - invalidate: () async {}, - ), - ); -} diff --git a/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart b/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart deleted file mode 100644 index e4da44cfa..000000000 --- a/packages/uni_app/lib/session/controller/throwing_authentication_controller.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:uni/session/controller/authentication_controller.dart'; -import 'package:uni/session/exception.dart'; - -class ThrowingAuthenticationController extends AuthenticationController { - @override - Future get snapshot => - throw const AuthenticationException('ThrowingAuthenticationController'); -} diff --git a/packages/uni_app/lib/session/flows/federated/request.dart b/packages/uni_app/lib/session/flows/federated/request.dart index 29e8f46fd..8d1a26b06 100644 --- a/packages/uni_app/lib/session/flows/federated/request.dart +++ b/packages/uni_app/lib/session/flows/federated/request.dart @@ -1,5 +1,6 @@ import 'package:http/http.dart' as http; import 'package:openid_client/openid_client.dart'; +import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/federated/session.dart'; @@ -39,7 +40,9 @@ class FederatedSessionRequest extends SessionRequest { @override Future perform([http.Client? httpClient]) async { - final authorizedClient = credential.createHttpClient(httpClient); + final client = httpClient ?? http.Client(); + + final authorizedClient = credential.createHttpClient(client); final oidc = SigarraOidc(); final response = await oidc.token.call( @@ -54,11 +57,21 @@ class FederatedSessionRequest extends SessionRequest { final userInfo = FederatedSessionUserInfo(await credential.getUserInfo()); final successfulResponse = response.asSuccessful(); - return FederatedSession( + + final tempSession = FederatedSession( username: userInfo.username, faculties: userInfo.faculties, cookies: successfulResponse.cookies, credential: credential, ); + + final faculties = await getStudentFaculties(tempSession, client); + + return FederatedSession( + username: userInfo.username, + faculties: faculties, + cookies: successfulResponse.cookies, + credential: credential, + ); } } diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart index e2f871e33..d91d38d63 100644 --- a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/response.dart @@ -25,8 +25,5 @@ enum LoginFailureReason { class LoginFailedResponse extends LoginResponse { const LoginFailedResponse({required this.reason}) : super(success: false); - @override - bool get success => false; - final LoginFailureReason reason; } From ede3c976620649467c7f083b59746a436ba9460f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 01:24:41 +0100 Subject: [PATCH 49/99] refactor: readd close method --- .../uni_app/lib/controller/networking/network_router.dart | 3 +-- .../uni_app/lib/session/authentication_controller.dart | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index 3545388bd..e78f43b9d 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -4,7 +4,6 @@ import 'package:http/http.dart' as http; import 'package:uni/http/client/authenticated.dart'; import 'package:uni/http/client/timeout.dart'; import 'package:uni/session/authentication_controller.dart'; -import 'package:uni/session/controller/?authentication_controller.dart'; import 'package:uni/session/flows/base/session.dart'; extension UriString on String { @@ -45,7 +44,7 @@ class NetworkRouter { Session session, ) async { final controller = - authenticationController ?? RefreshingAuthenticationController(session); + authenticationController ?? AuthenticationController(session); final client = AuthenticatedClient( TimeoutClient( diff --git a/packages/uni_app/lib/session/authentication_controller.dart b/packages/uni_app/lib/session/authentication_controller.dart index 5ccec42f4..6747594e0 100644 --- a/packages/uni_app/lib/session/authentication_controller.dart +++ b/packages/uni_app/lib/session/authentication_controller.dart @@ -49,6 +49,13 @@ class AuthenticationController { await currentSnapshot.invalidate(); } + Future close() async { + final currentSnapshot = await snapshot; + final session = currentSnapshot.session; + + return logoutHandler?.close(session); + } + AuthenticationSnapshot _createSnapshot(Session session) { return AuthenticationSnapshot( session, From dd1b60b4f73de63dbd8f5c290eb7951b4b2d5041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 11:48:15 +0100 Subject: [PATCH 50/99] fix: use inner client on callback client --- packages/uni_app/lib/http/client/callback.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/uni_app/lib/http/client/callback.dart b/packages/uni_app/lib/http/client/callback.dart index d727701de..41d72bf05 100644 --- a/packages/uni_app/lib/http/client/callback.dart +++ b/packages/uni_app/lib/http/client/callback.dart @@ -3,16 +3,20 @@ import 'package:http/http.dart' as http; class CallbackClient extends http.BaseClient { CallbackClient( http.Client inner, { - required Future Function(http.BaseRequest) send, + required Future Function( + http.Client, + http.BaseRequest, + ) send, }) : _inner = inner, _send = send; final http.Client _inner; - final Future Function(http.BaseRequest) _send; + final Future Function(http.Client, http.BaseRequest) + _send; @override Future send(http.BaseRequest request) => - _send(request); + _send(_inner, request); @override void close() => _inner.close(); From efce93cd8d39f3b444febfc5628bcb16a445cff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 17:28:26 +0100 Subject: [PATCH 51/99] refactor: add suggestions --- .../uni_app/lib/app_links/uni_app_links.dart | 38 +++++++++++++++++++ packages/uni_app/lib/http/utils.dart | 7 +--- .../session/authentication_controller.dart | 2 +- .../lib/session/flows/base/session.dart | 19 ---------- .../session/flows/credentials/request.dart | 9 +++-- .../session/flows/federated/initiator.dart | 4 +- .../lib/session/flows/federated/request.dart | 2 +- .../session/logout/uni_logout_handler.dart | 12 +++++- .../lib/sigarra/endpoints/{ => api}/api.dart | 2 +- .../{ => authentication}/authentication.dart | 2 +- .../api/authentication/{ => login}/login.dart | 0 .../{ => authentication}/authentication.dart | 4 +- .../authentication/{ => login}/login.dart | 0 .../html/authentication/login/response.dart | 3 -- .../authentication/{ => logout}/logout.dart | 0 .../sigarra/endpoints/{ => html}/html.dart | 2 +- .../sigarra/endpoints/{ => oidc}/oidc.dart | 2 +- .../endpoints/oidc/{ => token}/token.dart | 0 packages/uni_app/lib/view/login/login.dart | 30 +++++---------- 19 files changed, 73 insertions(+), 65 deletions(-) create mode 100644 packages/uni_app/lib/app_links/uni_app_links.dart rename packages/uni_app/lib/sigarra/endpoints/{ => api}/api.dart (71%) rename packages/uni_app/lib/sigarra/endpoints/api/{ => authentication}/authentication.dart (66%) rename packages/uni_app/lib/sigarra/endpoints/api/authentication/{ => login}/login.dart (100%) rename packages/uni_app/lib/sigarra/endpoints/html/{ => authentication}/authentication.dart (76%) rename packages/uni_app/lib/sigarra/endpoints/html/authentication/{ => login}/login.dart (100%) rename packages/uni_app/lib/sigarra/endpoints/html/authentication/{ => logout}/logout.dart (100%) rename packages/uni_app/lib/sigarra/endpoints/{ => html}/html.dart (71%) rename packages/uni_app/lib/sigarra/endpoints/{ => oidc}/oidc.dart (67%) rename packages/uni_app/lib/sigarra/endpoints/oidc/{ => token}/token.dart (100%) diff --git a/packages/uni_app/lib/app_links/uni_app_links.dart b/packages/uni_app/lib/app_links/uni_app_links.dart new file mode 100644 index 000000000..048472f0c --- /dev/null +++ b/packages/uni_app/lib/app_links/uni_app_links.dart @@ -0,0 +1,38 @@ +import 'dart:async'; + +import 'package:app_links/app_links.dart'; + +final _authUri = Uri(scheme: 'pt.up.fe.ni.uni', host: 'auth'); + +extension _StripQueryParameters on Uri { + Uri stripQueryParameters() { + return Uri(scheme: scheme, host: host, path: path); + } +} + +class UniAppLinks { + final login = _AuthenticationAppLink( + redirectUri: _authUri.replace(path: '/login'), + ); + + final logout = _AuthenticationAppLink( + redirectUri: _authUri.replace(path: '/logout'), + ); +} + +class _AuthenticationAppLink { + _AuthenticationAppLink({required this.redirectUri}); + + final AppLinks _appLinks = AppLinks(); + final Uri redirectUri; + + Future intercept( + FutureOr Function(Uri redirectUri) callback) async { + final interceptedUri = _appLinks.uriLinkStream + .firstWhere((uri) => redirectUri == uri.stripQueryParameters()); + + await callback(redirectUri); + final data = await interceptedUri; + return data; + } +} diff --git a/packages/uni_app/lib/http/utils.dart b/packages/uni_app/lib/http/utils.dart index f8aa8bc54..8849371e6 100644 --- a/packages/uni_app/lib/http/utils.dart +++ b/packages/uni_app/lib/http/utils.dart @@ -10,10 +10,5 @@ List extractCookies(http.Response response) { return []; } - final cookies = []; - for (final value in setCookieHeaders) { - cookies.add(Cookie.fromSetCookieValue(value)); - } - - return cookies; + return setCookieHeaders.map(Cookie.fromSetCookieValue).toList(); } diff --git a/packages/uni_app/lib/session/authentication_controller.dart b/packages/uni_app/lib/session/authentication_controller.dart index 6747594e0..fef3e3bc9 100644 --- a/packages/uni_app/lib/session/authentication_controller.dart +++ b/packages/uni_app/lib/session/authentication_controller.dart @@ -64,7 +64,7 @@ class AuthenticationController { } bool _shouldInvalidate(Session session) { - // We invalidate if the is not an invalidation in progress already + // We invalidate if there is not an invalidation in progress already // and the session is the same as the current one. return _nextAuthentication == null && _currentSession == session; } diff --git a/packages/uni_app/lib/session/flows/base/session.dart b/packages/uni_app/lib/session/flows/base/session.dart index c670c9647..05f7f97c8 100644 --- a/packages/uni_app/lib/session/flows/base/session.dart +++ b/packages/uni_app/lib/session/flows/base/session.dart @@ -43,25 +43,6 @@ abstract class Session { String get mainFaculty => faculties.first; SessionRequest createRefreshRequest(); - - /// Executed when the authorization provided by this session is rejected. - /// - /// This is useful for performing cleanup operations, such as invalidating - /// session cookies, since they will no longer be used. - // @mustCallSuper - // FutureOr onRejection([http.Client? httpClient]) async { - // final client = httpClient ?? http.Client(); - - // try { - // await authentication.logout( - // options: FacultyRequestOptions( - // client: CookieClient(client, cookies: () => cookies), - // ), - // ); - // } catch (err, st) { - // unawaited(Sentry.captureException(err, stackTrace: st)); - // } - // } } class CookieConverter implements JsonConverter { diff --git a/packages/uni_app/lib/session/flows/credentials/request.dart b/packages/uni_app/lib/session/flows/credentials/request.dart index 0b4c68578..727935b29 100644 --- a/packages/uni_app/lib/session/flows/credentials/request.dart +++ b/packages/uni_app/lib/session/flows/credentials/request.dart @@ -3,9 +3,9 @@ import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/credentials/session.dart'; -import 'package:uni/sigarra/endpoints/api.dart'; -import 'package:uni/sigarra/endpoints/html.dart'; +import 'package:uni/sigarra/endpoints/api/api.dart'; import 'package:uni/sigarra/endpoints/html/authentication/login/response.dart'; +import 'package:uni/sigarra/endpoints/html/html.dart'; import 'package:uni/sigarra/options.dart'; class CredentialsSessionRequest extends SessionRequest { @@ -61,11 +61,12 @@ class CredentialsSessionRequest extends SessionRequest { http.Client httpClient, ) async { final api = SigarraApi(); + const tempFaculty = 'feup'; final loginResponse = await api.authentication.login.call( username: username, password: password, - options: FacultyRequestOptions(faculty: 'feup', client: httpClient), + options: FacultyRequestOptions(faculty: tempFaculty, client: httpClient), ); if (!loginResponse.success) { @@ -77,7 +78,7 @@ class CredentialsSessionRequest extends SessionRequest { username: info.username, password: password, cookies: info.cookies, - faculties: ['feup'], + faculties: [tempFaculty], ); } diff --git a/packages/uni_app/lib/session/flows/federated/initiator.dart b/packages/uni_app/lib/session/flows/federated/initiator.dart index 8da7a280c..1e7387a0d 100644 --- a/packages/uni_app/lib/session/flows/federated/initiator.dart +++ b/packages/uni_app/lib/session/flows/federated/initiator.dart @@ -7,13 +7,11 @@ class FederatedSessionInitiator extends SessionInitiator { FederatedSessionInitiator({ required this.realm, required this.clientId, - required this.redirectUri, required this.performAuthentication, }); final Uri realm; final String clientId; - final Uri redirectUri; final Future Function(Flow flow) performAuthentication; @override @@ -31,7 +29,7 @@ class FederatedSessionInitiator extends SessionInitiator { 'audience', 'uporto_data', ], - )..redirectUri = redirectUri; + ); final uri = await performAuthentication(flow); final credential = await flow.callback(uri.queryParameters); diff --git a/packages/uni_app/lib/session/flows/federated/request.dart b/packages/uni_app/lib/session/flows/federated/request.dart index 8d1a26b06..99728aa55 100644 --- a/packages/uni_app/lib/session/flows/federated/request.dart +++ b/packages/uni_app/lib/session/flows/federated/request.dart @@ -4,7 +4,7 @@ import 'package:uni/controller/fetchers/faculties_fetcher.dart'; import 'package:uni/session/exception.dart'; import 'package:uni/session/flows/base/request.dart'; import 'package:uni/session/flows/federated/session.dart'; -import 'package:uni/sigarra/endpoints/oidc.dart'; +import 'package:uni/sigarra/endpoints/oidc/oidc.dart'; import 'package:uni/sigarra/options.dart'; class FederatedSessionUserInfo { diff --git a/packages/uni_app/lib/session/logout/uni_logout_handler.dart b/packages/uni_app/lib/session/logout/uni_logout_handler.dart index 4aa53dd58..952dfc245 100644 --- a/packages/uni_app/lib/session/logout/uni_logout_handler.dart +++ b/packages/uni_app/lib/session/logout/uni_logout_handler.dart @@ -1,5 +1,6 @@ import 'dart:async'; +// import 'package:uni/app_links/uni_app_links.dart'; import 'package:uni/session/flows/base/session.dart'; import 'package:uni/session/flows/federated/session.dart'; import 'package:uni/session/logout/logout_handler.dart'; @@ -9,12 +10,21 @@ import 'package:url_launcher/url_launcher.dart'; class UniLogoutHandler extends LogoutHandler { @override FutureOr closeFederatedSession(FederatedSession session) async { - final logoutUri = session.credential.generateLogoutUrl(); + // final appLinks = UniAppLinks(); + + // await appLinks.logout.intercept((redirectUri) async { + final logoutUri = session.credential.generateLogoutUrl( + // redirectUri: redirectUri, + ); + if (logoutUri == null) { throw Exception('Failed to generate logout url'); } await launchUrl(logoutUri); + // }); + + // await closeInAppWebView(); } @override diff --git a/packages/uni_app/lib/sigarra/endpoints/api.dart b/packages/uni_app/lib/sigarra/endpoints/api/api.dart similarity index 71% rename from packages/uni_app/lib/sigarra/endpoints/api.dart rename to packages/uni_app/lib/sigarra/endpoints/api/api.dart index b0dbf53ad..33bbcbec7 100644 --- a/packages/uni_app/lib/sigarra/endpoints/api.dart +++ b/packages/uni_app/lib/sigarra/endpoints/api/api.dart @@ -1,4 +1,4 @@ -import 'package:uni/sigarra/endpoints/api/authentication.dart'; +import 'package:uni/sigarra/endpoints/api/authentication/authentication.dart'; import 'package:uni/utils/lazy.dart'; class SigarraApi { diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/authentication.dart similarity index 66% rename from packages/uni_app/lib/sigarra/endpoints/api/authentication.dart rename to packages/uni_app/lib/sigarra/endpoints/api/authentication/authentication.dart index 5bdc1f223..c112747a5 100644 --- a/packages/uni_app/lib/sigarra/endpoints/api/authentication.dart +++ b/packages/uni_app/lib/sigarra/endpoints/api/authentication/authentication.dart @@ -1,4 +1,4 @@ -import 'package:uni/sigarra/endpoints/api/authentication/login.dart'; +import 'package:uni/sigarra/endpoints/api/authentication/login/login.dart'; import 'package:uni/utils/lazy.dart'; class SigarraApiAuthentication { diff --git a/packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart b/packages/uni_app/lib/sigarra/endpoints/api/authentication/login/login.dart similarity index 100% rename from packages/uni_app/lib/sigarra/endpoints/api/authentication/login.dart rename to packages/uni_app/lib/sigarra/endpoints/api/authentication/login/login.dart diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/authentication.dart similarity index 76% rename from packages/uni_app/lib/sigarra/endpoints/html/authentication.dart rename to packages/uni_app/lib/sigarra/endpoints/html/authentication/authentication.dart index 90069160c..6fe7810fa 100644 --- a/packages/uni_app/lib/sigarra/endpoints/html/authentication.dart +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication/authentication.dart @@ -1,5 +1,5 @@ -import 'package:uni/sigarra/endpoints/html/authentication/login.dart'; -import 'package:uni/sigarra/endpoints/html/authentication/logout.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/login/login.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/logout/logout.dart'; import 'package:uni/utils/lazy.dart'; class SigarraHtmlAuthentication { diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/login.dart similarity index 100% rename from packages/uni_app/lib/sigarra/endpoints/html/authentication/login.dart rename to packages/uni_app/lib/sigarra/endpoints/html/authentication/login/login.dart diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart index c5e436175..4399da48f 100644 --- a/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart +++ b/packages/uni_app/lib/sigarra/endpoints/html/authentication/login/response.dart @@ -18,8 +18,5 @@ enum LoginFailureReason { class LoginFailedResponse extends LoginResponse { const LoginFailedResponse({required this.reason}) : super(success: false); - @override - bool get success => false; - final LoginFailureReason reason; } diff --git a/packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart b/packages/uni_app/lib/sigarra/endpoints/html/authentication/logout/logout.dart similarity index 100% rename from packages/uni_app/lib/sigarra/endpoints/html/authentication/logout.dart rename to packages/uni_app/lib/sigarra/endpoints/html/authentication/logout/logout.dart diff --git a/packages/uni_app/lib/sigarra/endpoints/html.dart b/packages/uni_app/lib/sigarra/endpoints/html/html.dart similarity index 71% rename from packages/uni_app/lib/sigarra/endpoints/html.dart rename to packages/uni_app/lib/sigarra/endpoints/html/html.dart index 9f92ce067..ed131668d 100644 --- a/packages/uni_app/lib/sigarra/endpoints/html.dart +++ b/packages/uni_app/lib/sigarra/endpoints/html/html.dart @@ -1,4 +1,4 @@ -import 'package:uni/sigarra/endpoints/html/authentication.dart'; +import 'package:uni/sigarra/endpoints/html/authentication/authentication.dart'; import 'package:uni/utils/lazy.dart'; class SigarraHtml { diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/oidc.dart similarity index 67% rename from packages/uni_app/lib/sigarra/endpoints/oidc.dart rename to packages/uni_app/lib/sigarra/endpoints/oidc/oidc.dart index 3f9792644..82201ffe3 100644 --- a/packages/uni_app/lib/sigarra/endpoints/oidc.dart +++ b/packages/uni_app/lib/sigarra/endpoints/oidc/oidc.dart @@ -1,4 +1,4 @@ -import 'package:uni/sigarra/endpoints/oidc/token.dart'; +import 'package:uni/sigarra/endpoints/oidc/token/token.dart'; import 'package:uni/utils/lazy.dart'; class SigarraOidc { diff --git a/packages/uni_app/lib/sigarra/endpoints/oidc/token.dart b/packages/uni_app/lib/sigarra/endpoints/oidc/token/token.dart similarity index 100% rename from packages/uni_app/lib/sigarra/endpoints/oidc/token.dart rename to packages/uni_app/lib/sigarra/endpoints/oidc/token/token.dart diff --git a/packages/uni_app/lib/view/login/login.dart b/packages/uni_app/lib/view/login/login.dart index 32dff3968..cab5cfcb2 100644 --- a/packages/uni_app/lib/view/login/login.dart +++ b/packages/uni_app/lib/view/login/login.dart @@ -1,12 +1,12 @@ import 'dart:async'; -import 'package:app_links/app_links.dart'; import 'package:flutter/gestures.dart'; 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/app_links/uni_app_links.dart'; import 'package:uni/controller/networking/url_launcher.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/login_exceptions.dart'; @@ -56,28 +56,15 @@ class LoginPageViewState extends State @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); } @override void dispose() { - // TODO(thePeras): Fix error used after being disposed - // usernameController.dispose(); - // passwordController.dispose(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } - Future getInterceptedUri() async { - final appLinks = AppLinks(); - final uri = - await appLinks.uriLinkStream.firstWhere((uri) => uri.host == 'auth'); - - Logger().d('AppLinks intercepted: $uri'); - return uri; - } - Future _login() async { final sessionProvider = Provider.of(context, listen: false); @@ -156,25 +143,26 @@ class LoginPageViewState extends State _loggingIn = true; }); + final appLinks = UniAppLinks(); + await sessionProvider.login( FederatedSessionInitiator( clientId: clientId, realm: Uri.parse(realm), - redirectUri: Uri.parse('pt.up.fe.ni.uni://auth'), performAuthentication: (flow) async { - final interceptedUri = getInterceptedUri(); + final data = await appLinks.login.intercept((redirectUri) async { + flow.redirectUri = redirectUri; + await launchUrl(flow.authenticationUri); + }); - final authenticationUri = flow.authenticationUri; - await launchUrl(authenticationUri); + await closeInAppWebView(); - return interceptedUri; + return data; }, ), persistentSession: _keepSignedIn, ); - await closeInAppWebView(); - setState(() { _intercepting = true; _loggingIn = true; From f82beca9c9f7893a0141ce340a241242aba522ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 17:30:06 +0100 Subject: [PATCH 52/99] style: add trailing comma --- packages/uni_app/lib/app_links/uni_app_links.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/app_links/uni_app_links.dart b/packages/uni_app/lib/app_links/uni_app_links.dart index 048472f0c..e0a7c5a20 100644 --- a/packages/uni_app/lib/app_links/uni_app_links.dart +++ b/packages/uni_app/lib/app_links/uni_app_links.dart @@ -27,7 +27,8 @@ class _AuthenticationAppLink { final Uri redirectUri; Future intercept( - FutureOr Function(Uri redirectUri) callback) async { + FutureOr Function(Uri redirectUri) callback, + ) async { final interceptedUri = _appLinks.uriLinkStream .firstWhere((uri) => redirectUri == uri.stripQueryParameters()); From fa3f3bebf358093cbbfd85ad577ad4d24f64238a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 12 Sep 2024 17:31:37 +0100 Subject: [PATCH 53/99] fix: lectures are no longer stored with null blocks --- .../local_storage/database/app_lectures_database.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart index a7c1c7362..82bd3a253 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_lectures_database.dart @@ -16,11 +16,11 @@ class AppLecturesDatabase extends AppDatabase> { createScript, ], onUpgrade: migrate, - version: 9, + version: 10, ); static const createScript = ''' CREATE TABLE lectures(subject TEXT, typeClass TEXT, - startTime TEXT, endTime TEXT, blocks INTEGER, room TEXT, teacher TEXT, classNumber TEXT, occurrId INTEGER)'''; + startTime TEXT, endTime TEXT, room TEXT, teacher TEXT, classNumber TEXT, occurrId INTEGER)'''; /// Returns a list containing all of the lectures stored in this database. Future> lectures() async { @@ -28,11 +28,11 @@ CREATE TABLE lectures(subject TEXT, typeClass TEXT, final List> maps = await db.query('lectures'); return List.generate(maps.length, (i) { - return Lecture.fromApi( + return Lecture( maps[i]['subject'] as String, maps[i]['typeClass'] as String, DateTime.parse(maps[i]['startTime'] as String), - maps[i]['blocks'] as int, + DateTime.parse(maps[i]['endTime'] as String), maps[i]['room'] as String, maps[i]['teacher'] as String, maps[i]['classNumber'] as String, From 7291101a599b5c251e9b75fb6f71807b3e9eac59 Mon Sep 17 00:00:00 2001 From: limwa Date: Thu, 12 Sep 2024 21:22:51 +0000 Subject: [PATCH 54/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 0d582b7de..c3d0a9ab8 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.28+291 +1.9.0-beta.29+292 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 50d15b612..8703f0e61 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.28+291 +version: 1.9.0-beta.29+292 environment: sdk: ">=3.4.0 <4.0.0" From d7a23e0fc548d9ab5d4e29ffd1ba64d97c7270fb Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 12 Sep 2024 23:36:03 +0100 Subject: [PATCH 55/99] cleaning code --- .../fetchers/library_occupation_fetcher.dart | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 180ac1f5f..9970c8601 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; import 'package:uni/model/entities/library_occupation.dart'; @@ -20,30 +21,34 @@ class LibraryOccupationFetcher { Future getLibraryOccupation() async { final libraryOccupation = LibraryOccupation(0, 0); - for (var i = 0; i < floorMaxSeats.entries.length; i++) { - final floor = floorMaxSeats.entries.elementAt(i); + await Future.wait( + floorMaxSeats.entries.mapIndexed((i, entry) async { + final url = Uri.parse(baseUrl).replace( + queryParameters: { + 'token': entry.key, + }, + ); - final url = Uri.parse(baseUrl).replace( - queryParameters: { - 'token': floor.key, - }, - ); + final response = await http.get(url); - final response = await http.get(url); + final floorOccupation = + processFloorOccupation(response, entry.value, i); - final floorOccupation = processFloorOccupation(response, i); - - libraryOccupation.addFloor(floorOccupation); - } + libraryOccupation.addFloor(floorOccupation); + }), + ); return libraryOccupation; } - FloorOccupation processFloorOccupation(Response response, int floor) { + FloorOccupation processFloorOccupation( + Response response, + int floorCapacity, + int floor, + ) { final responseBody = jsonDecode(response.body) as Map; final floorOccupation = int.parse(responseBody['progress'].toString()); - final floorCapacity = floorMaxSeats.entries.elementAt(floor).value; return FloorOccupation( floor + 1, From 7acad75e3ca02757f537ef73cce51ce614df6fe0 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 12 Sep 2024 23:40:58 +0100 Subject: [PATCH 56/99] changing map to list of tuples --- .../fetchers/library_occupation_fetcher.dart | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index 9970c8601..d26662319 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -3,36 +3,37 @@ import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; import 'package:http/http.dart'; +import 'package:tuple/tuple.dart'; import 'package:uni/model/entities/library_occupation.dart'; /// Fetch the library occupation from Google Sheets class LibraryOccupationFetcher { String baseUrl = 'https://webapi.affluences.com/api/fillRate?'; - Map floorMaxSeats = { - 'BruV6IlujdwAe1': 72, - 'cEhyzJZvC5nHSr': 114, - 'iceVfgwZWaZRhV': 114, - '1yLPz9X0CNsg27': 114, - 'keu1j5zERlQn90': 40, - 'bY7K1v43HiAq55': 90, - }; + static const List> floorMaxSeats = [ + Tuple2('BruV6IlujdwAe1', 72), + Tuple2('cEhyzJZvC5nHSr', 114), + Tuple2('iceVfgwZWaZRhV', 114), + Tuple2('1yLPz9X0CNsg27', 114), + Tuple2('keu1j5zERlQn90', 40), + Tuple2('bY7K1v43HiAq55', 90), + ]; Future getLibraryOccupation() async { final libraryOccupation = LibraryOccupation(0, 0); await Future.wait( - floorMaxSeats.entries.mapIndexed((i, entry) async { + floorMaxSeats.mapIndexed((i, entry) async { final url = Uri.parse(baseUrl).replace( queryParameters: { - 'token': entry.key, + 'token': entry.item1, }, ); final response = await http.get(url); final floorOccupation = - processFloorOccupation(response, entry.value, i); + processFloorOccupation(response, entry.item2, i); libraryOccupation.addFloor(floorOccupation); }), From d5f2715a500299c07d5058305a19072decebba7e Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 13 Sep 2024 00:03:50 +0100 Subject: [PATCH 57/99] refreshing session over time while user is logged in --- .../uni_app/lib/model/providers/startup/session_provider.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/uni_app/lib/model/providers/startup/session_provider.dart b/packages/uni_app/lib/model/providers/startup/session_provider.dart index e1f9500b9..2c086cc41 100644 --- a/packages/uni_app/lib/model/providers/startup/session_provider.dart +++ b/packages/uni_app/lib/model/providers/startup/session_provider.dart @@ -52,6 +52,10 @@ class SessionProvider extends StateProviderNotifier { final newSnapshot = await controller.snapshot; final newState = newSnapshot.session; + if (await PreferencesController.isSessionPersistent()) { + await PreferencesController.saveSession(newSnapshot.session); + } + return newState; } From a3b12b9b1f6674948d2307d66277921d5c129f82 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 12 Sep 2024 23:25:45 +0000 Subject: [PATCH 58/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index c3d0a9ab8..b5f65d069 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.29+292 +1.9.0-beta.30+293 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 8703f0e61..30924bade 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.29+292 +version: 1.9.0-beta.30+293 environment: sdk: ">=3.4.0 <4.0.0" From db38d5fc6d959c0672fb7e9110600d4626e2d6b1 Mon Sep 17 00:00:00 2001 From: limwa Date: Thu, 12 Sep 2024 23:32:59 +0000 Subject: [PATCH 59/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index b5f65d069..9506b02e9 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.30+293 +1.9.0-beta.31+294 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 30924bade..f643c1557 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.30+293 +version: 1.9.0-beta.31+294 environment: sdk: ">=3.4.0 <4.0.0" From dd10d371be8e3cf8d4d02ecf1fc1a4f42b0ae021 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 12 Sep 2024 23:40:06 +0000 Subject: [PATCH 60/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 9506b02e9..fd5115fd1 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.31+294 +1.9.0-beta.32+295 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index f643c1557..23dfa3c4b 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.31+294 +version: 1.9.0-beta.32+295 environment: sdk: ">=3.4.0 <4.0.0" From 104b2ed828aecf6c2b5193ef2b7db4dc53648e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 13 Sep 2024 19:16:43 +0100 Subject: [PATCH 61/99] fix: add post logout url --- .../uni_app/lib/session/logout/uni_logout_handler.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/session/logout/uni_logout_handler.dart b/packages/uni_app/lib/session/logout/uni_logout_handler.dart index 952dfc245..00363d0be 100644 --- a/packages/uni_app/lib/session/logout/uni_logout_handler.dart +++ b/packages/uni_app/lib/session/logout/uni_logout_handler.dart @@ -1,6 +1,6 @@ import 'dart:async'; -// import 'package:uni/app_links/uni_app_links.dart'; +import 'package:uni/app_links/uni_app_links.dart'; import 'package:uni/session/flows/base/session.dart'; import 'package:uni/session/flows/federated/session.dart'; import 'package:uni/session/logout/logout_handler.dart'; @@ -10,12 +10,12 @@ import 'package:url_launcher/url_launcher.dart'; class UniLogoutHandler extends LogoutHandler { @override FutureOr closeFederatedSession(FederatedSession session) async { - // final appLinks = UniAppLinks(); + final appLinks = UniAppLinks(); // await appLinks.logout.intercept((redirectUri) async { final logoutUri = session.credential.generateLogoutUrl( - // redirectUri: redirectUri, - ); + redirectUri: appLinks.logout.redirectUri, + ); if (logoutUri == null) { throw Exception('Failed to generate logout url'); From e0d8d973e592aba2f427f1d0b0847aa5938a322f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 13 Sep 2024 21:27:08 +0100 Subject: [PATCH 62/99] fix: error when unit bibliography is null --- .../lib/controller/parsers/parser_course_unit_info.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart index 5e121ae2d..3d3337315 100644 --- a/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart +++ b/packages/uni_app/lib/controller/parsers/parser_course_unit_info.dart @@ -58,9 +58,8 @@ Future parseSheet(http.Response response) async { return Professor.fromJson(element as Map); }).toList(); - final books = (json['bibliografia'] as List) + final books = (json['bibliografia'] as List? ?? []) .map((element) => element as Map) - .toList() .map((element) { return Book( title: element['titulo'].toString(), From 67967c5e17519fd8d3068aacfc86fe81306e9258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 13 Sep 2024 21:33:35 +0100 Subject: [PATCH 63/99] fix: error when null progress in library --- .../lib/controller/fetchers/library_occupation_fetcher.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart index d26662319..f0616bd13 100644 --- a/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/library_occupation_fetcher.dart @@ -49,7 +49,7 @@ class LibraryOccupationFetcher { ) { final responseBody = jsonDecode(response.body) as Map; - final floorOccupation = int.parse(responseBody['progress'].toString()); + final floorOccupation = responseBody['progress'] as int? ?? 0; return FloorOccupation( floor + 1, From 4bedbbb9582602b0513581655129910d5e42b07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Sat, 14 Sep 2024 00:09:48 +0100 Subject: [PATCH 64/99] ci: upgrade upload-artifact --- .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 792f41516..9bb70dd5a 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -134,7 +134,7 @@ jobs: flutter build appbundle - name: Upload App Bundle - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: appbundle if-no-files-found: error From a17eca43edc348e05c58760473b825081be67909 Mon Sep 17 00:00:00 2001 From: niaefeup-admin Date: Fri, 13 Sep 2024 23:59:57 +0000 Subject: [PATCH 65/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index fd5115fd1..c6da94cfe 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.9.0-beta.32+295 +1.10.0-beta.0+297 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 23dfa3c4b..1540e60c0 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.9.0-beta.32+295 +version: 1.10.0-beta.0+297 environment: sdk: ">=3.4.0 <4.0.0" From 10af0cb8891bbc0a3fd1a184940aa59a42db51b6 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sat, 14 Sep 2024 12:55:58 +0100 Subject: [PATCH 66/99] fixing and modifying ios build for next release --- .../ios/Flutter/AppFrameworkInfo.plist | 2 +- packages/uni_app/ios/Podfile | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- packages/uni_app/pubspec.lock | 192 +----------------- packages/uni_app/pubspec.yaml | 1 - 6 files changed, 12 insertions(+), 189 deletions(-) diff --git a/packages/uni_app/ios/Flutter/AppFrameworkInfo.plist b/packages/uni_app/ios/Flutter/AppFrameworkInfo.plist index 9625e105d..7c5696400 100644 --- a/packages/uni_app/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/uni_app/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/packages/uni_app/ios/Podfile b/packages/uni_app/ios/Podfile index 15c570493..d97f17e22 100644 --- a/packages/uni_app/ios/Podfile +++ b/packages/uni_app/ios/Podfile @@ -41,4 +41,4 @@ 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 +end diff --git a/packages/uni_app/ios/Runner.xcodeproj/project.pbxproj b/packages/uni_app/ios/Runner.xcodeproj/project.pbxproj index 889daa0d4..f3ff7eddb 100644 --- a/packages/uni_app/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/uni_app/ios/Runner.xcodeproj/project.pbxproj @@ -214,7 +214,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 378A17102ACF02E100B89C1C = { diff --git a/packages/uni_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/uni_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 28bc2d73f..5b0c182f6 100644 --- a/packages/uni_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/uni_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 15 Sep 2024 17:01:35 +0100 Subject: [PATCH 67/99] fix a null uc id error --- .../local_storage/database/app_course_units_database.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart index 85d895df8..ee3cc8aa2 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart @@ -21,7 +21,7 @@ class AppCourseUnitsDatabase extends AppDatabase> { final List> maps = await db.query('course_units'); return List.generate(maps.length, (i) { return CourseUnit( - id: maps[i]['ucurr_id'] as int, + id: maps[i]['ucurr_id'] as int?, code: maps[i]['ucurr_codigo'] as String, abbreviation: maps[i]['ucurr_sigla'] as String, name: maps[i]['ucurr_nome'] as String, From f077d5fdc85f482844a0555d55ae7014221ecf6a Mon Sep 17 00:00:00 2001 From: DGoiana Date: Sun, 15 Sep 2024 20:41:13 +0100 Subject: [PATCH 68/99] changing db schema --- .../database/app_course_units_database.dart | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart b/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart index ee3cc8aa2..5418d240a 100644 --- a/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart +++ b/packages/uni_app/lib/controller/local_storage/database/app_course_units_database.dart @@ -9,12 +9,14 @@ class AppCourseUnitsDatabase extends AppDatabase> { : super( 'course_units.db', [createScript], + onUpgrade: migrate, + version: 2, ); static const String createScript = '''CREATE TABLE course_units(ucurr_id INTEGER, ucurr_codigo TEXT, ucurr_sigla TEXT , ''' '''ucurr_nome TEXT, ano INTEGER, ocorr_id INTEGER, per_codigo TEXT, ''' '''per_nome TEXT, tipo TEXT, estado TEXT, resultado_melhor TEXT, resultado_ects TEXT, ''' - '''resultado_insc TEXT, creditos_ects REAL, schoolYear TEXT)'''; + '''ectsGrade TEXT, resultado_insc TEXT, creditos_ects REAL, schoolYear TEXT)'''; Future> courseUnits() async { final db = await getDatabase(); @@ -55,6 +57,17 @@ class AppCourseUnitsDatabase extends AppDatabase> { await db.delete('course_units'); } + static FutureOr migrate( + Database db, + int oldVersion, + int newVersion, + ) async { + final batch = db.batch() + ..execute('DROP TABLE IF EXISTS course_units') + ..execute(createScript); + await batch.commit(); + } + @override Future saveToDatabase(List data) async { await deleteCourseUnits(); From ee1ae83558f4672e7340bfc99b14bf260b28f3e9 Mon Sep 17 00:00:00 2001 From: limwa Date: Sun, 15 Sep 2024 20:27:22 +0000 Subject: [PATCH 69/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index c6da94cfe..790e60652 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.0+297 +1.10.0-beta.1+298 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 1540e60c0..2b1496a50 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.0+297 +version: 1.10.0-beta.1+298 environment: sdk: ">=3.4.0 <4.0.0" From b4d58dafd3af2d84cca49aa54219da049dbb6ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Sun, 15 Sep 2024 23:44:37 +0100 Subject: [PATCH 70/99] fix: no information for mobility students --- packages/uni_app/lib/model/entities/course.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/uni_app/lib/model/entities/course.dart b/packages/uni_app/lib/model/entities/course.dart index ca287f149..8fa730695 100644 --- a/packages/uni_app/lib/model/entities/course.dart +++ b/packages/uni_app/lib/model/entities/course.dart @@ -14,7 +14,7 @@ part '../../generated/model/entities/course.g.dart'; @JsonSerializable(createFactory: false) class Course { Course({ - required this.id, + this.id, this.festId, this.name, this.abbreviation, @@ -28,7 +28,7 @@ class Course { factory Course.fromJson(Map json) { return Course( - id: json['cur_id'] as int, + id: json['cur_id'] as int?, festId: json['fest_id'] as int?, name: json['cur_nome'] as String?, abbreviation: json['abbreviation'] as String?, @@ -41,8 +41,8 @@ class Course { ); } @JsonKey(name: 'cur_id') - final int id; - @JsonKey(name: 'fest_id ') + final int? id; + @JsonKey(name: 'fest_id') final int? festId; @JsonKey(name: 'cur_nome') final String? name; From 67f1005638be2b0e6a34a4ed92d9c70d148a10b5 Mon Sep 17 00:00:00 2001 From: limwa Date: Sun, 15 Sep 2024 22:54:43 +0000 Subject: [PATCH 71/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 790e60652..a725cffd9 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.1+298 +1.10.0-beta.2+299 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 78251c356..0c49f3224 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.1+298 +version: 1.10.0-beta.2+299 environment: sdk: ">=3.4.0 <4.0.0" From d9c75b6d15672515590d9e03864fa632dd278b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Sun, 15 Sep 2024 23:56:30 +0100 Subject: [PATCH 72/99] refactor: remove profile from lecture provider --- .../fetchers/schedule_fetcher/schedule_fetcher.dart | 3 +-- .../fetchers/schedule_fetcher/schedule_fetcher_api.dart | 3 +-- .../fetchers/schedule_fetcher/schedule_fetcher_new_api.dart | 3 +-- .../uni_app/lib/model/providers/lazy/lecture_provider.dart | 6 +++--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart index 63544594f..03edab956 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher.dart @@ -1,13 +1,12 @@ import 'package:uni/controller/fetchers/session_dependant_fetcher.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's schedule. abstract class ScheduleFetcher extends SessionDependantFetcher { // Returns the user's lectures. - Future> getLectures(Session session, Profile profile); + Future> getLectures(Session session); List getWeeks(DateTime now) { final week = Week(start: now); diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart index 7efc35063..0c7da4f56 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_api.dart @@ -3,7 +3,6 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/schedule/api/parser.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/utils/time/week.dart'; import 'package:uni/session/flows/base/session.dart'; @@ -19,7 +18,7 @@ class ScheduleFetcherApi extends ScheduleFetcher { /// Fetches the user's lectures from the faculties' API. @override - Future> getLectures(Session session, Profile profile) async { + Future> getLectures(Session session) async { final dates = getDates(); final urls = getEndpoints(session); diff --git a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart index e42f24e30..9ab5b041f 100644 --- a/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart +++ b/packages/uni_app/lib/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart @@ -2,7 +2,6 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher.dart'; import 'package:uni/controller/networking/network_router.dart'; import 'package:uni/controller/parsers/schedule/new_api/parser.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/profile.dart'; import 'package:uni/session/flows/base/session.dart'; /// Class for fetching the user's lectures from the schedule's HTML page. @@ -17,7 +16,7 @@ class ScheduleFetcherNewApi extends ScheduleFetcher { /// Fetches the user's lectures from the schedule's HTML page. @override - Future> getLectures(Session session, Profile profile) async { + Future> getLectures(Session session) async { final endpoints = getEndpoints(session); final lectiveYear = getLectiveYear(DateTime.now()); diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index d7a3d4de4..0d7b61621 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -46,11 +46,11 @@ class LectureProvider extends StateProviderNotifier> { Session session, Profile profile, ) => - fetcher?.getLectures(session, profile) ?? getLectures(session, profile); + fetcher?.getLectures(session) ?? getLectures(session, profile); Future> getLectures(Session session, Profile profile) { - return ScheduleFetcherApi().getLectures(session, profile).catchError( - (e) => ScheduleFetcherNewApi().getLectures(session, profile), + return ScheduleFetcherApi().getLectures(session).catchError( + (e) => ScheduleFetcherNewApi().getLectures(session), ); } } From 1e26ab70fbef18088c0c8984cc34d8a235f5914f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Sun, 15 Sep 2024 23:58:20 +0100 Subject: [PATCH 73/99] refactor: remove more profile references from lecture provider --- .../lib/model/providers/lazy/lecture_provider.dart | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart index 0d7b61621..9f0f178e5 100644 --- a/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart +++ b/packages/uni_app/lib/model/providers/lazy/lecture_provider.dart @@ -5,7 +5,6 @@ import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_api.da import 'package:uni/controller/fetchers/schedule_fetcher/schedule_fetcher_new_api.dart'; import 'package:uni/controller/local_storage/database/app_lectures_database.dart'; import 'package:uni/model/entities/lecture.dart'; -import 'package:uni/model/entities/profile.dart'; import 'package:uni/model/providers/state_provider_notifier.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/session/flows/base/session.dart'; @@ -23,17 +22,14 @@ class LectureProvider extends StateProviderNotifier> { Future> loadFromRemote(StateProviders stateProviders) async { return fetchUserLectures( stateProviders.sessionProvider.state!, - stateProviders.profileProvider.state!, ); } Future> fetchUserLectures( - Session session, - Profile profile, { + Session session, { ScheduleFetcher? fetcher, }) async { - final lectures = - await getLecturesFromFetcherOrElse(fetcher, session, profile); + final lectures = await getLecturesFromFetcherOrElse(fetcher, session); final db = AppLecturesDatabase(); await db.saveIfPersistentSession(lectures); @@ -44,11 +40,10 @@ class LectureProvider extends StateProviderNotifier> { Future> getLecturesFromFetcherOrElse( ScheduleFetcher? fetcher, Session session, - Profile profile, ) => - fetcher?.getLectures(session) ?? getLectures(session, profile); + fetcher?.getLectures(session) ?? getLectures(session); - Future> getLectures(Session session, Profile profile) { + Future> getLectures(Session session) { return ScheduleFetcherApi().getLectures(session).catchError( (e) => ScheduleFetcherNewApi().getLectures(session), ); From 22a6719cc010082838b9b70641e763c2e84808e1 Mon Sep 17 00:00:00 2001 From: limwa Date: Mon, 16 Sep 2024 06:52:07 +0000 Subject: [PATCH 74/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index a725cffd9..8c59f4977 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.2+299 +1.10.0-beta.3+300 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 0c49f3224..0dd0e676c 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.2+299 +version: 1.10.0-beta.3+300 environment: sdk: ">=3.4.0 <4.0.0" From 8dbc59e7bf96fa3e169920d865772dc9df75278d Mon Sep 17 00:00:00 2001 From: limwa Date: Mon, 16 Sep 2024 07:42:30 +0000 Subject: [PATCH 75/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 8c59f4977..53b8d426e 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.3+300 +1.10.0-beta.4+301 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 0dd0e676c..653de31da 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.3+300 +version: 1.10.0-beta.4+301 environment: sdk: ">=3.4.0 <4.0.0" From fc9e34973b2aa506ad1cd49425288142f55ceefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 16 Sep 2024 12:33:25 +0100 Subject: [PATCH 76/99] fix: add mobility course name --- packages/uni_app/lib/model/entities/course.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/model/entities/course.dart b/packages/uni_app/lib/model/entities/course.dart index 8fa730695..25a978382 100644 --- a/packages/uni_app/lib/model/entities/course.dart +++ b/packages/uni_app/lib/model/entities/course.dart @@ -27,10 +27,15 @@ class Course { }); factory Course.fromJson(Map json) { + var name = json['cur_nome'] as String?; + if (name == null || name.isEmpty) { + name = json['fest_tipo_descr'] as String?; + } + return Course( id: json['cur_id'] as int?, festId: json['fest_id'] as int?, - name: json['cur_nome'] as String?, + name: name, abbreviation: json['abbreviation'] as String?, currYear: json['ano_curricular'] as String?, firstEnrollment: json['fest_a_lect_1_insc'] as int?, From 0e464766148e43d8889969f4c26a3645c956d610 Mon Sep 17 00:00:00 2001 From: limwa Date: Mon, 16 Sep 2024 12:59:37 +0000 Subject: [PATCH 77/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 53b8d426e..49565d6df 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.4+301 +1.10.0-beta.5+302 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 653de31da..606fa1794 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.4+301 +version: 1.10.0-beta.5+302 environment: sdk: ">=3.4.0 <4.0.0" From 61b3ecbde38aa7ce9e88f6bc9cde00c19b9f9f0c Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 16 Sep 2024 14:51:49 +0100 Subject: [PATCH 78/99] adding null information check --- .../widgets/course_unit_sheet.dart | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart index f5cdb1fd5..220437374 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart @@ -39,16 +39,17 @@ class CourseUnitSheetView extends StatelessWidget { ), _buildCard('Programa', courseUnitSheet.content), _buildCard('Avaliação', courseUnitSheet.evaluation), - const Opacity( - opacity: 0.25, - child: Divider(color: Colors.grey), - ), - const Text( - 'Bibliografia', - style: TextStyle(fontSize: 20), - ), - if (courseUnitSheet.books.isNotEmpty) + if (courseUnitSheet.books.isNotEmpty) ...[ + const Opacity( + opacity: 0.25, + child: Divider(color: Colors.grey), + ), + const Text( + 'Bibliografia', + style: TextStyle(fontSize: 20), + ), buildBooksRow(context, courseUnitSheet.books), + ], ], ), ), @@ -215,7 +216,7 @@ Widget buildBooksRow(BuildContext context, List books) { Widget _buildCard( String sectionTitle, - dynamic sectionContent, + String sectionContent, ) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), @@ -226,7 +227,11 @@ Widget _buildCard( child: Divider(color: Colors.grey), ), GenericExpandable( - content: HtmlWidget(sectionContent.toString()), + content: HtmlWidget( + sectionContent != 'null' + ? sectionContent + : 'Sem informações para apresentar', + ), title: sectionTitle, ), ], From f51466135c4d0f2c663c17a2a7c0c2d2487e638d Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 16 Sep 2024 16:38:41 +0100 Subject: [PATCH 79/99] localizing --- .../lib/generated/intl/messages_all.dart | 9 +- .../lib/generated/intl/messages_en.dart | 439 +++++++---------- .../lib/generated/intl/messages_pt_PT.dart | 440 +++++++----------- packages/uni_app/lib/generated/l10n.dart | 51 +- packages/uni_app/lib/l10n/intl_en.arb | 6 + packages/uni_app/lib/l10n/intl_pt_PT.arb | 6 + .../widgets/course_unit_sheet.dart | 23 +- 7 files changed, 400 insertions(+), 574 deletions(-) diff --git a/packages/uni_app/lib/generated/intl/messages_all.dart b/packages/uni_app/lib/generated/intl/messages_all.dart index 6b3ebeae5..fb1bd2689 100644 --- a/packages/uni_app/lib/generated/intl/messages_all.dart +++ b/packages/uni_app/lib/generated/intl/messages_all.dart @@ -38,8 +38,9 @@ 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); + localeName, + (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { return new Future.value(false); } @@ -59,8 +60,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var 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/packages/uni_app/lib/generated/intl/messages_en.dart b/packages/uni_app/lib/generated/intl/messages_en.dart index 595583f38..78777d17f 100644 --- a/packages/uni_app/lib/generated/intl/messages_en.dart +++ b/packages/uni_app/lib/generated/intl/messages_en.dart @@ -21,280 +21,173 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "last refresh at ${time}"; - static m1(time) => - "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + static m1(time) => "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - 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', - 'percurso_academico': 'Academic Path', - 'transportes': 'Transports', - 'faculdade': 'Faculty', - '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', 'percurso_academico': 'Academic Path', 'transportes': 'Transports', 'faculdade': 'Faculty', 'other': 'Other', })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about": MessageLookupByLibrary.simpleMessage("About us"), - "academic_services": - MessageLookupByLibrary.simpleMessage("Academic services"), - "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!"), - "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:"), - "banner_info": MessageLookupByLibrary.simpleMessage( - "We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), - "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( - "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"), - "change": MessageLookupByLibrary.simpleMessage("Change"), - "change_prompt": MessageLookupByLibrary.simpleMessage( - "Do you want to change the password?"), - "check_internet": MessageLookupByLibrary.simpleMessage( - "Check your internet connection"), - "class_registration": - MessageLookupByLibrary.simpleMessage("Class Registration"), - "collect_usage_stats": - MessageLookupByLibrary.simpleMessage("Collect usage statistics"), - "college": MessageLookupByLibrary.simpleMessage("College: "), - "college_select": - MessageLookupByLibrary.simpleMessage("select your college(s)"), - "conclude": MessageLookupByLibrary.simpleMessage("Done"), - "configured_buses": - MessageLookupByLibrary.simpleMessage("Configured Buses"), - "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), - "confirm_logout": MessageLookupByLibrary.simpleMessage( - "Do you really want to log out? Your local data will be deleted and you will have to log in again."), - "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"), - "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"), - "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B (B-142)"), - "download_error": - MessageLookupByLibrary.simpleMessage("Error downloading the file"), - "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("Exams Filter Settings"), - "exit_confirm": - MessageLookupByLibrary.simpleMessage("Do you really want to exit?"), - "expired_password": - MessageLookupByLibrary.simpleMessage("Your password has expired"), - "fail_to_authenticate": - MessageLookupByLibrary.simpleMessage("Failed to authenticate"), - "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), - "fee_date": - MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), - "fee_notification": - MessageLookupByLibrary.simpleMessage("Fee deadline"), - "files": MessageLookupByLibrary.simpleMessage("Files"), - "first_year_registration": MessageLookupByLibrary.simpleMessage( - "Year of first registration: "), - "floor": MessageLookupByLibrary.simpleMessage("Floor"), - "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€"), - "internet_status_exception": MessageLookupByLibrary.simpleMessage( - "Check your internet connection"), - "invalid_credentials": - MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), - "language": MessageLookupByLibrary.simpleMessage("Language"), - "last_refresh_time": m0, - "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..."), - "login": MessageLookupByLibrary.simpleMessage("Login"), - "login_with_credentials": - MessageLookupByLibrary.simpleMessage("Login with credentials"), - "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": MessageLookupByLibrary.simpleMessage("No"), - "no_app": MessageLookupByLibrary.simpleMessage( - "No app found to open the file"), - "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"), - "no_classes_on_weekend": - 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( - "There is no data to show at this time"), - "no_date": MessageLookupByLibrary.simpleMessage("No date"), - "no_events": MessageLookupByLibrary.simpleMessage("No events found"), - "no_exams": MessageLookupByLibrary.simpleMessage( - "You have no exams scheduled\n"), - "no_exams_label": MessageLookupByLibrary.simpleMessage( - "Looks like you are on vacation!"), - "no_favorite_restaurants": - MessageLookupByLibrary.simpleMessage("No favorite restaurants"), - "no_files_found": - MessageLookupByLibrary.simpleMessage("No files found"), - "no_info": MessageLookupByLibrary.simpleMessage( - "There is no information to display"), - "no_internet": MessageLookupByLibrary.simpleMessage( - "It looks like you\'re offline"), - "no_library_info": MessageLookupByLibrary.simpleMessage( - "No library occupation information available"), - "no_link": - MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), - "no_menu_info": MessageLookupByLibrary.simpleMessage( - "There is no information available about meals"), - "no_menus": MessageLookupByLibrary.simpleMessage( - "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_print_info": MessageLookupByLibrary.simpleMessage( - "No print balance information"), - "no_references": MessageLookupByLibrary.simpleMessage( - "There are no references to pay"), - "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"), - "notifications": MessageLookupByLibrary.simpleMessage("Notifications"), - "occurrence_type": - MessageLookupByLibrary.simpleMessage("Type of occurrence"), - "of_month": MessageLookupByLibrary.simpleMessage("of"), - "open_error": - MessageLookupByLibrary.simpleMessage("Error opening the file"), - "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"), - "permission_denied": - MessageLookupByLibrary.simpleMessage("Permission denied"), - "personal_assistance": - MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), - "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"), - "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"), - "report_error": MessageLookupByLibrary.simpleMessage("Report error"), - "report_error_suggestion": - MessageLookupByLibrary.simpleMessage("Report error/suggestion"), - "restaurant_main_page": MessageLookupByLibrary.simpleMessage( - "Do you want to see your favorite restaurants in the main page?"), - "room": MessageLookupByLibrary.simpleMessage("Room"), - "school_calendar": - MessageLookupByLibrary.simpleMessage("School Calendar"), - "search": MessageLookupByLibrary.simpleMessage("Search"), - "semester": MessageLookupByLibrary.simpleMessage("Semester"), - "send": MessageLookupByLibrary.simpleMessage("Send"), - "sent_error": MessageLookupByLibrary.simpleMessage( - "An error occurred in sending"), - "settings": MessageLookupByLibrary.simpleMessage("Settings"), - "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), - "stcp_stops": - MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), - "student_number": - MessageLookupByLibrary.simpleMessage("student number"), - "success": MessageLookupByLibrary.simpleMessage("Sent with success"), - "successful_open": - MessageLookupByLibrary.simpleMessage("File opened successfully"), - "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"), - "theme": MessageLookupByLibrary.simpleMessage("Theme"), - "title": MessageLookupByLibrary.simpleMessage("Title"), - "try_again": MessageLookupByLibrary.simpleMessage("Try again"), - "try_different_login": MessageLookupByLibrary.simpleMessage( - "Problems with login? Try a different login"), - "uc_info": MessageLookupByLibrary.simpleMessage("Open UC page"), - "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), - "valid_email": - MessageLookupByLibrary.simpleMessage("Please enter a valid email"), - "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:"), - "wrong_credentials_exception": - MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "year": MessageLookupByLibrary.simpleMessage("Year"), - "yes": MessageLookupByLibrary.simpleMessage("Yes") - }; + static _notInlinedMessages(_) => { + "about" : MessageLookupByLibrary.simpleMessage("About us"), + "academic_services" : MessageLookupByLibrary.simpleMessage("Academic services"), + "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!"), + "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:"), + "banner_info" : MessageLookupByLibrary.simpleMessage("We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), + "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), + "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("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"), + "change" : MessageLookupByLibrary.simpleMessage("Change"), + "change_prompt" : MessageLookupByLibrary.simpleMessage("Do you want to change the password?"), + "check_internet" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), + "class_registration" : MessageLookupByLibrary.simpleMessage("Class Registration"), + "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Collect usage statistics"), + "college" : MessageLookupByLibrary.simpleMessage("College: "), + "college_select" : MessageLookupByLibrary.simpleMessage("select your college(s)"), + "conclude" : MessageLookupByLibrary.simpleMessage("Done"), + "configured_buses" : MessageLookupByLibrary.simpleMessage("Configured Buses"), + "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), + "confirm_logout" : MessageLookupByLibrary.simpleMessage("Do you really want to log out? Your local data will be deleted and you will have to log in again."), + "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"), + "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"), + "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Floor -1 of building B (B-142)"), + "download_error" : MessageLookupByLibrary.simpleMessage("Error downloading the file"), + "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"), + "evaluation" : MessageLookupByLibrary.simpleMessage("Evaluation"), + "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"), + "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Failed to authenticate"), + "failed_login" : MessageLookupByLibrary.simpleMessage("Login failed"), + "fee_date" : MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), + "fee_notification" : MessageLookupByLibrary.simpleMessage("Fee deadline"), + "files" : MessageLookupByLibrary.simpleMessage("Files"), + "first_year_registration" : MessageLookupByLibrary.simpleMessage("Year of first registration: "), + "floor" : MessageLookupByLibrary.simpleMessage("Floor"), + "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€"), + "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), + "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "keep_login" : MessageLookupByLibrary.simpleMessage("Stay signed in"), + "language" : MessageLookupByLibrary.simpleMessage("Language"), + "last_refresh_time" : m0, + "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..."), + "login" : MessageLookupByLibrary.simpleMessage("Login"), + "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Login with credentials"), + "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" : MessageLookupByLibrary.simpleMessage("No"), + "no_app" : MessageLookupByLibrary.simpleMessage("No app found to open the file"), + "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"), + "no_classes_on_weekend" : 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("There is no data to show at this time"), + "no_date" : MessageLookupByLibrary.simpleMessage("No date"), + "no_events" : MessageLookupByLibrary.simpleMessage("No events found"), + "no_exams" : MessageLookupByLibrary.simpleMessage("You have no exams scheduled\n"), + "no_exams_label" : MessageLookupByLibrary.simpleMessage("Looks like you are on vacation!"), + "no_favorite_restaurants" : MessageLookupByLibrary.simpleMessage("No favorite restaurants"), + "no_files_found" : MessageLookupByLibrary.simpleMessage("No files found"), + "no_info" : MessageLookupByLibrary.simpleMessage("There is no information to display"), + "no_internet" : MessageLookupByLibrary.simpleMessage("It looks like you\'re offline"), + "no_library_info" : MessageLookupByLibrary.simpleMessage("No library occupation information available"), + "no_link" : MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), + "no_menu_info" : MessageLookupByLibrary.simpleMessage("There is no information available about meals"), + "no_menus" : MessageLookupByLibrary.simpleMessage("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_print_info" : MessageLookupByLibrary.simpleMessage("No print balance information"), + "no_references" : MessageLookupByLibrary.simpleMessage("There are no references to pay"), + "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"), + "notifications" : MessageLookupByLibrary.simpleMessage("Notifications"), + "occurrence_type" : MessageLookupByLibrary.simpleMessage("Type of occurrence"), + "of_month" : MessageLookupByLibrary.simpleMessage("of"), + "open_error" : MessageLookupByLibrary.simpleMessage("Error opening the file"), + "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"), + "permission_denied" : MessageLookupByLibrary.simpleMessage("Permission denied"), + "personal_assistance" : MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "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"), + "program" : MessageLookupByLibrary.simpleMessage("Program"), + "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"), + "report_error" : MessageLookupByLibrary.simpleMessage("Report error"), + "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Report error/suggestion"), + "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Do you want to see your favorite restaurants in the main page?"), + "room" : MessageLookupByLibrary.simpleMessage("Room"), + "school_calendar" : MessageLookupByLibrary.simpleMessage("School Calendar"), + "search" : MessageLookupByLibrary.simpleMessage("Search"), + "semester" : MessageLookupByLibrary.simpleMessage("Semester"), + "send" : MessageLookupByLibrary.simpleMessage("Send"), + "sent_error" : MessageLookupByLibrary.simpleMessage("An error occurred in sending"), + "settings" : MessageLookupByLibrary.simpleMessage("Settings"), + "some_error" : MessageLookupByLibrary.simpleMessage("Some error!"), + "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "student_number" : MessageLookupByLibrary.simpleMessage("student number"), + "success" : MessageLookupByLibrary.simpleMessage("Sent with success"), + "successful_open" : MessageLookupByLibrary.simpleMessage("File opened successfully"), + "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"), + "theme" : MessageLookupByLibrary.simpleMessage("Theme"), + "title" : MessageLookupByLibrary.simpleMessage("Title"), + "try_again" : MessageLookupByLibrary.simpleMessage("Try again"), + "try_different_login" : MessageLookupByLibrary.simpleMessage("Problems with login? Try a different login"), + "uc_info" : MessageLookupByLibrary.simpleMessage("Open UC page"), + "unavailable" : MessageLookupByLibrary.simpleMessage("Unavailable"), + "valid_email" : MessageLookupByLibrary.simpleMessage("Please enter a valid email"), + "widget_prompt" : MessageLookupByLibrary.simpleMessage("Choose a widget to add to your personal area:"), + "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "year" : MessageLookupByLibrary.simpleMessage("Year"), + "yes" : MessageLookupByLibrary.simpleMessage("Yes") + }; } diff --git a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart index 6f1667a4a..56d68ca61 100644 --- a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart +++ b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart @@ -21,281 +21,173 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "última atualização às ${time}"; - static m1(time) => - "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + static m1(time) => "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static 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', - 'percurso_academico': 'Percurso Académico', - 'transportes': 'Transportes', - 'faculdade': 'Faculdade', - 'other': 'Outros', - })}"; + static 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', 'percurso_academico': 'Percurso Académico', 'transportes': 'Transportes', 'faculdade': 'Faculdade', 'other': 'Outros', })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about": MessageLookupByLibrary.simpleMessage("Sobre nós"), - "academic_services": - MessageLookupByLibrary.simpleMessage("Serviços académicos"), - "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"), - "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"), - "available_amount": - MessageLookupByLibrary.simpleMessage("Valor disponível"), - "average": MessageLookupByLibrary.simpleMessage("Média: "), - "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), - "banner_info": MessageLookupByLibrary.simpleMessage( - "Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), - "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( - "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"), - "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"), - "collect_usage_stats": MessageLookupByLibrary.simpleMessage( - "Partilhar estatísticas de uso"), - "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"), - "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), - "confirm_logout": MessageLookupByLibrary.simpleMessage( - "Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), - "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"), - "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"), - "dona_bia": - MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), - "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B (B-142)"), - "download_error": MessageLookupByLibrary.simpleMessage( - "Erro ao descarregar o ficheiro"), - "ects": MessageLookupByLibrary.simpleMessage("ECTS realizados: "), - "edit_off": MessageLookupByLibrary.simpleMessage("Editar"), - "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"), - "exit_confirm": MessageLookupByLibrary.simpleMessage( - "Tem a certeza de que pretende sair?"), - "expired_password": - MessageLookupByLibrary.simpleMessage("A tua palavra-passe expirou"), - "fail_to_authenticate": - MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), - "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), - "fee_date": MessageLookupByLibrary.simpleMessage( - "Data limite próxima prestação:"), - "fee_notification": - MessageLookupByLibrary.simpleMessage("Data limite de propina"), - "files": MessageLookupByLibrary.simpleMessage("Ficheiros"), - "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€"), - "internet_status_exception": MessageLookupByLibrary.simpleMessage( - "Verifique sua conexão com a internet"), - "invalid_credentials": - MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão"), - "language": MessageLookupByLibrary.simpleMessage("Idioma"), - "last_refresh_time": m0, - "last_timestamp": m1, - "library_occupation": - MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), - "load_error": MessageLookupByLibrary.simpleMessage( - "Erro ao carregar a informação"), - "loading_terms": MessageLookupByLibrary.simpleMessage( - "Carregando os Termos e Condições..."), - "login": MessageLookupByLibrary.simpleMessage("Entrar"), - "login_with_credentials": MessageLookupByLibrary.simpleMessage( - "Iniciar sessão com credenciais"), - "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": MessageLookupByLibrary.simpleMessage("Não"), - "no_app": MessageLookupByLibrary.simpleMessage( - "Nenhuma aplicação encontrada para abrir o ficheiro"), - "no_bus": MessageLookupByLibrary.simpleMessage( - "Não percas nenhum autocarro!"), - "no_bus_stops": MessageLookupByLibrary.simpleMessage( - "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"), - "no_classes_on": - MessageLookupByLibrary.simpleMessage("Não possui aulas à"), - "no_classes_on_weekend": - MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), - "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), - "no_course_units": MessageLookupByLibrary.simpleMessage( - "Sem cadeiras no período selecionado"), - "no_data": MessageLookupByLibrary.simpleMessage( - "Não há dados a mostrar neste momento"), - "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), - "no_events": - MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), - "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_files_found": - MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), - "no_info": MessageLookupByLibrary.simpleMessage( - "Não existem informações para apresentar"), - "no_internet": - MessageLookupByLibrary.simpleMessage("Parece que estás offline"), - "no_library_info": - MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), - "no_link": MessageLookupByLibrary.simpleMessage( - "Não conseguimos abrir o link"), - "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_name_course": - MessageLookupByLibrary.simpleMessage("Curso sem nome"), - "no_places_info": MessageLookupByLibrary.simpleMessage( - "Não há informação disponível sobre locais"), - "no_print_info": - MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), - "no_references": MessageLookupByLibrary.simpleMessage( - "Não existem referências a pagar"), - "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"), - "notifications": MessageLookupByLibrary.simpleMessage("Notificações"), - "occurrence_type": - MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), - "of_month": MessageLookupByLibrary.simpleMessage("de"), - "open_error": - MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), - "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"), - "permission_denied": - MessageLookupByLibrary.simpleMessage("Sem permissão"), - "personal_assistance": - MessageLookupByLibrary.simpleMessage("Atendimento presencial"), - "press_again": MessageLookupByLibrary.simpleMessage( - "Pressione novamente para sair"), - "print": MessageLookupByLibrary.simpleMessage("Impressão"), - "prints": MessageLookupByLibrary.simpleMessage("Impressões"), - "problem_id": MessageLookupByLibrary.simpleMessage( - "Breve identificação do problema"), - "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - "Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), - "reference_success": MessageLookupByLibrary.simpleMessage( - "Referência criada com sucesso!"), - "remove": MessageLookupByLibrary.simpleMessage("Remover"), - "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), - "report_error_suggestion": - MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), - "restaurant_main_page": MessageLookupByLibrary.simpleMessage( - "Queres ver os teus restaurantes favoritos na página principal?"), - "room": MessageLookupByLibrary.simpleMessage("Sala"), - "school_calendar": - MessageLookupByLibrary.simpleMessage("Calendário Escolar"), - "search": MessageLookupByLibrary.simpleMessage("Pesquisar"), - "semester": MessageLookupByLibrary.simpleMessage("Semestre"), - "send": MessageLookupByLibrary.simpleMessage("Enviar"), - "sent_error": - MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), - "settings": MessageLookupByLibrary.simpleMessage("Definições"), - "some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"), - "stcp_stops": - MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), - "student_number": - MessageLookupByLibrary.simpleMessage("número de estudante"), - "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), - "successful_open": - MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), - "theme": MessageLookupByLibrary.simpleMessage("Tema"), - "title": MessageLookupByLibrary.simpleMessage("Título"), - "try_again": MessageLookupByLibrary.simpleMessage("Tentar de novo"), - "try_different_login": MessageLookupByLibrary.simpleMessage( - "Problemas a iniciar sessão? Experimenta o login alternativo"), - "uc_info": MessageLookupByLibrary.simpleMessage("Abrir página da UC"), - "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), - "valid_email": MessageLookupByLibrary.simpleMessage( - "Por favor insere um email válido"), - "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:"), - "wrong_credentials_exception": - MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "year": MessageLookupByLibrary.simpleMessage("Ano"), - "yes": MessageLookupByLibrary.simpleMessage("Sim") - }; + static _notInlinedMessages(_) => { + "about" : MessageLookupByLibrary.simpleMessage("Sobre nós"), + "academic_services" : MessageLookupByLibrary.simpleMessage("Serviços académicos"), + "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"), + "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"), + "available_amount" : MessageLookupByLibrary.simpleMessage("Valor disponível"), + "average" : MessageLookupByLibrary.simpleMessage("Média: "), + "balance" : MessageLookupByLibrary.simpleMessage("Saldo:"), + "banner_info" : MessageLookupByLibrary.simpleMessage("Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), + "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), + "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("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"), + "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"), + "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Partilhar estatísticas de uso"), + "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"), + "confirm" : MessageLookupByLibrary.simpleMessage("Confirmar"), + "confirm_logout" : MessageLookupByLibrary.simpleMessage("Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), + "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"), + "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"), + "dona_bia" : MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), + "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Piso -1 do edifício B (B-142)"), + "download_error" : MessageLookupByLibrary.simpleMessage("Erro ao descarregar o ficheiro"), + "ects" : MessageLookupByLibrary.simpleMessage("ECTS realizados: "), + "edit_off" : MessageLookupByLibrary.simpleMessage("Editar"), + "edit_on" : MessageLookupByLibrary.simpleMessage("Concluir edição"), + "empty_text" : MessageLookupByLibrary.simpleMessage("Por favor preenche este campo"), + "evaluation" : MessageLookupByLibrary.simpleMessage("Avaliação"), + "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"), + "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), + "failed_login" : MessageLookupByLibrary.simpleMessage("O login falhou"), + "fee_date" : MessageLookupByLibrary.simpleMessage("Data limite próxima prestação:"), + "fee_notification" : MessageLookupByLibrary.simpleMessage("Data limite de propina"), + "files" : MessageLookupByLibrary.simpleMessage("Ficheiros"), + "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€"), + "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Verifique sua conexão com a internet"), + "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "keep_login" : MessageLookupByLibrary.simpleMessage("Manter sessão"), + "language" : MessageLookupByLibrary.simpleMessage("Idioma"), + "last_refresh_time" : m0, + "last_timestamp" : m1, + "library_occupation" : MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "load_error" : MessageLookupByLibrary.simpleMessage("Erro ao carregar a informação"), + "loading_terms" : MessageLookupByLibrary.simpleMessage("Carregando os Termos e Condições..."), + "login" : MessageLookupByLibrary.simpleMessage("Entrar"), + "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Iniciar sessão com credenciais"), + "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" : MessageLookupByLibrary.simpleMessage("Não"), + "no_app" : MessageLookupByLibrary.simpleMessage("Nenhuma aplicação encontrada para abrir o ficheiro"), + "no_bus" : MessageLookupByLibrary.simpleMessage("Não percas nenhum autocarro!"), + "no_bus_stops" : MessageLookupByLibrary.simpleMessage("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"), + "no_classes_on" : MessageLookupByLibrary.simpleMessage("Não possui aulas à"), + "no_classes_on_weekend" : MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), + "no_college" : MessageLookupByLibrary.simpleMessage("sem faculdade"), + "no_course_units" : MessageLookupByLibrary.simpleMessage("Sem cadeiras no período selecionado"), + "no_data" : MessageLookupByLibrary.simpleMessage("Não há dados a mostrar neste momento"), + "no_date" : MessageLookupByLibrary.simpleMessage("Sem data"), + "no_events" : MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), + "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_files_found" : MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), + "no_info" : MessageLookupByLibrary.simpleMessage("Não existem informações para apresentar"), + "no_internet" : MessageLookupByLibrary.simpleMessage("Parece que estás offline"), + "no_library_info" : MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), + "no_link" : MessageLookupByLibrary.simpleMessage("Não conseguimos abrir o link"), + "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_name_course" : MessageLookupByLibrary.simpleMessage("Curso sem nome"), + "no_places_info" : MessageLookupByLibrary.simpleMessage("Não há informação disponível sobre locais"), + "no_print_info" : MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), + "no_references" : MessageLookupByLibrary.simpleMessage("Não existem referências a pagar"), + "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"), + "notifications" : MessageLookupByLibrary.simpleMessage("Notificações"), + "occurrence_type" : MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), + "of_month" : MessageLookupByLibrary.simpleMessage("de"), + "open_error" : MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), + "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"), + "permission_denied" : MessageLookupByLibrary.simpleMessage("Sem permissão"), + "personal_assistance" : MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "press_again" : MessageLookupByLibrary.simpleMessage("Pressione novamente para sair"), + "print" : MessageLookupByLibrary.simpleMessage("Impressão"), + "prints" : MessageLookupByLibrary.simpleMessage("Impressões"), + "problem_id" : MessageLookupByLibrary.simpleMessage("Breve identificação do problema"), + "program" : MessageLookupByLibrary.simpleMessage("Programa"), + "reference_sigarra_help" : MessageLookupByLibrary.simpleMessage("Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), + "reference_success" : MessageLookupByLibrary.simpleMessage("Referência criada com sucesso!"), + "remove" : MessageLookupByLibrary.simpleMessage("Remover"), + "report_error" : MessageLookupByLibrary.simpleMessage("Reportar erro"), + "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), + "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Queres ver os teus restaurantes favoritos na página principal?"), + "room" : MessageLookupByLibrary.simpleMessage("Sala"), + "school_calendar" : MessageLookupByLibrary.simpleMessage("Calendário Escolar"), + "search" : MessageLookupByLibrary.simpleMessage("Pesquisar"), + "semester" : MessageLookupByLibrary.simpleMessage("Semestre"), + "send" : MessageLookupByLibrary.simpleMessage("Enviar"), + "sent_error" : MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), + "settings" : MessageLookupByLibrary.simpleMessage("Definições"), + "some_error" : MessageLookupByLibrary.simpleMessage("Algum erro!"), + "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "student_number" : MessageLookupByLibrary.simpleMessage("número de estudante"), + "success" : MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), + "successful_open" : MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), + "theme" : MessageLookupByLibrary.simpleMessage("Tema"), + "title" : MessageLookupByLibrary.simpleMessage("Título"), + "try_again" : MessageLookupByLibrary.simpleMessage("Tentar de novo"), + "try_different_login" : MessageLookupByLibrary.simpleMessage("Problemas a iniciar sessão? Experimenta o login alternativo"), + "uc_info" : MessageLookupByLibrary.simpleMessage("Abrir página da UC"), + "unavailable" : MessageLookupByLibrary.simpleMessage("Indisponível"), + "valid_email" : MessageLookupByLibrary.simpleMessage("Por favor insere um email válido"), + "widget_prompt" : MessageLookupByLibrary.simpleMessage("Escolhe um widget para adicionares à tua área pessoal:"), + "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "year" : MessageLookupByLibrary.simpleMessage("Ano"), + "yes" : MessageLookupByLibrary.simpleMessage("Sim") + }; } diff --git a/packages/uni_app/lib/generated/l10n.dart b/packages/uni_app/lib/generated/l10n.dart index 74b11f274..04b76c9ef 100644 --- a/packages/uni_app/lib/generated/l10n.dart +++ b/packages/uni_app/lib/generated/l10n.dart @@ -18,31 +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!; } @@ -250,6 +247,16 @@ class S { ); } + /// `Bibliografia` + String get bibliography { + return Intl.message( + 'Bibliografia', + name: 'bibliography', + desc: '', + args: [], + ); + } + /// `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( @@ -580,6 +587,16 @@ class S { ); } + /// `Evaluation` + String get evaluation { + return Intl.message( + 'Evaluation', + name: 'evaluation', + desc: '', + args: [], + ); + } + /// `Exams Filter Settings` String get exams_filter { return Intl.message( @@ -1268,6 +1285,16 @@ class S { ); } + /// `Program` + String get program { + return Intl.message( + 'Program', + name: 'program', + desc: '', + args: [], + ); + } + /// `Error opening the file` String get open_error { return Intl.message( @@ -1684,4 +1711,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} +} \ No newline at end of file diff --git a/packages/uni_app/lib/l10n/intl_en.arb b/packages/uni_app/lib/l10n/intl_en.arb index 20950b4af..94b7d3c06 100644 --- a/packages/uni_app/lib/l10n/intl_en.arb +++ b/packages/uni_app/lib/l10n/intl_en.arb @@ -40,6 +40,8 @@ "@banner_info": {}, "balance": "Balance:", "@balance": {}, + "bibliography": "Bibliografia", + "@bibliography": {}, "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.", @@ -106,6 +108,8 @@ "@edit_on": {}, "empty_text": "Please fill in this field", "@empty_text": {}, + "evaluation": "Evaluation", + "@evaluation": {}, "exams_filter": "Exams Filter Settings", "@exams_filter": {}, "expired_password": "Your password has expired", @@ -248,6 +252,8 @@ "@successful_open": {}, "permission_denied": "Permission denied", "@permission_denied": {}, + "program": "Program", + "@program": {}, "open_error": "Error opening the file", "@open_error": {}, "no_app": "No app found to open the file", diff --git a/packages/uni_app/lib/l10n/intl_pt_PT.arb b/packages/uni_app/lib/l10n/intl_pt_PT.arb index 766458f7b..14837abe4 100644 --- a/packages/uni_app/lib/l10n/intl_pt_PT.arb +++ b/packages/uni_app/lib/l10n/intl_pt_PT.arb @@ -42,6 +42,8 @@ "@banner_info": {}, "balance": "Saldo:", "@balance": {}, + "bibliography": "Bibliografia", + "@bibliography": {}, "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", @@ -108,6 +110,8 @@ "@edit_on": {}, "empty_text": "Por favor preenche este campo", "@empty_text": {}, + "evaluation": "Avaliação", + "@evaluation": {}, "exams_filter": "Definições Filtro de Exames", "@exams_filter": {}, "expired_password": "A tua palavra-passe expirou", @@ -252,6 +256,8 @@ "@personal_assistance": {}, "press_again": "Pressione novamente para sair", "@press_again": {}, + "program": "Programa", + "@program": {}, "print": "Impressão", "@print": {}, "prints": "Impressões", diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart index 220437374..e5f1d95ce 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:provider/provider.dart'; import 'package:uni/controller/fetchers/book_fetcher.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/course_units/sheet.dart'; import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; @@ -37,16 +38,20 @@ class CourseUnitSheetView extends StatelessWidget { secondChild: buildExpandedProfessors(context, courseUnitSheet.professors), ), - _buildCard('Programa', courseUnitSheet.content), - _buildCard('Avaliação', courseUnitSheet.evaluation), + _buildCard(S.of(context).program, courseUnitSheet.content, context), + _buildCard( + S.of(context).evaluation, + courseUnitSheet.evaluation, + context, + ), if (courseUnitSheet.books.isNotEmpty) ...[ const Opacity( opacity: 0.25, child: Divider(color: Colors.grey), ), - const Text( - 'Bibliografia', - style: TextStyle(fontSize: 20), + Text( + S.of(context).bibliography, + style: const TextStyle(fontSize: 20), ), buildBooksRow(context, courseUnitSheet.books), ], @@ -215,9 +220,7 @@ Widget buildBooksRow(BuildContext context, List books) { } Widget _buildCard( - String sectionTitle, - String sectionContent, -) { + String sectionTitle, String sectionContent, BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Column( @@ -228,9 +231,7 @@ Widget _buildCard( ), GenericExpandable( content: HtmlWidget( - sectionContent != 'null' - ? sectionContent - : 'Sem informações para apresentar', + sectionContent != 'null' ? sectionContent : S.of(context).no_info, ), title: sectionTitle, ), From 5bc73f9ade19b167a3f8bfdabec7ea020b0fdf17 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Mon, 16 Sep 2024 16:41:43 +0100 Subject: [PATCH 80/99] formatting --- .../lib/generated/intl/messages_all.dart | 9 +- .../lib/generated/intl/messages_en.dart | 442 ++++++++++------- .../lib/generated/intl/messages_pt_PT.dart | 443 +++++++++++------- packages/uni_app/lib/generated/l10n.dart | 25 +- packages/uni_app/lib/l10n/intl_en.arb | 2 +- .../widgets/course_unit_sheet.dart | 5 +- 6 files changed, 576 insertions(+), 350 deletions(-) diff --git a/packages/uni_app/lib/generated/intl/messages_all.dart b/packages/uni_app/lib/generated/intl/messages_all.dart index fb1bd2689..6b3ebeae5 100644 --- a/packages/uni_app/lib/generated/intl/messages_all.dart +++ b/packages/uni_app/lib/generated/intl/messages_all.dart @@ -38,9 +38,8 @@ 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); + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { return new Future.value(false); } @@ -60,8 +59,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var 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/packages/uni_app/lib/generated/intl/messages_en.dart b/packages/uni_app/lib/generated/intl/messages_en.dart index 78777d17f..4719af7cd 100644 --- a/packages/uni_app/lib/generated/intl/messages_en.dart +++ b/packages/uni_app/lib/generated/intl/messages_en.dart @@ -21,173 +21,283 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "last refresh at ${time}"; - static m1(time) => "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + static m1(time) => + "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - 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', 'percurso_academico': 'Academic Path', 'transportes': 'Transports', 'faculdade': 'Faculty', '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', + 'percurso_academico': 'Academic Path', + 'transportes': 'Transports', + 'faculdade': 'Faculty', + 'other': 'Other', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about" : MessageLookupByLibrary.simpleMessage("About us"), - "academic_services" : MessageLookupByLibrary.simpleMessage("Academic services"), - "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!"), - "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:"), - "banner_info" : MessageLookupByLibrary.simpleMessage("We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), - "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), - "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("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"), - "change" : MessageLookupByLibrary.simpleMessage("Change"), - "change_prompt" : MessageLookupByLibrary.simpleMessage("Do you want to change the password?"), - "check_internet" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), - "class_registration" : MessageLookupByLibrary.simpleMessage("Class Registration"), - "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Collect usage statistics"), - "college" : MessageLookupByLibrary.simpleMessage("College: "), - "college_select" : MessageLookupByLibrary.simpleMessage("select your college(s)"), - "conclude" : MessageLookupByLibrary.simpleMessage("Done"), - "configured_buses" : MessageLookupByLibrary.simpleMessage("Configured Buses"), - "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), - "confirm_logout" : MessageLookupByLibrary.simpleMessage("Do you really want to log out? Your local data will be deleted and you will have to log in again."), - "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"), - "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"), - "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Floor -1 of building B (B-142)"), - "download_error" : MessageLookupByLibrary.simpleMessage("Error downloading the file"), - "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"), - "evaluation" : MessageLookupByLibrary.simpleMessage("Evaluation"), - "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"), - "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Failed to authenticate"), - "failed_login" : MessageLookupByLibrary.simpleMessage("Login failed"), - "fee_date" : MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), - "fee_notification" : MessageLookupByLibrary.simpleMessage("Fee deadline"), - "files" : MessageLookupByLibrary.simpleMessage("Files"), - "first_year_registration" : MessageLookupByLibrary.simpleMessage("Year of first registration: "), - "floor" : MessageLookupByLibrary.simpleMessage("Floor"), - "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€"), - "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), - "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "keep_login" : MessageLookupByLibrary.simpleMessage("Stay signed in"), - "language" : MessageLookupByLibrary.simpleMessage("Language"), - "last_refresh_time" : m0, - "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..."), - "login" : MessageLookupByLibrary.simpleMessage("Login"), - "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Login with credentials"), - "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" : MessageLookupByLibrary.simpleMessage("No"), - "no_app" : MessageLookupByLibrary.simpleMessage("No app found to open the file"), - "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"), - "no_classes_on_weekend" : 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("There is no data to show at this time"), - "no_date" : MessageLookupByLibrary.simpleMessage("No date"), - "no_events" : MessageLookupByLibrary.simpleMessage("No events found"), - "no_exams" : MessageLookupByLibrary.simpleMessage("You have no exams scheduled\n"), - "no_exams_label" : MessageLookupByLibrary.simpleMessage("Looks like you are on vacation!"), - "no_favorite_restaurants" : MessageLookupByLibrary.simpleMessage("No favorite restaurants"), - "no_files_found" : MessageLookupByLibrary.simpleMessage("No files found"), - "no_info" : MessageLookupByLibrary.simpleMessage("There is no information to display"), - "no_internet" : MessageLookupByLibrary.simpleMessage("It looks like you\'re offline"), - "no_library_info" : MessageLookupByLibrary.simpleMessage("No library occupation information available"), - "no_link" : MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), - "no_menu_info" : MessageLookupByLibrary.simpleMessage("There is no information available about meals"), - "no_menus" : MessageLookupByLibrary.simpleMessage("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_print_info" : MessageLookupByLibrary.simpleMessage("No print balance information"), - "no_references" : MessageLookupByLibrary.simpleMessage("There are no references to pay"), - "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"), - "notifications" : MessageLookupByLibrary.simpleMessage("Notifications"), - "occurrence_type" : MessageLookupByLibrary.simpleMessage("Type of occurrence"), - "of_month" : MessageLookupByLibrary.simpleMessage("of"), - "open_error" : MessageLookupByLibrary.simpleMessage("Error opening the file"), - "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"), - "permission_denied" : MessageLookupByLibrary.simpleMessage("Permission denied"), - "personal_assistance" : MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), - "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"), - "program" : MessageLookupByLibrary.simpleMessage("Program"), - "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"), - "report_error" : MessageLookupByLibrary.simpleMessage("Report error"), - "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Report error/suggestion"), - "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Do you want to see your favorite restaurants in the main page?"), - "room" : MessageLookupByLibrary.simpleMessage("Room"), - "school_calendar" : MessageLookupByLibrary.simpleMessage("School Calendar"), - "search" : MessageLookupByLibrary.simpleMessage("Search"), - "semester" : MessageLookupByLibrary.simpleMessage("Semester"), - "send" : MessageLookupByLibrary.simpleMessage("Send"), - "sent_error" : MessageLookupByLibrary.simpleMessage("An error occurred in sending"), - "settings" : MessageLookupByLibrary.simpleMessage("Settings"), - "some_error" : MessageLookupByLibrary.simpleMessage("Some error!"), - "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), - "student_number" : MessageLookupByLibrary.simpleMessage("student number"), - "success" : MessageLookupByLibrary.simpleMessage("Sent with success"), - "successful_open" : MessageLookupByLibrary.simpleMessage("File opened successfully"), - "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"), - "theme" : MessageLookupByLibrary.simpleMessage("Theme"), - "title" : MessageLookupByLibrary.simpleMessage("Title"), - "try_again" : MessageLookupByLibrary.simpleMessage("Try again"), - "try_different_login" : MessageLookupByLibrary.simpleMessage("Problems with login? Try a different login"), - "uc_info" : MessageLookupByLibrary.simpleMessage("Open UC page"), - "unavailable" : MessageLookupByLibrary.simpleMessage("Unavailable"), - "valid_email" : MessageLookupByLibrary.simpleMessage("Please enter a valid email"), - "widget_prompt" : MessageLookupByLibrary.simpleMessage("Choose a widget to add to your personal area:"), - "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "year" : MessageLookupByLibrary.simpleMessage("Year"), - "yes" : MessageLookupByLibrary.simpleMessage("Yes") - }; + static _notInlinedMessages(_) => { + "about": MessageLookupByLibrary.simpleMessage("About us"), + "academic_services": + MessageLookupByLibrary.simpleMessage("Academic services"), + "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!"), + "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:"), + "banner_info": MessageLookupByLibrary.simpleMessage( + "We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), + "bibliography": MessageLookupByLibrary.simpleMessage("Bibliography"), + "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( + "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"), + "change": MessageLookupByLibrary.simpleMessage("Change"), + "change_prompt": MessageLookupByLibrary.simpleMessage( + "Do you want to change the password?"), + "check_internet": MessageLookupByLibrary.simpleMessage( + "Check your internet connection"), + "class_registration": + MessageLookupByLibrary.simpleMessage("Class Registration"), + "collect_usage_stats": + MessageLookupByLibrary.simpleMessage("Collect usage statistics"), + "college": MessageLookupByLibrary.simpleMessage("College: "), + "college_select": + MessageLookupByLibrary.simpleMessage("select your college(s)"), + "conclude": MessageLookupByLibrary.simpleMessage("Done"), + "configured_buses": + MessageLookupByLibrary.simpleMessage("Configured Buses"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), + "confirm_logout": MessageLookupByLibrary.simpleMessage( + "Do you really want to log out? Your local data will be deleted and you will have to log in again."), + "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"), + "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"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Floor -1 of building B (B-142)"), + "download_error": + MessageLookupByLibrary.simpleMessage("Error downloading the file"), + "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"), + "evaluation": MessageLookupByLibrary.simpleMessage("Evaluation"), + "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"), + "fail_to_authenticate": + MessageLookupByLibrary.simpleMessage("Failed to authenticate"), + "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), + "fee_date": + MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), + "fee_notification": + MessageLookupByLibrary.simpleMessage("Fee deadline"), + "files": MessageLookupByLibrary.simpleMessage("Files"), + "first_year_registration": MessageLookupByLibrary.simpleMessage( + "Year of first registration: "), + "floor": MessageLookupByLibrary.simpleMessage("Floor"), + "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€"), + "internet_status_exception": MessageLookupByLibrary.simpleMessage( + "Check your internet connection"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), + "language": MessageLookupByLibrary.simpleMessage("Language"), + "last_refresh_time": m0, + "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..."), + "login": MessageLookupByLibrary.simpleMessage("Login"), + "login_with_credentials": + MessageLookupByLibrary.simpleMessage("Login with credentials"), + "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": MessageLookupByLibrary.simpleMessage("No"), + "no_app": MessageLookupByLibrary.simpleMessage( + "No app found to open the file"), + "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"), + "no_classes_on_weekend": + 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( + "There is no data to show at this time"), + "no_date": MessageLookupByLibrary.simpleMessage("No date"), + "no_events": MessageLookupByLibrary.simpleMessage("No events found"), + "no_exams": MessageLookupByLibrary.simpleMessage( + "You have no exams scheduled\n"), + "no_exams_label": MessageLookupByLibrary.simpleMessage( + "Looks like you are on vacation!"), + "no_favorite_restaurants": + MessageLookupByLibrary.simpleMessage("No favorite restaurants"), + "no_files_found": + MessageLookupByLibrary.simpleMessage("No files found"), + "no_info": MessageLookupByLibrary.simpleMessage( + "There is no information to display"), + "no_internet": MessageLookupByLibrary.simpleMessage( + "It looks like you\'re offline"), + "no_library_info": MessageLookupByLibrary.simpleMessage( + "No library occupation information available"), + "no_link": + MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), + "no_menu_info": MessageLookupByLibrary.simpleMessage( + "There is no information available about meals"), + "no_menus": MessageLookupByLibrary.simpleMessage( + "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_print_info": MessageLookupByLibrary.simpleMessage( + "No print balance information"), + "no_references": MessageLookupByLibrary.simpleMessage( + "There are no references to pay"), + "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"), + "notifications": MessageLookupByLibrary.simpleMessage("Notifications"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Type of occurrence"), + "of_month": MessageLookupByLibrary.simpleMessage("of"), + "open_error": + MessageLookupByLibrary.simpleMessage("Error opening the file"), + "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"), + "permission_denied": + MessageLookupByLibrary.simpleMessage("Permission denied"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "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"), + "program": MessageLookupByLibrary.simpleMessage("Program"), + "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"), + "report_error": MessageLookupByLibrary.simpleMessage("Report error"), + "report_error_suggestion": + MessageLookupByLibrary.simpleMessage("Report error/suggestion"), + "restaurant_main_page": MessageLookupByLibrary.simpleMessage( + "Do you want to see your favorite restaurants in the main page?"), + "room": MessageLookupByLibrary.simpleMessage("Room"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("School Calendar"), + "search": MessageLookupByLibrary.simpleMessage("Search"), + "semester": MessageLookupByLibrary.simpleMessage("Semester"), + "send": MessageLookupByLibrary.simpleMessage("Send"), + "sent_error": MessageLookupByLibrary.simpleMessage( + "An error occurred in sending"), + "settings": MessageLookupByLibrary.simpleMessage("Settings"), + "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "student_number": + MessageLookupByLibrary.simpleMessage("student number"), + "success": MessageLookupByLibrary.simpleMessage("Sent with success"), + "successful_open": + MessageLookupByLibrary.simpleMessage("File opened successfully"), + "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"), + "theme": MessageLookupByLibrary.simpleMessage("Theme"), + "title": MessageLookupByLibrary.simpleMessage("Title"), + "try_again": MessageLookupByLibrary.simpleMessage("Try again"), + "try_different_login": MessageLookupByLibrary.simpleMessage( + "Problems with login? Try a different login"), + "uc_info": MessageLookupByLibrary.simpleMessage("Open UC page"), + "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), + "valid_email": + MessageLookupByLibrary.simpleMessage("Please enter a valid email"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Choose a widget to add to your personal area:"), + "wrong_credentials_exception": + MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "year": MessageLookupByLibrary.simpleMessage("Year"), + "yes": MessageLookupByLibrary.simpleMessage("Yes") + }; } diff --git a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart index 56d68ca61..0198f3d78 100644 --- a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart +++ b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart @@ -21,173 +21,284 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "última atualização às ${time}"; - static m1(time) => "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + static m1(time) => + "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static 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', 'percurso_academico': 'Percurso Académico', 'transportes': 'Transportes', 'faculdade': 'Faculdade', 'other': 'Outros', })}"; + static 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', + 'percurso_academico': 'Percurso Académico', + 'transportes': 'Transportes', + 'faculdade': 'Faculdade', + 'other': 'Outros', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about" : MessageLookupByLibrary.simpleMessage("Sobre nós"), - "academic_services" : MessageLookupByLibrary.simpleMessage("Serviços académicos"), - "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"), - "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"), - "available_amount" : MessageLookupByLibrary.simpleMessage("Valor disponível"), - "average" : MessageLookupByLibrary.simpleMessage("Média: "), - "balance" : MessageLookupByLibrary.simpleMessage("Saldo:"), - "banner_info" : MessageLookupByLibrary.simpleMessage("Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), - "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), - "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("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"), - "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"), - "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Partilhar estatísticas de uso"), - "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"), - "confirm" : MessageLookupByLibrary.simpleMessage("Confirmar"), - "confirm_logout" : MessageLookupByLibrary.simpleMessage("Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), - "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"), - "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"), - "dona_bia" : MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), - "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Piso -1 do edifício B (B-142)"), - "download_error" : MessageLookupByLibrary.simpleMessage("Erro ao descarregar o ficheiro"), - "ects" : MessageLookupByLibrary.simpleMessage("ECTS realizados: "), - "edit_off" : MessageLookupByLibrary.simpleMessage("Editar"), - "edit_on" : MessageLookupByLibrary.simpleMessage("Concluir edição"), - "empty_text" : MessageLookupByLibrary.simpleMessage("Por favor preenche este campo"), - "evaluation" : MessageLookupByLibrary.simpleMessage("Avaliação"), - "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"), - "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), - "failed_login" : MessageLookupByLibrary.simpleMessage("O login falhou"), - "fee_date" : MessageLookupByLibrary.simpleMessage("Data limite próxima prestação:"), - "fee_notification" : MessageLookupByLibrary.simpleMessage("Data limite de propina"), - "files" : MessageLookupByLibrary.simpleMessage("Ficheiros"), - "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€"), - "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Verifique sua conexão com a internet"), - "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "keep_login" : MessageLookupByLibrary.simpleMessage("Manter sessão"), - "language" : MessageLookupByLibrary.simpleMessage("Idioma"), - "last_refresh_time" : m0, - "last_timestamp" : m1, - "library_occupation" : MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), - "load_error" : MessageLookupByLibrary.simpleMessage("Erro ao carregar a informação"), - "loading_terms" : MessageLookupByLibrary.simpleMessage("Carregando os Termos e Condições..."), - "login" : MessageLookupByLibrary.simpleMessage("Entrar"), - "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Iniciar sessão com credenciais"), - "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" : MessageLookupByLibrary.simpleMessage("Não"), - "no_app" : MessageLookupByLibrary.simpleMessage("Nenhuma aplicação encontrada para abrir o ficheiro"), - "no_bus" : MessageLookupByLibrary.simpleMessage("Não percas nenhum autocarro!"), - "no_bus_stops" : MessageLookupByLibrary.simpleMessage("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"), - "no_classes_on" : MessageLookupByLibrary.simpleMessage("Não possui aulas à"), - "no_classes_on_weekend" : MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), - "no_college" : MessageLookupByLibrary.simpleMessage("sem faculdade"), - "no_course_units" : MessageLookupByLibrary.simpleMessage("Sem cadeiras no período selecionado"), - "no_data" : MessageLookupByLibrary.simpleMessage("Não há dados a mostrar neste momento"), - "no_date" : MessageLookupByLibrary.simpleMessage("Sem data"), - "no_events" : MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), - "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_files_found" : MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), - "no_info" : MessageLookupByLibrary.simpleMessage("Não existem informações para apresentar"), - "no_internet" : MessageLookupByLibrary.simpleMessage("Parece que estás offline"), - "no_library_info" : MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), - "no_link" : MessageLookupByLibrary.simpleMessage("Não conseguimos abrir o link"), - "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_name_course" : MessageLookupByLibrary.simpleMessage("Curso sem nome"), - "no_places_info" : MessageLookupByLibrary.simpleMessage("Não há informação disponível sobre locais"), - "no_print_info" : MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), - "no_references" : MessageLookupByLibrary.simpleMessage("Não existem referências a pagar"), - "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"), - "notifications" : MessageLookupByLibrary.simpleMessage("Notificações"), - "occurrence_type" : MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), - "of_month" : MessageLookupByLibrary.simpleMessage("de"), - "open_error" : MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), - "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"), - "permission_denied" : MessageLookupByLibrary.simpleMessage("Sem permissão"), - "personal_assistance" : MessageLookupByLibrary.simpleMessage("Atendimento presencial"), - "press_again" : MessageLookupByLibrary.simpleMessage("Pressione novamente para sair"), - "print" : MessageLookupByLibrary.simpleMessage("Impressão"), - "prints" : MessageLookupByLibrary.simpleMessage("Impressões"), - "problem_id" : MessageLookupByLibrary.simpleMessage("Breve identificação do problema"), - "program" : MessageLookupByLibrary.simpleMessage("Programa"), - "reference_sigarra_help" : MessageLookupByLibrary.simpleMessage("Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), - "reference_success" : MessageLookupByLibrary.simpleMessage("Referência criada com sucesso!"), - "remove" : MessageLookupByLibrary.simpleMessage("Remover"), - "report_error" : MessageLookupByLibrary.simpleMessage("Reportar erro"), - "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), - "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Queres ver os teus restaurantes favoritos na página principal?"), - "room" : MessageLookupByLibrary.simpleMessage("Sala"), - "school_calendar" : MessageLookupByLibrary.simpleMessage("Calendário Escolar"), - "search" : MessageLookupByLibrary.simpleMessage("Pesquisar"), - "semester" : MessageLookupByLibrary.simpleMessage("Semestre"), - "send" : MessageLookupByLibrary.simpleMessage("Enviar"), - "sent_error" : MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), - "settings" : MessageLookupByLibrary.simpleMessage("Definições"), - "some_error" : MessageLookupByLibrary.simpleMessage("Algum erro!"), - "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), - "student_number" : MessageLookupByLibrary.simpleMessage("número de estudante"), - "success" : MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), - "successful_open" : MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), - "theme" : MessageLookupByLibrary.simpleMessage("Tema"), - "title" : MessageLookupByLibrary.simpleMessage("Título"), - "try_again" : MessageLookupByLibrary.simpleMessage("Tentar de novo"), - "try_different_login" : MessageLookupByLibrary.simpleMessage("Problemas a iniciar sessão? Experimenta o login alternativo"), - "uc_info" : MessageLookupByLibrary.simpleMessage("Abrir página da UC"), - "unavailable" : MessageLookupByLibrary.simpleMessage("Indisponível"), - "valid_email" : MessageLookupByLibrary.simpleMessage("Por favor insere um email válido"), - "widget_prompt" : MessageLookupByLibrary.simpleMessage("Escolhe um widget para adicionares à tua área pessoal:"), - "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "year" : MessageLookupByLibrary.simpleMessage("Ano"), - "yes" : MessageLookupByLibrary.simpleMessage("Sim") - }; + static _notInlinedMessages(_) => { + "about": MessageLookupByLibrary.simpleMessage("Sobre nós"), + "academic_services": + MessageLookupByLibrary.simpleMessage("Serviços académicos"), + "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"), + "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"), + "available_amount": + MessageLookupByLibrary.simpleMessage("Valor disponível"), + "average": MessageLookupByLibrary.simpleMessage("Média: "), + "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), + "banner_info": MessageLookupByLibrary.simpleMessage( + "Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), + "bibliography": MessageLookupByLibrary.simpleMessage("Bibliografia"), + "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( + "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"), + "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"), + "collect_usage_stats": MessageLookupByLibrary.simpleMessage( + "Partilhar estatísticas de uso"), + "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"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), + "confirm_logout": MessageLookupByLibrary.simpleMessage( + "Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), + "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"), + "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"), + "dona_bia": + MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Piso -1 do edifício B (B-142)"), + "download_error": MessageLookupByLibrary.simpleMessage( + "Erro ao descarregar o ficheiro"), + "ects": MessageLookupByLibrary.simpleMessage("ECTS realizados: "), + "edit_off": MessageLookupByLibrary.simpleMessage("Editar"), + "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), + "empty_text": MessageLookupByLibrary.simpleMessage( + "Por favor preenche este campo"), + "evaluation": MessageLookupByLibrary.simpleMessage("Avaliação"), + "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"), + "fail_to_authenticate": + MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), + "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), + "fee_date": MessageLookupByLibrary.simpleMessage( + "Data limite próxima prestação:"), + "fee_notification": + MessageLookupByLibrary.simpleMessage("Data limite de propina"), + "files": MessageLookupByLibrary.simpleMessage("Ficheiros"), + "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€"), + "internet_status_exception": MessageLookupByLibrary.simpleMessage( + "Verifique sua conexão com a internet"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão"), + "language": MessageLookupByLibrary.simpleMessage("Idioma"), + "last_refresh_time": m0, + "last_timestamp": m1, + "library_occupation": + MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "load_error": MessageLookupByLibrary.simpleMessage( + "Erro ao carregar a informação"), + "loading_terms": MessageLookupByLibrary.simpleMessage( + "Carregando os Termos e Condições..."), + "login": MessageLookupByLibrary.simpleMessage("Entrar"), + "login_with_credentials": MessageLookupByLibrary.simpleMessage( + "Iniciar sessão com credenciais"), + "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": MessageLookupByLibrary.simpleMessage("Não"), + "no_app": MessageLookupByLibrary.simpleMessage( + "Nenhuma aplicação encontrada para abrir o ficheiro"), + "no_bus": MessageLookupByLibrary.simpleMessage( + "Não percas nenhum autocarro!"), + "no_bus_stops": MessageLookupByLibrary.simpleMessage( + "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"), + "no_classes_on": + MessageLookupByLibrary.simpleMessage("Não possui aulas à"), + "no_classes_on_weekend": + MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), + "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), + "no_course_units": MessageLookupByLibrary.simpleMessage( + "Sem cadeiras no período selecionado"), + "no_data": MessageLookupByLibrary.simpleMessage( + "Não há dados a mostrar neste momento"), + "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), + "no_events": + MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), + "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_files_found": + MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), + "no_info": MessageLookupByLibrary.simpleMessage( + "Não existem informações para apresentar"), + "no_internet": + MessageLookupByLibrary.simpleMessage("Parece que estás offline"), + "no_library_info": + MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), + "no_link": MessageLookupByLibrary.simpleMessage( + "Não conseguimos abrir o link"), + "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_name_course": + MessageLookupByLibrary.simpleMessage("Curso sem nome"), + "no_places_info": MessageLookupByLibrary.simpleMessage( + "Não há informação disponível sobre locais"), + "no_print_info": + MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), + "no_references": MessageLookupByLibrary.simpleMessage( + "Não existem referências a pagar"), + "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"), + "notifications": MessageLookupByLibrary.simpleMessage("Notificações"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), + "of_month": MessageLookupByLibrary.simpleMessage("de"), + "open_error": + MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), + "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"), + "permission_denied": + MessageLookupByLibrary.simpleMessage("Sem permissão"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "press_again": MessageLookupByLibrary.simpleMessage( + "Pressione novamente para sair"), + "print": MessageLookupByLibrary.simpleMessage("Impressão"), + "prints": MessageLookupByLibrary.simpleMessage("Impressões"), + "problem_id": MessageLookupByLibrary.simpleMessage( + "Breve identificação do problema"), + "program": MessageLookupByLibrary.simpleMessage("Programa"), + "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( + "Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), + "reference_success": MessageLookupByLibrary.simpleMessage( + "Referência criada com sucesso!"), + "remove": MessageLookupByLibrary.simpleMessage("Remover"), + "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), + "report_error_suggestion": + MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), + "restaurant_main_page": MessageLookupByLibrary.simpleMessage( + "Queres ver os teus restaurantes favoritos na página principal?"), + "room": MessageLookupByLibrary.simpleMessage("Sala"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("Calendário Escolar"), + "search": MessageLookupByLibrary.simpleMessage("Pesquisar"), + "semester": MessageLookupByLibrary.simpleMessage("Semestre"), + "send": MessageLookupByLibrary.simpleMessage("Enviar"), + "sent_error": + MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), + "settings": MessageLookupByLibrary.simpleMessage("Definições"), + "some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "student_number": + MessageLookupByLibrary.simpleMessage("número de estudante"), + "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), + "successful_open": + MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), + "theme": MessageLookupByLibrary.simpleMessage("Tema"), + "title": MessageLookupByLibrary.simpleMessage("Título"), + "try_again": MessageLookupByLibrary.simpleMessage("Tentar de novo"), + "try_different_login": MessageLookupByLibrary.simpleMessage( + "Problemas a iniciar sessão? Experimenta o login alternativo"), + "uc_info": MessageLookupByLibrary.simpleMessage("Abrir página da UC"), + "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), + "valid_email": MessageLookupByLibrary.simpleMessage( + "Por favor insere um email válido"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Escolhe um widget para adicionares à tua área pessoal:"), + "wrong_credentials_exception": + MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "year": MessageLookupByLibrary.simpleMessage("Ano"), + "yes": MessageLookupByLibrary.simpleMessage("Sim") + }; } diff --git a/packages/uni_app/lib/generated/l10n.dart b/packages/uni_app/lib/generated/l10n.dart index 04b76c9ef..3ec5fd8f5 100644 --- a/packages/uni_app/lib/generated/l10n.dart +++ b/packages/uni_app/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!; } @@ -247,10 +250,10 @@ class S { ); } - /// `Bibliografia` + /// `Bibliography` String get bibliography { return Intl.message( - 'Bibliografia', + 'Bibliography', name: 'bibliography', desc: '', args: [], @@ -1711,4 +1714,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} \ No newline at end of file +} diff --git a/packages/uni_app/lib/l10n/intl_en.arb b/packages/uni_app/lib/l10n/intl_en.arb index 94b7d3c06..c6c45536e 100644 --- a/packages/uni_app/lib/l10n/intl_en.arb +++ b/packages/uni_app/lib/l10n/intl_en.arb @@ -40,7 +40,7 @@ "@banner_info": {}, "balance": "Balance:", "@balance": {}, - "bibliography": "Bibliografia", + "bibliography": "Bibliography", "@bibliography": {}, "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": {}, diff --git a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart index e5f1d95ce..d4df55a78 100644 --- a/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart +++ b/packages/uni_app/lib/view/course_unit_info/widgets/course_unit_sheet.dart @@ -220,7 +220,10 @@ Widget buildBooksRow(BuildContext context, List books) { } Widget _buildCard( - String sectionTitle, String sectionContent, BuildContext context) { + String sectionTitle, + String sectionContent, + BuildContext context, +) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Column( From 837c1c78b4a8563f3f1134d84e7ca54ea4098834 Mon Sep 17 00:00:00 2001 From: limwa Date: Mon, 16 Sep 2024 23:53:54 +0000 Subject: [PATCH 81/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 49565d6df..58ec195f0 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.5+302 +1.10.0-beta.6+303 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 606fa1794..eb535073d 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.5+302 +version: 1.10.0-beta.6+303 environment: sdk: ">=3.4.0 <4.0.0" From 1fc65d3f66f4ec111305ff5f7b3daee1d681d71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Tue, 17 Sep 2024 14:42:07 +0100 Subject: [PATCH 82/99] fix: unit info error on relogin Co-Authored-By: Process-ing --- .../lib/model/providers/state_provider_notifier.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/model/providers/state_provider_notifier.dart b/packages/uni_app/lib/model/providers/state_provider_notifier.dart index 2b47392fc..ff0469e95 100644 --- a/packages/uni_app/lib/model/providers/state_provider_notifier.dart +++ b/packages/uni_app/lib/model/providers/state_provider_notifier.dart @@ -16,8 +16,12 @@ abstract class StateProviderNotifier extends ChangeNotifier { RequestStatus initialStatus = RequestStatus.busy, T? initialState, }) : _requestStatus = initialStatus, + _initialState = initialState, _state = initialState; + /// The initial state of the model. + final T? _initialState; + /// The model that this notifier provides. /// This future will throw if the data loading fails. T? _state; @@ -68,7 +72,7 @@ abstract class StateProviderNotifier extends ChangeNotifier { /// Makes the state null, as if the model has never been loaded, /// so that consumers may trigger the loading again. void invalidate() { - _state = null; + _state = _initialState; notifyListeners(); } From 0abc077d2886188cabb17a3e14b3f9121a9bac73 Mon Sep 17 00:00:00 2001 From: limwa Date: Tue, 17 Sep 2024 14:54:20 +0000 Subject: [PATCH 83/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 58ec195f0..cb83f6b04 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.6+303 +1.10.0-beta.7+304 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index eb535073d..ac2b5c544 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.6+303 +version: 1.10.0-beta.7+304 environment: sdk: ">=3.4.0 <4.0.0" From ef5d4ce887c8679c1afeae011862000744ad7b33 Mon Sep 17 00:00:00 2001 From: niaefeup-admin Date: Wed, 18 Sep 2024 20:09:22 +0000 Subject: [PATCH 84/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index cb83f6b04..543c2b5b3 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.7+304 +1.10.0-beta.8+306 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index ac2b5c544..1ad2dc965 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.7+304 +version: 1.10.0-beta.8+306 environment: sdk: ">=3.4.0 <4.0.0" From 4538f7c36a23862076e414a2f7e4f28bd350ac73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 19 Sep 2024 00:52:11 +0100 Subject: [PATCH 85/99] fix: forbidden error on calendar fetching --- .../lib/controller/networking/network_router.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index e78f43b9d..d6a8bf379 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -11,6 +11,10 @@ extension UriString on String { Uri toUri() => Uri.parse(this); } +extension SigarraUriEncoding on Uri { + Uri normalizeQueryComponent() => replace(query: query.replaceAll('+', '%20')); +} + /// Manages the networking of the app. class NetworkRouter { /// The HTTP client used for all requests. @@ -65,6 +69,10 @@ class NetworkRouter { ]; } - return client.get(parsedUrl.replace(queryParameters: allQueryParameters)); + final requestUri = parsedUrl + .replace(queryParameters: allQueryParameters) + .normalizeQueryComponent(); + + return client.get(requestUri); } } From 346dce2bc253a40d4818044e754ef94a2c30402b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 19 Sep 2024 01:07:02 +0100 Subject: [PATCH 86/99] refactor: deduplicate logic --- .../uni_app/lib/app_links/uni_app_links.dart | 9 ++------- .../controller/networking/network_router.dart | 5 +---- packages/uni_app/lib/utils/uri.dart | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 packages/uni_app/lib/utils/uri.dart diff --git a/packages/uni_app/lib/app_links/uni_app_links.dart b/packages/uni_app/lib/app_links/uni_app_links.dart index e0a7c5a20..c168dcda9 100644 --- a/packages/uni_app/lib/app_links/uni_app_links.dart +++ b/packages/uni_app/lib/app_links/uni_app_links.dart @@ -1,15 +1,10 @@ import 'dart:async'; import 'package:app_links/app_links.dart'; +import 'package:uni/utils/uri.dart'; final _authUri = Uri(scheme: 'pt.up.fe.ni.uni', host: 'auth'); -extension _StripQueryParameters on Uri { - Uri stripQueryParameters() { - return Uri(scheme: scheme, host: host, path: path); - } -} - class UniAppLinks { final login = _AuthenticationAppLink( redirectUri: _authUri.replace(path: '/login'), @@ -30,7 +25,7 @@ class _AuthenticationAppLink { FutureOr Function(Uri redirectUri) callback, ) async { final interceptedUri = _appLinks.uriLinkStream - .firstWhere((uri) => redirectUri == uri.stripQueryParameters()); + .firstWhere((uri) => redirectUri == uri.stripQueryComponent()); await callback(redirectUri); final data = await interceptedUri; diff --git a/packages/uni_app/lib/controller/networking/network_router.dart b/packages/uni_app/lib/controller/networking/network_router.dart index d6a8bf379..7fcff1dcc 100644 --- a/packages/uni_app/lib/controller/networking/network_router.dart +++ b/packages/uni_app/lib/controller/networking/network_router.dart @@ -5,16 +5,13 @@ import 'package:uni/http/client/authenticated.dart'; import 'package:uni/http/client/timeout.dart'; import 'package:uni/session/authentication_controller.dart'; import 'package:uni/session/flows/base/session.dart'; +import 'package:uni/utils/uri.dart'; extension UriString on String { /// Converts a [String] to an [Uri]. Uri toUri() => Uri.parse(this); } -extension SigarraUriEncoding on Uri { - Uri normalizeQueryComponent() => replace(query: query.replaceAll('+', '%20')); -} - /// Manages the networking of the app. class NetworkRouter { /// The HTTP client used for all requests. diff --git a/packages/uni_app/lib/utils/uri.dart b/packages/uni_app/lib/utils/uri.dart new file mode 100644 index 000000000..29cebecb2 --- /dev/null +++ b/packages/uni_app/lib/utils/uri.dart @@ -0,0 +1,16 @@ +extension UriUtils on Uri { + Uri stripQueryComponent() { + return Uri( + scheme: scheme, + userInfo: userInfo, + host: host, + port: port, + path: path, + fragment: fragment, + ); + } + + Uri normalizeQueryComponent() => query.isNotEmpty + ? replace(query: query.replaceAll('+', '%20')) + : stripQueryComponent(); +} From 5515d1dde6d66ef50faa018cce5483de05914889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Thu, 19 Sep 2024 14:58:29 +0100 Subject: [PATCH 87/99] fix: app link not being intercepted --- packages/uni_app/lib/utils/uri.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uni_app/lib/utils/uri.dart b/packages/uni_app/lib/utils/uri.dart index 29cebecb2..c2f140ba9 100644 --- a/packages/uni_app/lib/utils/uri.dart +++ b/packages/uni_app/lib/utils/uri.dart @@ -6,7 +6,7 @@ extension UriUtils on Uri { host: host, port: port, path: path, - fragment: fragment, + fragment: fragment.isNotEmpty ? fragment : null, ); } From 6d67b6fa2f8461282b4c2e1146df8a7c99849135 Mon Sep 17 00:00:00 2001 From: limwa Date: Fri, 20 Sep 2024 08:40:36 +0000 Subject: [PATCH 88/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 543c2b5b3..7e44e6946 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.8+306 +1.10.0-beta.9+307 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 1ad2dc965..c9ff63acc 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.8+306 +version: 1.10.0-beta.9+307 environment: sdk: ">=3.4.0 <4.0.0" From 67e8ccec6b086168948b4dad852dc033adca014e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 20 Sep 2024 22:07:45 +0100 Subject: [PATCH 89/99] fix: exams background --- packages/uni_app/lib/view/exams/exams.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/uni_app/lib/view/exams/exams.dart b/packages/uni_app/lib/view/exams/exams.dart index 207b0fa55..40ecde31f 100644 --- a/packages/uni_app/lib/view/exams/exams.dart +++ b/packages/uni_app/lib/view/exams/exams.dart @@ -139,9 +139,7 @@ class ExamsPageViewState extends SecondaryPageViewState { key: Key('$exam-exam'), margin: const EdgeInsets.fromLTRB(12, 4, 12, 0), child: RowContainer( - color: isHidden - ? Theme.of(context).hintColor - : Theme.of(context).scaffoldBackgroundColor, + color: isHidden ? Theme.of(context).hintColor : null, child: ExamRow( exam: exam, teacher: '', From c66f7a73f73747340fce5457718da34539fac27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 20 Sep 2024 22:08:39 +0100 Subject: [PATCH 90/99] fix: transports background --- .../bus_stop_next_arrivals/bus_stop_next_arrivals.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/uni_app/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart b/packages/uni_app/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart index 85705edac..4271c9182 100644 --- a/packages/uni_app/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart +++ b/packages/uni_app/lib/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart @@ -132,11 +132,9 @@ class NextArrivalsState extends State { ), ), constraints: const BoxConstraints(maxHeight: 150), - child: Material( - child: TabBar( - isScrollable: true, - tabs: createTabs(queryData), - ), + child: TabBar( + isScrollable: true, + tabs: createTabs(queryData), ), ), Expanded( From 69ff45e2d46e6d21bbeff362dadb61ce50bcafc5 Mon Sep 17 00:00:00 2001 From: limwa Date: Sun, 22 Sep 2024 19:15:03 +0000 Subject: [PATCH 91/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 7e44e6946..db8d561b6 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.9+307 +1.10.0-beta.10+308 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index c9ff63acc..d9f4fa559 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.9+307 +version: 1.10.0-beta.10+308 environment: sdk: ">=3.4.0 <4.0.0" From 0090db6573726def4cf815955c9e3354c7bbeb3a Mon Sep 17 00:00:00 2001 From: niaefeup-admin Date: Wed, 25 Sep 2024 13:14:33 +0000 Subject: [PATCH 92/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index db8d561b6..aa31bb552 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.10+308 +1.10.0-beta.11+310 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index d9f4fa559..8a809f3db 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.10+308 +version: 1.10.0-beta.11+310 environment: sdk: ">=3.4.0 <4.0.0" From 3c69b668a89b9e8e8a7b3d0ec95c44a2c8d4c5b5 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 26 Sep 2024 15:05:23 +0100 Subject: [PATCH 93/99] changing bg color and a missed translation --- .../lib/generated/intl/messages_all.dart | 9 +- .../lib/generated/intl/messages_en.dart | 443 +++++++---------- .../lib/generated/intl/messages_pt_PT.dart | 444 +++++++----------- packages/uni_app/lib/generated/l10n.dart | 31 +- packages/uni_app/lib/l10n/intl_en.arb | 2 + packages/uni_app/lib/l10n/intl_pt_PT.arb | 2 + .../widgets/bus_stop_row.dart | 3 +- .../widgets/bus_stop_search.dart | 7 + 8 files changed, 371 insertions(+), 570 deletions(-) diff --git a/packages/uni_app/lib/generated/intl/messages_all.dart b/packages/uni_app/lib/generated/intl/messages_all.dart index 6b3ebeae5..fb1bd2689 100644 --- a/packages/uni_app/lib/generated/intl/messages_all.dart +++ b/packages/uni_app/lib/generated/intl/messages_all.dart @@ -38,8 +38,9 @@ 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); + localeName, + (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { return new Future.value(false); } @@ -59,8 +60,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var 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/packages/uni_app/lib/generated/intl/messages_en.dart b/packages/uni_app/lib/generated/intl/messages_en.dart index 4719af7cd..05cdbdd8d 100644 --- a/packages/uni_app/lib/generated/intl/messages_en.dart +++ b/packages/uni_app/lib/generated/intl/messages_en.dart @@ -21,283 +21,174 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "last refresh at ${time}"; - static m1(time) => - "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + static m1(time) => "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - 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', - 'percurso_academico': 'Academic Path', - 'transportes': 'Transports', - 'faculdade': 'Faculty', - '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', 'percurso_academico': 'Academic Path', 'transportes': 'Transports', 'faculdade': 'Faculty', 'other': 'Other', })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about": MessageLookupByLibrary.simpleMessage("About us"), - "academic_services": - MessageLookupByLibrary.simpleMessage("Academic services"), - "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!"), - "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:"), - "banner_info": MessageLookupByLibrary.simpleMessage( - "We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), - "bibliography": MessageLookupByLibrary.simpleMessage("Bibliography"), - "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( - "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"), - "change": MessageLookupByLibrary.simpleMessage("Change"), - "change_prompt": MessageLookupByLibrary.simpleMessage( - "Do you want to change the password?"), - "check_internet": MessageLookupByLibrary.simpleMessage( - "Check your internet connection"), - "class_registration": - MessageLookupByLibrary.simpleMessage("Class Registration"), - "collect_usage_stats": - MessageLookupByLibrary.simpleMessage("Collect usage statistics"), - "college": MessageLookupByLibrary.simpleMessage("College: "), - "college_select": - MessageLookupByLibrary.simpleMessage("select your college(s)"), - "conclude": MessageLookupByLibrary.simpleMessage("Done"), - "configured_buses": - MessageLookupByLibrary.simpleMessage("Configured Buses"), - "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), - "confirm_logout": MessageLookupByLibrary.simpleMessage( - "Do you really want to log out? Your local data will be deleted and you will have to log in again."), - "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"), - "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"), - "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Floor -1 of building B (B-142)"), - "download_error": - MessageLookupByLibrary.simpleMessage("Error downloading the file"), - "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"), - "evaluation": MessageLookupByLibrary.simpleMessage("Evaluation"), - "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"), - "fail_to_authenticate": - MessageLookupByLibrary.simpleMessage("Failed to authenticate"), - "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), - "fee_date": - MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), - "fee_notification": - MessageLookupByLibrary.simpleMessage("Fee deadline"), - "files": MessageLookupByLibrary.simpleMessage("Files"), - "first_year_registration": MessageLookupByLibrary.simpleMessage( - "Year of first registration: "), - "floor": MessageLookupByLibrary.simpleMessage("Floor"), - "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€"), - "internet_status_exception": MessageLookupByLibrary.simpleMessage( - "Check your internet connection"), - "invalid_credentials": - MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), - "language": MessageLookupByLibrary.simpleMessage("Language"), - "last_refresh_time": m0, - "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..."), - "login": MessageLookupByLibrary.simpleMessage("Login"), - "login_with_credentials": - MessageLookupByLibrary.simpleMessage("Login with credentials"), - "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": MessageLookupByLibrary.simpleMessage("No"), - "no_app": MessageLookupByLibrary.simpleMessage( - "No app found to open the file"), - "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"), - "no_classes_on_weekend": - 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( - "There is no data to show at this time"), - "no_date": MessageLookupByLibrary.simpleMessage("No date"), - "no_events": MessageLookupByLibrary.simpleMessage("No events found"), - "no_exams": MessageLookupByLibrary.simpleMessage( - "You have no exams scheduled\n"), - "no_exams_label": MessageLookupByLibrary.simpleMessage( - "Looks like you are on vacation!"), - "no_favorite_restaurants": - MessageLookupByLibrary.simpleMessage("No favorite restaurants"), - "no_files_found": - MessageLookupByLibrary.simpleMessage("No files found"), - "no_info": MessageLookupByLibrary.simpleMessage( - "There is no information to display"), - "no_internet": MessageLookupByLibrary.simpleMessage( - "It looks like you\'re offline"), - "no_library_info": MessageLookupByLibrary.simpleMessage( - "No library occupation information available"), - "no_link": - MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), - "no_menu_info": MessageLookupByLibrary.simpleMessage( - "There is no information available about meals"), - "no_menus": MessageLookupByLibrary.simpleMessage( - "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_print_info": MessageLookupByLibrary.simpleMessage( - "No print balance information"), - "no_references": MessageLookupByLibrary.simpleMessage( - "There are no references to pay"), - "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"), - "notifications": MessageLookupByLibrary.simpleMessage("Notifications"), - "occurrence_type": - MessageLookupByLibrary.simpleMessage("Type of occurrence"), - "of_month": MessageLookupByLibrary.simpleMessage("of"), - "open_error": - MessageLookupByLibrary.simpleMessage("Error opening the file"), - "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"), - "permission_denied": - MessageLookupByLibrary.simpleMessage("Permission denied"), - "personal_assistance": - MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), - "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"), - "program": MessageLookupByLibrary.simpleMessage("Program"), - "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"), - "report_error": MessageLookupByLibrary.simpleMessage("Report error"), - "report_error_suggestion": - MessageLookupByLibrary.simpleMessage("Report error/suggestion"), - "restaurant_main_page": MessageLookupByLibrary.simpleMessage( - "Do you want to see your favorite restaurants in the main page?"), - "room": MessageLookupByLibrary.simpleMessage("Room"), - "school_calendar": - MessageLookupByLibrary.simpleMessage("School Calendar"), - "search": MessageLookupByLibrary.simpleMessage("Search"), - "semester": MessageLookupByLibrary.simpleMessage("Semester"), - "send": MessageLookupByLibrary.simpleMessage("Send"), - "sent_error": MessageLookupByLibrary.simpleMessage( - "An error occurred in sending"), - "settings": MessageLookupByLibrary.simpleMessage("Settings"), - "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), - "stcp_stops": - MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), - "student_number": - MessageLookupByLibrary.simpleMessage("student number"), - "success": MessageLookupByLibrary.simpleMessage("Sent with success"), - "successful_open": - MessageLookupByLibrary.simpleMessage("File opened successfully"), - "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"), - "theme": MessageLookupByLibrary.simpleMessage("Theme"), - "title": MessageLookupByLibrary.simpleMessage("Title"), - "try_again": MessageLookupByLibrary.simpleMessage("Try again"), - "try_different_login": MessageLookupByLibrary.simpleMessage( - "Problems with login? Try a different login"), - "uc_info": MessageLookupByLibrary.simpleMessage("Open UC page"), - "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), - "valid_email": - MessageLookupByLibrary.simpleMessage("Please enter a valid email"), - "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Choose a widget to add to your personal area:"), - "wrong_credentials_exception": - MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "year": MessageLookupByLibrary.simpleMessage("Year"), - "yes": MessageLookupByLibrary.simpleMessage("Yes") - }; + static _notInlinedMessages(_) => { + "about" : MessageLookupByLibrary.simpleMessage("About us"), + "academic_services" : MessageLookupByLibrary.simpleMessage("Academic services"), + "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!"), + "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:"), + "banner_info" : MessageLookupByLibrary.simpleMessage("We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), + "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliography"), + "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("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"), + "change" : MessageLookupByLibrary.simpleMessage("Change"), + "change_prompt" : MessageLookupByLibrary.simpleMessage("Do you want to change the password?"), + "check_internet" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), + "class_registration" : MessageLookupByLibrary.simpleMessage("Class Registration"), + "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Collect usage statistics"), + "college" : MessageLookupByLibrary.simpleMessage("College: "), + "college_select" : MessageLookupByLibrary.simpleMessage("select your college(s)"), + "conclude" : MessageLookupByLibrary.simpleMessage("Done"), + "configured_buses" : MessageLookupByLibrary.simpleMessage("Configured Buses"), + "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), + "confirm_logout" : MessageLookupByLibrary.simpleMessage("Do you really want to log out? Your local data will be deleted and you will have to log in again."), + "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"), + "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"), + "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Floor -1 of building B (B-142)"), + "download_error" : MessageLookupByLibrary.simpleMessage("Error downloading the file"), + "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"), + "evaluation" : MessageLookupByLibrary.simpleMessage("Evaluation"), + "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"), + "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Failed to authenticate"), + "failed_login" : MessageLookupByLibrary.simpleMessage("Login failed"), + "fee_date" : MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), + "fee_notification" : MessageLookupByLibrary.simpleMessage("Fee deadline"), + "files" : MessageLookupByLibrary.simpleMessage("Files"), + "first_year_registration" : MessageLookupByLibrary.simpleMessage("Year of first registration: "), + "floor" : MessageLookupByLibrary.simpleMessage("Floor"), + "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€"), + "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), + "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "keep_login" : MessageLookupByLibrary.simpleMessage("Stay signed in"), + "language" : MessageLookupByLibrary.simpleMessage("Language"), + "last_refresh_time" : m0, + "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..."), + "login" : MessageLookupByLibrary.simpleMessage("Login"), + "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Login with credentials"), + "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" : MessageLookupByLibrary.simpleMessage("No"), + "no_app" : MessageLookupByLibrary.simpleMessage("No app found to open the file"), + "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"), + "no_classes_on_weekend" : 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("There is no data to show at this time"), + "no_date" : MessageLookupByLibrary.simpleMessage("No date"), + "no_events" : MessageLookupByLibrary.simpleMessage("No events found"), + "no_exams" : MessageLookupByLibrary.simpleMessage("You have no exams scheduled\n"), + "no_exams_label" : MessageLookupByLibrary.simpleMessage("Looks like you are on vacation!"), + "no_favorite_restaurants" : MessageLookupByLibrary.simpleMessage("No favorite restaurants"), + "no_files_found" : MessageLookupByLibrary.simpleMessage("No files found"), + "no_info" : MessageLookupByLibrary.simpleMessage("There is no information to display"), + "no_internet" : MessageLookupByLibrary.simpleMessage("It looks like you\'re offline"), + "no_library_info" : MessageLookupByLibrary.simpleMessage("No library occupation information available"), + "no_link" : MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), + "no_menu_info" : MessageLookupByLibrary.simpleMessage("There is no information available about meals"), + "no_menus" : MessageLookupByLibrary.simpleMessage("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_print_info" : MessageLookupByLibrary.simpleMessage("No print balance information"), + "no_references" : MessageLookupByLibrary.simpleMessage("There are no references to pay"), + "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"), + "no_trips" : MessageLookupByLibrary.simpleMessage("No trips found at the moment"), + "notifications" : MessageLookupByLibrary.simpleMessage("Notifications"), + "occurrence_type" : MessageLookupByLibrary.simpleMessage("Type of occurrence"), + "of_month" : MessageLookupByLibrary.simpleMessage("of"), + "open_error" : MessageLookupByLibrary.simpleMessage("Error opening the file"), + "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"), + "permission_denied" : MessageLookupByLibrary.simpleMessage("Permission denied"), + "personal_assistance" : MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "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"), + "program" : MessageLookupByLibrary.simpleMessage("Program"), + "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"), + "report_error" : MessageLookupByLibrary.simpleMessage("Report error"), + "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Report error/suggestion"), + "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Do you want to see your favorite restaurants in the main page?"), + "room" : MessageLookupByLibrary.simpleMessage("Room"), + "school_calendar" : MessageLookupByLibrary.simpleMessage("School Calendar"), + "search" : MessageLookupByLibrary.simpleMessage("Search"), + "semester" : MessageLookupByLibrary.simpleMessage("Semester"), + "send" : MessageLookupByLibrary.simpleMessage("Send"), + "sent_error" : MessageLookupByLibrary.simpleMessage("An error occurred in sending"), + "settings" : MessageLookupByLibrary.simpleMessage("Settings"), + "some_error" : MessageLookupByLibrary.simpleMessage("Some error!"), + "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "student_number" : MessageLookupByLibrary.simpleMessage("student number"), + "success" : MessageLookupByLibrary.simpleMessage("Sent with success"), + "successful_open" : MessageLookupByLibrary.simpleMessage("File opened successfully"), + "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"), + "theme" : MessageLookupByLibrary.simpleMessage("Theme"), + "title" : MessageLookupByLibrary.simpleMessage("Title"), + "try_again" : MessageLookupByLibrary.simpleMessage("Try again"), + "try_different_login" : MessageLookupByLibrary.simpleMessage("Problems with login? Try a different login"), + "uc_info" : MessageLookupByLibrary.simpleMessage("Open UC page"), + "unavailable" : MessageLookupByLibrary.simpleMessage("Unavailable"), + "valid_email" : MessageLookupByLibrary.simpleMessage("Please enter a valid email"), + "widget_prompt" : MessageLookupByLibrary.simpleMessage("Choose a widget to add to your personal area:"), + "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "year" : MessageLookupByLibrary.simpleMessage("Year"), + "yes" : MessageLookupByLibrary.simpleMessage("Yes") + }; } diff --git a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart index 0198f3d78..c69b3a76e 100644 --- a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart +++ b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart @@ -21,284 +21,174 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "última atualização às ${time}"; - static m1(time) => - "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + static m1(time) => "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static 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', - 'percurso_academico': 'Percurso Académico', - 'transportes': 'Transportes', - 'faculdade': 'Faculdade', - 'other': 'Outros', - })}"; + static 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', 'percurso_academico': 'Percurso Académico', 'transportes': 'Transportes', 'faculdade': 'Faculdade', 'other': 'Outros', })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about": MessageLookupByLibrary.simpleMessage("Sobre nós"), - "academic_services": - MessageLookupByLibrary.simpleMessage("Serviços académicos"), - "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"), - "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"), - "available_amount": - MessageLookupByLibrary.simpleMessage("Valor disponível"), - "average": MessageLookupByLibrary.simpleMessage("Média: "), - "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), - "banner_info": MessageLookupByLibrary.simpleMessage( - "Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), - "bibliography": MessageLookupByLibrary.simpleMessage("Bibliografia"), - "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( - "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"), - "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"), - "collect_usage_stats": MessageLookupByLibrary.simpleMessage( - "Partilhar estatísticas de uso"), - "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"), - "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), - "confirm_logout": MessageLookupByLibrary.simpleMessage( - "Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), - "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"), - "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"), - "dona_bia": - MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), - "dona_bia_building": MessageLookupByLibrary.simpleMessage( - "Piso -1 do edifício B (B-142)"), - "download_error": MessageLookupByLibrary.simpleMessage( - "Erro ao descarregar o ficheiro"), - "ects": MessageLookupByLibrary.simpleMessage("ECTS realizados: "), - "edit_off": MessageLookupByLibrary.simpleMessage("Editar"), - "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), - "empty_text": MessageLookupByLibrary.simpleMessage( - "Por favor preenche este campo"), - "evaluation": MessageLookupByLibrary.simpleMessage("Avaliação"), - "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"), - "fail_to_authenticate": - MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), - "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), - "fee_date": MessageLookupByLibrary.simpleMessage( - "Data limite próxima prestação:"), - "fee_notification": - MessageLookupByLibrary.simpleMessage("Data limite de propina"), - "files": MessageLookupByLibrary.simpleMessage("Ficheiros"), - "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€"), - "internet_status_exception": MessageLookupByLibrary.simpleMessage( - "Verifique sua conexão com a internet"), - "invalid_credentials": - MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão"), - "language": MessageLookupByLibrary.simpleMessage("Idioma"), - "last_refresh_time": m0, - "last_timestamp": m1, - "library_occupation": - MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), - "load_error": MessageLookupByLibrary.simpleMessage( - "Erro ao carregar a informação"), - "loading_terms": MessageLookupByLibrary.simpleMessage( - "Carregando os Termos e Condições..."), - "login": MessageLookupByLibrary.simpleMessage("Entrar"), - "login_with_credentials": MessageLookupByLibrary.simpleMessage( - "Iniciar sessão com credenciais"), - "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": MessageLookupByLibrary.simpleMessage("Não"), - "no_app": MessageLookupByLibrary.simpleMessage( - "Nenhuma aplicação encontrada para abrir o ficheiro"), - "no_bus": MessageLookupByLibrary.simpleMessage( - "Não percas nenhum autocarro!"), - "no_bus_stops": MessageLookupByLibrary.simpleMessage( - "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"), - "no_classes_on": - MessageLookupByLibrary.simpleMessage("Não possui aulas à"), - "no_classes_on_weekend": - MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), - "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), - "no_course_units": MessageLookupByLibrary.simpleMessage( - "Sem cadeiras no período selecionado"), - "no_data": MessageLookupByLibrary.simpleMessage( - "Não há dados a mostrar neste momento"), - "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), - "no_events": - MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), - "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_files_found": - MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), - "no_info": MessageLookupByLibrary.simpleMessage( - "Não existem informações para apresentar"), - "no_internet": - MessageLookupByLibrary.simpleMessage("Parece que estás offline"), - "no_library_info": - MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), - "no_link": MessageLookupByLibrary.simpleMessage( - "Não conseguimos abrir o link"), - "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_name_course": - MessageLookupByLibrary.simpleMessage("Curso sem nome"), - "no_places_info": MessageLookupByLibrary.simpleMessage( - "Não há informação disponível sobre locais"), - "no_print_info": - MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), - "no_references": MessageLookupByLibrary.simpleMessage( - "Não existem referências a pagar"), - "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"), - "notifications": MessageLookupByLibrary.simpleMessage("Notificações"), - "occurrence_type": - MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), - "of_month": MessageLookupByLibrary.simpleMessage("de"), - "open_error": - MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), - "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"), - "permission_denied": - MessageLookupByLibrary.simpleMessage("Sem permissão"), - "personal_assistance": - MessageLookupByLibrary.simpleMessage("Atendimento presencial"), - "press_again": MessageLookupByLibrary.simpleMessage( - "Pressione novamente para sair"), - "print": MessageLookupByLibrary.simpleMessage("Impressão"), - "prints": MessageLookupByLibrary.simpleMessage("Impressões"), - "problem_id": MessageLookupByLibrary.simpleMessage( - "Breve identificação do problema"), - "program": MessageLookupByLibrary.simpleMessage("Programa"), - "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( - "Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), - "reference_success": MessageLookupByLibrary.simpleMessage( - "Referência criada com sucesso!"), - "remove": MessageLookupByLibrary.simpleMessage("Remover"), - "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), - "report_error_suggestion": - MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), - "restaurant_main_page": MessageLookupByLibrary.simpleMessage( - "Queres ver os teus restaurantes favoritos na página principal?"), - "room": MessageLookupByLibrary.simpleMessage("Sala"), - "school_calendar": - MessageLookupByLibrary.simpleMessage("Calendário Escolar"), - "search": MessageLookupByLibrary.simpleMessage("Pesquisar"), - "semester": MessageLookupByLibrary.simpleMessage("Semestre"), - "send": MessageLookupByLibrary.simpleMessage("Enviar"), - "sent_error": - MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), - "settings": MessageLookupByLibrary.simpleMessage("Definições"), - "some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"), - "stcp_stops": - MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), - "student_number": - MessageLookupByLibrary.simpleMessage("número de estudante"), - "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), - "successful_open": - MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), - "theme": MessageLookupByLibrary.simpleMessage("Tema"), - "title": MessageLookupByLibrary.simpleMessage("Título"), - "try_again": MessageLookupByLibrary.simpleMessage("Tentar de novo"), - "try_different_login": MessageLookupByLibrary.simpleMessage( - "Problemas a iniciar sessão? Experimenta o login alternativo"), - "uc_info": MessageLookupByLibrary.simpleMessage("Abrir página da UC"), - "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), - "valid_email": MessageLookupByLibrary.simpleMessage( - "Por favor insere um email válido"), - "widget_prompt": MessageLookupByLibrary.simpleMessage( - "Escolhe um widget para adicionares à tua área pessoal:"), - "wrong_credentials_exception": - MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "year": MessageLookupByLibrary.simpleMessage("Ano"), - "yes": MessageLookupByLibrary.simpleMessage("Sim") - }; + static _notInlinedMessages(_) => { + "about" : MessageLookupByLibrary.simpleMessage("Sobre nós"), + "academic_services" : MessageLookupByLibrary.simpleMessage("Serviços académicos"), + "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"), + "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"), + "available_amount" : MessageLookupByLibrary.simpleMessage("Valor disponível"), + "average" : MessageLookupByLibrary.simpleMessage("Média: "), + "balance" : MessageLookupByLibrary.simpleMessage("Saldo:"), + "banner_info" : MessageLookupByLibrary.simpleMessage("Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), + "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), + "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("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"), + "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"), + "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Partilhar estatísticas de uso"), + "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"), + "confirm" : MessageLookupByLibrary.simpleMessage("Confirmar"), + "confirm_logout" : MessageLookupByLibrary.simpleMessage("Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), + "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"), + "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"), + "dona_bia" : MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), + "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Piso -1 do edifício B (B-142)"), + "download_error" : MessageLookupByLibrary.simpleMessage("Erro ao descarregar o ficheiro"), + "ects" : MessageLookupByLibrary.simpleMessage("ECTS realizados: "), + "edit_off" : MessageLookupByLibrary.simpleMessage("Editar"), + "edit_on" : MessageLookupByLibrary.simpleMessage("Concluir edição"), + "empty_text" : MessageLookupByLibrary.simpleMessage("Por favor preenche este campo"), + "evaluation" : MessageLookupByLibrary.simpleMessage("Avaliação"), + "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"), + "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), + "failed_login" : MessageLookupByLibrary.simpleMessage("O login falhou"), + "fee_date" : MessageLookupByLibrary.simpleMessage("Data limite próxima prestação:"), + "fee_notification" : MessageLookupByLibrary.simpleMessage("Data limite de propina"), + "files" : MessageLookupByLibrary.simpleMessage("Ficheiros"), + "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€"), + "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Verifique sua conexão com a internet"), + "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "keep_login" : MessageLookupByLibrary.simpleMessage("Manter sessão"), + "language" : MessageLookupByLibrary.simpleMessage("Idioma"), + "last_refresh_time" : m0, + "last_timestamp" : m1, + "library_occupation" : MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "load_error" : MessageLookupByLibrary.simpleMessage("Erro ao carregar a informação"), + "loading_terms" : MessageLookupByLibrary.simpleMessage("Carregando os Termos e Condições..."), + "login" : MessageLookupByLibrary.simpleMessage("Entrar"), + "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Iniciar sessão com credenciais"), + "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" : MessageLookupByLibrary.simpleMessage("Não"), + "no_app" : MessageLookupByLibrary.simpleMessage("Nenhuma aplicação encontrada para abrir o ficheiro"), + "no_bus" : MessageLookupByLibrary.simpleMessage("Não percas nenhum autocarro!"), + "no_bus_stops" : MessageLookupByLibrary.simpleMessage("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"), + "no_classes_on" : MessageLookupByLibrary.simpleMessage("Não possui aulas à"), + "no_classes_on_weekend" : MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), + "no_college" : MessageLookupByLibrary.simpleMessage("sem faculdade"), + "no_course_units" : MessageLookupByLibrary.simpleMessage("Sem cadeiras no período selecionado"), + "no_data" : MessageLookupByLibrary.simpleMessage("Não há dados a mostrar neste momento"), + "no_date" : MessageLookupByLibrary.simpleMessage("Sem data"), + "no_events" : MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), + "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_files_found" : MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), + "no_info" : MessageLookupByLibrary.simpleMessage("Não existem informações para apresentar"), + "no_internet" : MessageLookupByLibrary.simpleMessage("Parece que estás offline"), + "no_library_info" : MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), + "no_link" : MessageLookupByLibrary.simpleMessage("Não conseguimos abrir o link"), + "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_name_course" : MessageLookupByLibrary.simpleMessage("Curso sem nome"), + "no_places_info" : MessageLookupByLibrary.simpleMessage("Não há informação disponível sobre locais"), + "no_print_info" : MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), + "no_references" : MessageLookupByLibrary.simpleMessage("Não existem referências a pagar"), + "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"), + "no_trips" : MessageLookupByLibrary.simpleMessage("Não há viagens planeadas de momento"), + "notifications" : MessageLookupByLibrary.simpleMessage("Notificações"), + "occurrence_type" : MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), + "of_month" : MessageLookupByLibrary.simpleMessage("de"), + "open_error" : MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), + "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"), + "permission_denied" : MessageLookupByLibrary.simpleMessage("Sem permissão"), + "personal_assistance" : MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "press_again" : MessageLookupByLibrary.simpleMessage("Pressione novamente para sair"), + "print" : MessageLookupByLibrary.simpleMessage("Impressão"), + "prints" : MessageLookupByLibrary.simpleMessage("Impressões"), + "problem_id" : MessageLookupByLibrary.simpleMessage("Breve identificação do problema"), + "program" : MessageLookupByLibrary.simpleMessage("Programa"), + "reference_sigarra_help" : MessageLookupByLibrary.simpleMessage("Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), + "reference_success" : MessageLookupByLibrary.simpleMessage("Referência criada com sucesso!"), + "remove" : MessageLookupByLibrary.simpleMessage("Remover"), + "report_error" : MessageLookupByLibrary.simpleMessage("Reportar erro"), + "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), + "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Queres ver os teus restaurantes favoritos na página principal?"), + "room" : MessageLookupByLibrary.simpleMessage("Sala"), + "school_calendar" : MessageLookupByLibrary.simpleMessage("Calendário Escolar"), + "search" : MessageLookupByLibrary.simpleMessage("Pesquisar"), + "semester" : MessageLookupByLibrary.simpleMessage("Semestre"), + "send" : MessageLookupByLibrary.simpleMessage("Enviar"), + "sent_error" : MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), + "settings" : MessageLookupByLibrary.simpleMessage("Definições"), + "some_error" : MessageLookupByLibrary.simpleMessage("Algum erro!"), + "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "student_number" : MessageLookupByLibrary.simpleMessage("número de estudante"), + "success" : MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), + "successful_open" : MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), + "theme" : MessageLookupByLibrary.simpleMessage("Tema"), + "title" : MessageLookupByLibrary.simpleMessage("Título"), + "try_again" : MessageLookupByLibrary.simpleMessage("Tentar de novo"), + "try_different_login" : MessageLookupByLibrary.simpleMessage("Problemas a iniciar sessão? Experimenta o login alternativo"), + "uc_info" : MessageLookupByLibrary.simpleMessage("Abrir página da UC"), + "unavailable" : MessageLookupByLibrary.simpleMessage("Indisponível"), + "valid_email" : MessageLookupByLibrary.simpleMessage("Por favor insere um email válido"), + "widget_prompt" : MessageLookupByLibrary.simpleMessage("Escolhe um widget para adicionares à tua área pessoal:"), + "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "year" : MessageLookupByLibrary.simpleMessage("Ano"), + "yes" : MessageLookupByLibrary.simpleMessage("Sim") + }; } diff --git a/packages/uni_app/lib/generated/l10n.dart b/packages/uni_app/lib/generated/l10n.dart index 3ec5fd8f5..ffce269e6 100644 --- a/packages/uni_app/lib/generated/l10n.dart +++ b/packages/uni_app/lib/generated/l10n.dart @@ -18,31 +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!; } @@ -1198,6 +1195,16 @@ class S { ); } + /// `No trips found at the moment` + String get no_trips { + return Intl.message( + 'No trips found at the moment', + name: 'no_trips', + desc: '', + args: [], + ); + } + /// `Other links` String get other_links { return Intl.message( @@ -1714,4 +1721,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} +} \ No newline at end of file diff --git a/packages/uni_app/lib/l10n/intl_en.arb b/packages/uni_app/lib/l10n/intl_en.arb index c6c45536e..5e3eb22a6 100644 --- a/packages/uni_app/lib/l10n/intl_en.arb +++ b/packages/uni_app/lib/l10n/intl_en.arb @@ -234,6 +234,8 @@ "@no_internet": {}, "no_files_found": "No files found", "@no_files_found": {}, + "no_trips": "No trips found at the moment", + "@no_trips": {}, "other_links": "Other links", "@other_links": {}, "pass_change_request": "For security reasons, passwords must be changed periodically.", diff --git a/packages/uni_app/lib/l10n/intl_pt_PT.arb b/packages/uni_app/lib/l10n/intl_pt_PT.arb index 14837abe4..4212fe69c 100644 --- a/packages/uni_app/lib/l10n/intl_pt_PT.arb +++ b/packages/uni_app/lib/l10n/intl_pt_PT.arb @@ -244,6 +244,8 @@ "@no_link": {}, "no_files_found": "Nenhum ficheiro encontrado", "@no_files_found": {}, + "no_trips": "Não há viagens planeadas de momento", + "@no_trips": {}, "other_links": "Outros links", "@other_links": {}, "pass_change_request": "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", diff --git a/packages/uni_app/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart b/packages/uni_app/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart index 0661fd001..7e9c36542 100644 --- a/packages/uni_app/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart +++ b/packages/uni_app/lib/view/bus_stop_next_arrivals/widgets/bus_stop_row.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; import 'package:uni/model/entities/trip.dart'; import 'package:uni/view/bus_stop_next_arrivals/widgets/trip_row.dart'; @@ -48,7 +49,7 @@ class BusStopRow extends StatelessWidget { return Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Text( - 'Não há viagens planeadas de momento.', + S.of(context).no_trips, maxLines: 3, textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, diff --git a/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart b/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart index 8c1b03b79..967d9a632 100644 --- a/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart +++ b/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart @@ -38,6 +38,13 @@ class BusStopSearch extends SearchDelegate { ]; } + @override + ThemeData appBarTheme(BuildContext context) { + return Theme.of(context).copyWith( + scaffoldBackgroundColor: Theme.of(context).colorScheme.surface, + ); + } + @override Widget buildLeading(BuildContext context) { // Back arrow to go back to menu From a235ca9c816b107bdec83aa25898f3bacf6e5a03 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 26 Sep 2024 15:07:50 +0100 Subject: [PATCH 94/99] formatting --- .../lib/generated/intl/messages_all.dart | 9 +- .../lib/generated/intl/messages_en.dart | 445 ++++++++++------- .../lib/generated/intl/messages_pt_PT.dart | 446 +++++++++++------- packages/uni_app/lib/generated/l10n.dart | 21 +- 4 files changed, 573 insertions(+), 348 deletions(-) diff --git a/packages/uni_app/lib/generated/intl/messages_all.dart b/packages/uni_app/lib/generated/intl/messages_all.dart index fb1bd2689..6b3ebeae5 100644 --- a/packages/uni_app/lib/generated/intl/messages_all.dart +++ b/packages/uni_app/lib/generated/intl/messages_all.dart @@ -38,9 +38,8 @@ 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); + localeName, (locale) => _deferredLibraries[locale] != null, + onFailure: (_) => null); if (availableLocale == null) { return new Future.value(false); } @@ -60,8 +59,8 @@ bool _messagesExistFor(String locale) { } MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) { - var 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/packages/uni_app/lib/generated/intl/messages_en.dart b/packages/uni_app/lib/generated/intl/messages_en.dart index 05cdbdd8d..24826a3e3 100644 --- a/packages/uni_app/lib/generated/intl/messages_en.dart +++ b/packages/uni_app/lib/generated/intl/messages_en.dart @@ -21,174 +21,285 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "last refresh at ${time}"; - static m1(time) => "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; + static m1(time) => + "${Intl.plural(time, zero: 'Refreshed ${time} minutes ago', one: 'Refreshed ${time} minute ago', other: 'Refreshed ${time} minutes ago')}"; - 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', 'percurso_academico': 'Academic Path', 'transportes': 'Transports', 'faculdade': 'Faculty', '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', + 'percurso_academico': 'Academic Path', + 'transportes': 'Transports', + 'faculdade': 'Faculty', + 'other': 'Other', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about" : MessageLookupByLibrary.simpleMessage("About us"), - "academic_services" : MessageLookupByLibrary.simpleMessage("Academic services"), - "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!"), - "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:"), - "banner_info" : MessageLookupByLibrary.simpleMessage("We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), - "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliography"), - "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("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"), - "change" : MessageLookupByLibrary.simpleMessage("Change"), - "change_prompt" : MessageLookupByLibrary.simpleMessage("Do you want to change the password?"), - "check_internet" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), - "class_registration" : MessageLookupByLibrary.simpleMessage("Class Registration"), - "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Collect usage statistics"), - "college" : MessageLookupByLibrary.simpleMessage("College: "), - "college_select" : MessageLookupByLibrary.simpleMessage("select your college(s)"), - "conclude" : MessageLookupByLibrary.simpleMessage("Done"), - "configured_buses" : MessageLookupByLibrary.simpleMessage("Configured Buses"), - "confirm" : MessageLookupByLibrary.simpleMessage("Confirm"), - "confirm_logout" : MessageLookupByLibrary.simpleMessage("Do you really want to log out? Your local data will be deleted and you will have to log in again."), - "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"), - "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"), - "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Floor -1 of building B (B-142)"), - "download_error" : MessageLookupByLibrary.simpleMessage("Error downloading the file"), - "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"), - "evaluation" : MessageLookupByLibrary.simpleMessage("Evaluation"), - "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"), - "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Failed to authenticate"), - "failed_login" : MessageLookupByLibrary.simpleMessage("Login failed"), - "fee_date" : MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), - "fee_notification" : MessageLookupByLibrary.simpleMessage("Fee deadline"), - "files" : MessageLookupByLibrary.simpleMessage("Files"), - "first_year_registration" : MessageLookupByLibrary.simpleMessage("Year of first registration: "), - "floor" : MessageLookupByLibrary.simpleMessage("Floor"), - "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€"), - "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Check your internet connection"), - "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "keep_login" : MessageLookupByLibrary.simpleMessage("Stay signed in"), - "language" : MessageLookupByLibrary.simpleMessage("Language"), - "last_refresh_time" : m0, - "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..."), - "login" : MessageLookupByLibrary.simpleMessage("Login"), - "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Login with credentials"), - "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" : MessageLookupByLibrary.simpleMessage("No"), - "no_app" : MessageLookupByLibrary.simpleMessage("No app found to open the file"), - "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"), - "no_classes_on_weekend" : 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("There is no data to show at this time"), - "no_date" : MessageLookupByLibrary.simpleMessage("No date"), - "no_events" : MessageLookupByLibrary.simpleMessage("No events found"), - "no_exams" : MessageLookupByLibrary.simpleMessage("You have no exams scheduled\n"), - "no_exams_label" : MessageLookupByLibrary.simpleMessage("Looks like you are on vacation!"), - "no_favorite_restaurants" : MessageLookupByLibrary.simpleMessage("No favorite restaurants"), - "no_files_found" : MessageLookupByLibrary.simpleMessage("No files found"), - "no_info" : MessageLookupByLibrary.simpleMessage("There is no information to display"), - "no_internet" : MessageLookupByLibrary.simpleMessage("It looks like you\'re offline"), - "no_library_info" : MessageLookupByLibrary.simpleMessage("No library occupation information available"), - "no_link" : MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), - "no_menu_info" : MessageLookupByLibrary.simpleMessage("There is no information available about meals"), - "no_menus" : MessageLookupByLibrary.simpleMessage("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_print_info" : MessageLookupByLibrary.simpleMessage("No print balance information"), - "no_references" : MessageLookupByLibrary.simpleMessage("There are no references to pay"), - "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"), - "no_trips" : MessageLookupByLibrary.simpleMessage("No trips found at the moment"), - "notifications" : MessageLookupByLibrary.simpleMessage("Notifications"), - "occurrence_type" : MessageLookupByLibrary.simpleMessage("Type of occurrence"), - "of_month" : MessageLookupByLibrary.simpleMessage("of"), - "open_error" : MessageLookupByLibrary.simpleMessage("Error opening the file"), - "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"), - "permission_denied" : MessageLookupByLibrary.simpleMessage("Permission denied"), - "personal_assistance" : MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), - "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"), - "program" : MessageLookupByLibrary.simpleMessage("Program"), - "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"), - "report_error" : MessageLookupByLibrary.simpleMessage("Report error"), - "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Report error/suggestion"), - "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Do you want to see your favorite restaurants in the main page?"), - "room" : MessageLookupByLibrary.simpleMessage("Room"), - "school_calendar" : MessageLookupByLibrary.simpleMessage("School Calendar"), - "search" : MessageLookupByLibrary.simpleMessage("Search"), - "semester" : MessageLookupByLibrary.simpleMessage("Semester"), - "send" : MessageLookupByLibrary.simpleMessage("Send"), - "sent_error" : MessageLookupByLibrary.simpleMessage("An error occurred in sending"), - "settings" : MessageLookupByLibrary.simpleMessage("Settings"), - "some_error" : MessageLookupByLibrary.simpleMessage("Some error!"), - "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), - "student_number" : MessageLookupByLibrary.simpleMessage("student number"), - "success" : MessageLookupByLibrary.simpleMessage("Sent with success"), - "successful_open" : MessageLookupByLibrary.simpleMessage("File opened successfully"), - "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"), - "theme" : MessageLookupByLibrary.simpleMessage("Theme"), - "title" : MessageLookupByLibrary.simpleMessage("Title"), - "try_again" : MessageLookupByLibrary.simpleMessage("Try again"), - "try_different_login" : MessageLookupByLibrary.simpleMessage("Problems with login? Try a different login"), - "uc_info" : MessageLookupByLibrary.simpleMessage("Open UC page"), - "unavailable" : MessageLookupByLibrary.simpleMessage("Unavailable"), - "valid_email" : MessageLookupByLibrary.simpleMessage("Please enter a valid email"), - "widget_prompt" : MessageLookupByLibrary.simpleMessage("Choose a widget to add to your personal area:"), - "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Invalid credentials"), - "year" : MessageLookupByLibrary.simpleMessage("Year"), - "yes" : MessageLookupByLibrary.simpleMessage("Yes") - }; + static _notInlinedMessages(_) => { + "about": MessageLookupByLibrary.simpleMessage("About us"), + "academic_services": + MessageLookupByLibrary.simpleMessage("Academic services"), + "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!"), + "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:"), + "banner_info": MessageLookupByLibrary.simpleMessage( + "We do now collect anonymous usage statistics in order to improve your experience. You can change it in settings."), + "bibliography": MessageLookupByLibrary.simpleMessage("Bibliography"), + "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( + "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"), + "change": MessageLookupByLibrary.simpleMessage("Change"), + "change_prompt": MessageLookupByLibrary.simpleMessage( + "Do you want to change the password?"), + "check_internet": MessageLookupByLibrary.simpleMessage( + "Check your internet connection"), + "class_registration": + MessageLookupByLibrary.simpleMessage("Class Registration"), + "collect_usage_stats": + MessageLookupByLibrary.simpleMessage("Collect usage statistics"), + "college": MessageLookupByLibrary.simpleMessage("College: "), + "college_select": + MessageLookupByLibrary.simpleMessage("select your college(s)"), + "conclude": MessageLookupByLibrary.simpleMessage("Done"), + "configured_buses": + MessageLookupByLibrary.simpleMessage("Configured Buses"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), + "confirm_logout": MessageLookupByLibrary.simpleMessage( + "Do you really want to log out? Your local data will be deleted and you will have to log in again."), + "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"), + "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"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Floor -1 of building B (B-142)"), + "download_error": + MessageLookupByLibrary.simpleMessage("Error downloading the file"), + "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"), + "evaluation": MessageLookupByLibrary.simpleMessage("Evaluation"), + "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"), + "fail_to_authenticate": + MessageLookupByLibrary.simpleMessage("Failed to authenticate"), + "failed_login": MessageLookupByLibrary.simpleMessage("Login failed"), + "fee_date": + MessageLookupByLibrary.simpleMessage("Deadline for next fee:"), + "fee_notification": + MessageLookupByLibrary.simpleMessage("Fee deadline"), + "files": MessageLookupByLibrary.simpleMessage("Files"), + "first_year_registration": MessageLookupByLibrary.simpleMessage( + "Year of first registration: "), + "floor": MessageLookupByLibrary.simpleMessage("Floor"), + "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€"), + "internet_status_exception": MessageLookupByLibrary.simpleMessage( + "Check your internet connection"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "keep_login": MessageLookupByLibrary.simpleMessage("Stay signed in"), + "language": MessageLookupByLibrary.simpleMessage("Language"), + "last_refresh_time": m0, + "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..."), + "login": MessageLookupByLibrary.simpleMessage("Login"), + "login_with_credentials": + MessageLookupByLibrary.simpleMessage("Login with credentials"), + "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": MessageLookupByLibrary.simpleMessage("No"), + "no_app": MessageLookupByLibrary.simpleMessage( + "No app found to open the file"), + "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"), + "no_classes_on_weekend": + 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( + "There is no data to show at this time"), + "no_date": MessageLookupByLibrary.simpleMessage("No date"), + "no_events": MessageLookupByLibrary.simpleMessage("No events found"), + "no_exams": MessageLookupByLibrary.simpleMessage( + "You have no exams scheduled\n"), + "no_exams_label": MessageLookupByLibrary.simpleMessage( + "Looks like you are on vacation!"), + "no_favorite_restaurants": + MessageLookupByLibrary.simpleMessage("No favorite restaurants"), + "no_files_found": + MessageLookupByLibrary.simpleMessage("No files found"), + "no_info": MessageLookupByLibrary.simpleMessage( + "There is no information to display"), + "no_internet": MessageLookupByLibrary.simpleMessage( + "It looks like you\'re offline"), + "no_library_info": MessageLookupByLibrary.simpleMessage( + "No library occupation information available"), + "no_link": + MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), + "no_menu_info": MessageLookupByLibrary.simpleMessage( + "There is no information available about meals"), + "no_menus": MessageLookupByLibrary.simpleMessage( + "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_print_info": MessageLookupByLibrary.simpleMessage( + "No print balance information"), + "no_references": MessageLookupByLibrary.simpleMessage( + "There are no references to pay"), + "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"), + "no_trips": MessageLookupByLibrary.simpleMessage( + "No trips found at the moment"), + "notifications": MessageLookupByLibrary.simpleMessage("Notifications"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Type of occurrence"), + "of_month": MessageLookupByLibrary.simpleMessage("of"), + "open_error": + MessageLookupByLibrary.simpleMessage("Error opening the file"), + "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"), + "permission_denied": + MessageLookupByLibrary.simpleMessage("Permission denied"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Face-to-face assistance"), + "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"), + "program": MessageLookupByLibrary.simpleMessage("Program"), + "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"), + "report_error": MessageLookupByLibrary.simpleMessage("Report error"), + "report_error_suggestion": + MessageLookupByLibrary.simpleMessage("Report error/suggestion"), + "restaurant_main_page": MessageLookupByLibrary.simpleMessage( + "Do you want to see your favorite restaurants in the main page?"), + "room": MessageLookupByLibrary.simpleMessage("Room"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("School Calendar"), + "search": MessageLookupByLibrary.simpleMessage("Search"), + "semester": MessageLookupByLibrary.simpleMessage("Semester"), + "send": MessageLookupByLibrary.simpleMessage("Send"), + "sent_error": MessageLookupByLibrary.simpleMessage( + "An error occurred in sending"), + "settings": MessageLookupByLibrary.simpleMessage("Settings"), + "some_error": MessageLookupByLibrary.simpleMessage("Some error!"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Upcoming Trips"), + "student_number": + MessageLookupByLibrary.simpleMessage("student number"), + "success": MessageLookupByLibrary.simpleMessage("Sent with success"), + "successful_open": + MessageLookupByLibrary.simpleMessage("File opened successfully"), + "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"), + "theme": MessageLookupByLibrary.simpleMessage("Theme"), + "title": MessageLookupByLibrary.simpleMessage("Title"), + "try_again": MessageLookupByLibrary.simpleMessage("Try again"), + "try_different_login": MessageLookupByLibrary.simpleMessage( + "Problems with login? Try a different login"), + "uc_info": MessageLookupByLibrary.simpleMessage("Open UC page"), + "unavailable": MessageLookupByLibrary.simpleMessage("Unavailable"), + "valid_email": + MessageLookupByLibrary.simpleMessage("Please enter a valid email"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Choose a widget to add to your personal area:"), + "wrong_credentials_exception": + MessageLookupByLibrary.simpleMessage("Invalid credentials"), + "year": MessageLookupByLibrary.simpleMessage("Year"), + "yes": MessageLookupByLibrary.simpleMessage("Yes") + }; } diff --git a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart index c69b3a76e..502e9f9ec 100644 --- a/packages/uni_app/lib/generated/intl/messages_pt_PT.dart +++ b/packages/uni_app/lib/generated/intl/messages_pt_PT.dart @@ -21,174 +21,286 @@ class MessageLookup extends MessageLookupByLibrary { static m0(time) => "última atualização às ${time}"; - static m1(time) => "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; + static m1(time) => + "${Intl.plural(time, zero: 'Atualizado há ${time} minutos', one: 'Atualizado há ${time} minuto', other: 'Atualizado há ${time} minutos')}"; - static 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', 'percurso_academico': 'Percurso Académico', 'transportes': 'Transportes', 'faculdade': 'Faculdade', 'other': 'Outros', })}"; + static 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', + 'percurso_academico': 'Percurso Académico', + 'transportes': 'Transportes', + 'faculdade': 'Faculdade', + 'other': 'Outros', + })}"; final messages = _notInlinedMessages(_notInlinedMessages); - static _notInlinedMessages(_) => { - "about" : MessageLookupByLibrary.simpleMessage("Sobre nós"), - "academic_services" : MessageLookupByLibrary.simpleMessage("Serviços académicos"), - "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"), - "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"), - "available_amount" : MessageLookupByLibrary.simpleMessage("Valor disponível"), - "average" : MessageLookupByLibrary.simpleMessage("Média: "), - "balance" : MessageLookupByLibrary.simpleMessage("Saldo:"), - "banner_info" : MessageLookupByLibrary.simpleMessage("Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), - "bibliography" : MessageLookupByLibrary.simpleMessage("Bibliografia"), - "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("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"), - "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"), - "collect_usage_stats" : MessageLookupByLibrary.simpleMessage("Partilhar estatísticas de uso"), - "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"), - "confirm" : MessageLookupByLibrary.simpleMessage("Confirmar"), - "confirm_logout" : MessageLookupByLibrary.simpleMessage("Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), - "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"), - "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"), - "dona_bia" : MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), - "dona_bia_building" : MessageLookupByLibrary.simpleMessage("Piso -1 do edifício B (B-142)"), - "download_error" : MessageLookupByLibrary.simpleMessage("Erro ao descarregar o ficheiro"), - "ects" : MessageLookupByLibrary.simpleMessage("ECTS realizados: "), - "edit_off" : MessageLookupByLibrary.simpleMessage("Editar"), - "edit_on" : MessageLookupByLibrary.simpleMessage("Concluir edição"), - "empty_text" : MessageLookupByLibrary.simpleMessage("Por favor preenche este campo"), - "evaluation" : MessageLookupByLibrary.simpleMessage("Avaliação"), - "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"), - "fail_to_authenticate" : MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), - "failed_login" : MessageLookupByLibrary.simpleMessage("O login falhou"), - "fee_date" : MessageLookupByLibrary.simpleMessage("Data limite próxima prestação:"), - "fee_notification" : MessageLookupByLibrary.simpleMessage("Data limite de propina"), - "files" : MessageLookupByLibrary.simpleMessage("Ficheiros"), - "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€"), - "internet_status_exception" : MessageLookupByLibrary.simpleMessage("Verifique sua conexão com a internet"), - "invalid_credentials" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "keep_login" : MessageLookupByLibrary.simpleMessage("Manter sessão"), - "language" : MessageLookupByLibrary.simpleMessage("Idioma"), - "last_refresh_time" : m0, - "last_timestamp" : m1, - "library_occupation" : MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), - "load_error" : MessageLookupByLibrary.simpleMessage("Erro ao carregar a informação"), - "loading_terms" : MessageLookupByLibrary.simpleMessage("Carregando os Termos e Condições..."), - "login" : MessageLookupByLibrary.simpleMessage("Entrar"), - "login_with_credentials" : MessageLookupByLibrary.simpleMessage("Iniciar sessão com credenciais"), - "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" : MessageLookupByLibrary.simpleMessage("Não"), - "no_app" : MessageLookupByLibrary.simpleMessage("Nenhuma aplicação encontrada para abrir o ficheiro"), - "no_bus" : MessageLookupByLibrary.simpleMessage("Não percas nenhum autocarro!"), - "no_bus_stops" : MessageLookupByLibrary.simpleMessage("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"), - "no_classes_on" : MessageLookupByLibrary.simpleMessage("Não possui aulas à"), - "no_classes_on_weekend" : MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), - "no_college" : MessageLookupByLibrary.simpleMessage("sem faculdade"), - "no_course_units" : MessageLookupByLibrary.simpleMessage("Sem cadeiras no período selecionado"), - "no_data" : MessageLookupByLibrary.simpleMessage("Não há dados a mostrar neste momento"), - "no_date" : MessageLookupByLibrary.simpleMessage("Sem data"), - "no_events" : MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), - "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_files_found" : MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), - "no_info" : MessageLookupByLibrary.simpleMessage("Não existem informações para apresentar"), - "no_internet" : MessageLookupByLibrary.simpleMessage("Parece que estás offline"), - "no_library_info" : MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), - "no_link" : MessageLookupByLibrary.simpleMessage("Não conseguimos abrir o link"), - "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_name_course" : MessageLookupByLibrary.simpleMessage("Curso sem nome"), - "no_places_info" : MessageLookupByLibrary.simpleMessage("Não há informação disponível sobre locais"), - "no_print_info" : MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), - "no_references" : MessageLookupByLibrary.simpleMessage("Não existem referências a pagar"), - "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"), - "no_trips" : MessageLookupByLibrary.simpleMessage("Não há viagens planeadas de momento"), - "notifications" : MessageLookupByLibrary.simpleMessage("Notificações"), - "occurrence_type" : MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), - "of_month" : MessageLookupByLibrary.simpleMessage("de"), - "open_error" : MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), - "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"), - "permission_denied" : MessageLookupByLibrary.simpleMessage("Sem permissão"), - "personal_assistance" : MessageLookupByLibrary.simpleMessage("Atendimento presencial"), - "press_again" : MessageLookupByLibrary.simpleMessage("Pressione novamente para sair"), - "print" : MessageLookupByLibrary.simpleMessage("Impressão"), - "prints" : MessageLookupByLibrary.simpleMessage("Impressões"), - "problem_id" : MessageLookupByLibrary.simpleMessage("Breve identificação do problema"), - "program" : MessageLookupByLibrary.simpleMessage("Programa"), - "reference_sigarra_help" : MessageLookupByLibrary.simpleMessage("Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), - "reference_success" : MessageLookupByLibrary.simpleMessage("Referência criada com sucesso!"), - "remove" : MessageLookupByLibrary.simpleMessage("Remover"), - "report_error" : MessageLookupByLibrary.simpleMessage("Reportar erro"), - "report_error_suggestion" : MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), - "restaurant_main_page" : MessageLookupByLibrary.simpleMessage("Queres ver os teus restaurantes favoritos na página principal?"), - "room" : MessageLookupByLibrary.simpleMessage("Sala"), - "school_calendar" : MessageLookupByLibrary.simpleMessage("Calendário Escolar"), - "search" : MessageLookupByLibrary.simpleMessage("Pesquisar"), - "semester" : MessageLookupByLibrary.simpleMessage("Semestre"), - "send" : MessageLookupByLibrary.simpleMessage("Enviar"), - "sent_error" : MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), - "settings" : MessageLookupByLibrary.simpleMessage("Definições"), - "some_error" : MessageLookupByLibrary.simpleMessage("Algum erro!"), - "stcp_stops" : MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), - "student_number" : MessageLookupByLibrary.simpleMessage("número de estudante"), - "success" : MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), - "successful_open" : MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), - "theme" : MessageLookupByLibrary.simpleMessage("Tema"), - "title" : MessageLookupByLibrary.simpleMessage("Título"), - "try_again" : MessageLookupByLibrary.simpleMessage("Tentar de novo"), - "try_different_login" : MessageLookupByLibrary.simpleMessage("Problemas a iniciar sessão? Experimenta o login alternativo"), - "uc_info" : MessageLookupByLibrary.simpleMessage("Abrir página da UC"), - "unavailable" : MessageLookupByLibrary.simpleMessage("Indisponível"), - "valid_email" : MessageLookupByLibrary.simpleMessage("Por favor insere um email válido"), - "widget_prompt" : MessageLookupByLibrary.simpleMessage("Escolhe um widget para adicionares à tua área pessoal:"), - "wrong_credentials_exception" : MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), - "year" : MessageLookupByLibrary.simpleMessage("Ano"), - "yes" : MessageLookupByLibrary.simpleMessage("Sim") - }; + static _notInlinedMessages(_) => { + "about": MessageLookupByLibrary.simpleMessage("Sobre nós"), + "academic_services": + MessageLookupByLibrary.simpleMessage("Serviços académicos"), + "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"), + "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"), + "available_amount": + MessageLookupByLibrary.simpleMessage("Valor disponível"), + "average": MessageLookupByLibrary.simpleMessage("Média: "), + "balance": MessageLookupByLibrary.simpleMessage("Saldo:"), + "banner_info": MessageLookupByLibrary.simpleMessage( + "Agora recolhemos estatísticas de uso anónimas para melhorar a tua experiência. Podes alterá-lo nas definições."), + "bibliography": MessageLookupByLibrary.simpleMessage("Bibliografia"), + "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( + "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"), + "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"), + "collect_usage_stats": MessageLookupByLibrary.simpleMessage( + "Partilhar estatísticas de uso"), + "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"), + "confirm": MessageLookupByLibrary.simpleMessage("Confirmar"), + "confirm_logout": MessageLookupByLibrary.simpleMessage( + "Tens a certeza de que queres terminar sessão? Os teus dados locais serão apagados e terás de iniciar sessão novamente."), + "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"), + "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"), + "dona_bia": + MessageLookupByLibrary.simpleMessage("Papelaria D. Beatriz"), + "dona_bia_building": MessageLookupByLibrary.simpleMessage( + "Piso -1 do edifício B (B-142)"), + "download_error": MessageLookupByLibrary.simpleMessage( + "Erro ao descarregar o ficheiro"), + "ects": MessageLookupByLibrary.simpleMessage("ECTS realizados: "), + "edit_off": MessageLookupByLibrary.simpleMessage("Editar"), + "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), + "empty_text": MessageLookupByLibrary.simpleMessage( + "Por favor preenche este campo"), + "evaluation": MessageLookupByLibrary.simpleMessage("Avaliação"), + "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"), + "fail_to_authenticate": + MessageLookupByLibrary.simpleMessage("Falha ao autenticar"), + "failed_login": MessageLookupByLibrary.simpleMessage("O login falhou"), + "fee_date": MessageLookupByLibrary.simpleMessage( + "Data limite próxima prestação:"), + "fee_notification": + MessageLookupByLibrary.simpleMessage("Data limite de propina"), + "files": MessageLookupByLibrary.simpleMessage("Ficheiros"), + "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€"), + "internet_status_exception": MessageLookupByLibrary.simpleMessage( + "Verifique sua conexão com a internet"), + "invalid_credentials": + MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "keep_login": MessageLookupByLibrary.simpleMessage("Manter sessão"), + "language": MessageLookupByLibrary.simpleMessage("Idioma"), + "last_refresh_time": m0, + "last_timestamp": m1, + "library_occupation": + MessageLookupByLibrary.simpleMessage("Ocupação da Biblioteca"), + "load_error": MessageLookupByLibrary.simpleMessage( + "Erro ao carregar a informação"), + "loading_terms": MessageLookupByLibrary.simpleMessage( + "Carregando os Termos e Condições..."), + "login": MessageLookupByLibrary.simpleMessage("Entrar"), + "login_with_credentials": MessageLookupByLibrary.simpleMessage( + "Iniciar sessão com credenciais"), + "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": MessageLookupByLibrary.simpleMessage("Não"), + "no_app": MessageLookupByLibrary.simpleMessage( + "Nenhuma aplicação encontrada para abrir o ficheiro"), + "no_bus": MessageLookupByLibrary.simpleMessage( + "Não percas nenhum autocarro!"), + "no_bus_stops": MessageLookupByLibrary.simpleMessage( + "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"), + "no_classes_on": + MessageLookupByLibrary.simpleMessage("Não possui aulas à"), + "no_classes_on_weekend": + MessageLookupByLibrary.simpleMessage("Não possui aulas ao"), + "no_college": MessageLookupByLibrary.simpleMessage("sem faculdade"), + "no_course_units": MessageLookupByLibrary.simpleMessage( + "Sem cadeiras no período selecionado"), + "no_data": MessageLookupByLibrary.simpleMessage( + "Não há dados a mostrar neste momento"), + "no_date": MessageLookupByLibrary.simpleMessage("Sem data"), + "no_events": + MessageLookupByLibrary.simpleMessage("Nenhum evento encontrado"), + "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_files_found": + MessageLookupByLibrary.simpleMessage("Nenhum ficheiro encontrado"), + "no_info": MessageLookupByLibrary.simpleMessage( + "Não existem informações para apresentar"), + "no_internet": + MessageLookupByLibrary.simpleMessage("Parece que estás offline"), + "no_library_info": + MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), + "no_link": MessageLookupByLibrary.simpleMessage( + "Não conseguimos abrir o link"), + "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_name_course": + MessageLookupByLibrary.simpleMessage("Curso sem nome"), + "no_places_info": MessageLookupByLibrary.simpleMessage( + "Não há informação disponível sobre locais"), + "no_print_info": + MessageLookupByLibrary.simpleMessage("Sem informação de saldo"), + "no_references": MessageLookupByLibrary.simpleMessage( + "Não existem referências a pagar"), + "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"), + "no_trips": MessageLookupByLibrary.simpleMessage( + "Não há viagens planeadas de momento"), + "notifications": MessageLookupByLibrary.simpleMessage("Notificações"), + "occurrence_type": + MessageLookupByLibrary.simpleMessage("Tipo de ocorrência"), + "of_month": MessageLookupByLibrary.simpleMessage("de"), + "open_error": + MessageLookupByLibrary.simpleMessage("Erro ao abrir o ficheiro"), + "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"), + "permission_denied": + MessageLookupByLibrary.simpleMessage("Sem permissão"), + "personal_assistance": + MessageLookupByLibrary.simpleMessage("Atendimento presencial"), + "press_again": MessageLookupByLibrary.simpleMessage( + "Pressione novamente para sair"), + "print": MessageLookupByLibrary.simpleMessage("Impressão"), + "prints": MessageLookupByLibrary.simpleMessage("Impressões"), + "problem_id": MessageLookupByLibrary.simpleMessage( + "Breve identificação do problema"), + "program": MessageLookupByLibrary.simpleMessage("Programa"), + "reference_sigarra_help": MessageLookupByLibrary.simpleMessage( + "Os dados da referência gerada aparecerão no Sigarra, conta corrente. Perfil > Conta Corrente"), + "reference_success": MessageLookupByLibrary.simpleMessage( + "Referência criada com sucesso!"), + "remove": MessageLookupByLibrary.simpleMessage("Remover"), + "report_error": MessageLookupByLibrary.simpleMessage("Reportar erro"), + "report_error_suggestion": + MessageLookupByLibrary.simpleMessage("Reportar erro/sugestão"), + "restaurant_main_page": MessageLookupByLibrary.simpleMessage( + "Queres ver os teus restaurantes favoritos na página principal?"), + "room": MessageLookupByLibrary.simpleMessage("Sala"), + "school_calendar": + MessageLookupByLibrary.simpleMessage("Calendário Escolar"), + "search": MessageLookupByLibrary.simpleMessage("Pesquisar"), + "semester": MessageLookupByLibrary.simpleMessage("Semestre"), + "send": MessageLookupByLibrary.simpleMessage("Enviar"), + "sent_error": + MessageLookupByLibrary.simpleMessage("Ocorreu um erro no envio"), + "settings": MessageLookupByLibrary.simpleMessage("Definições"), + "some_error": MessageLookupByLibrary.simpleMessage("Algum erro!"), + "stcp_stops": + MessageLookupByLibrary.simpleMessage("STCP - Próximas Viagens"), + "student_number": + MessageLookupByLibrary.simpleMessage("número de estudante"), + "success": MessageLookupByLibrary.simpleMessage("Enviado com sucesso"), + "successful_open": + MessageLookupByLibrary.simpleMessage("Ficheiro aberto 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"), + "theme": MessageLookupByLibrary.simpleMessage("Tema"), + "title": MessageLookupByLibrary.simpleMessage("Título"), + "try_again": MessageLookupByLibrary.simpleMessage("Tentar de novo"), + "try_different_login": MessageLookupByLibrary.simpleMessage( + "Problemas a iniciar sessão? Experimenta o login alternativo"), + "uc_info": MessageLookupByLibrary.simpleMessage("Abrir página da UC"), + "unavailable": MessageLookupByLibrary.simpleMessage("Indisponível"), + "valid_email": MessageLookupByLibrary.simpleMessage( + "Por favor insere um email válido"), + "widget_prompt": MessageLookupByLibrary.simpleMessage( + "Escolhe um widget para adicionares à tua área pessoal:"), + "wrong_credentials_exception": + MessageLookupByLibrary.simpleMessage("Credenciais inválidas"), + "year": MessageLookupByLibrary.simpleMessage("Ano"), + "yes": MessageLookupByLibrary.simpleMessage("Sim") + }; } diff --git a/packages/uni_app/lib/generated/l10n.dart b/packages/uni_app/lib/generated/l10n.dart index ffce269e6..4201d66c1 100644 --- a/packages/uni_app/lib/generated/l10n.dart +++ b/packages/uni_app/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!; } @@ -1721,4 +1724,4 @@ class AppLocalizationDelegate extends LocalizationsDelegate { } return false; } -} \ No newline at end of file +} From 9acce2d61a3f52345cac902e674fe29d3d19e2ed Mon Sep 17 00:00:00 2001 From: DGoiana Date: Thu, 26 Sep 2024 15:26:48 +0100 Subject: [PATCH 95/99] abstracting code to the generic theme --- .../view/bus_stop_selection/widgets/bus_stop_search.dart | 7 ------- packages/uni_app/lib/view/theme.dart | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart b/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart index 967d9a632..8c1b03b79 100644 --- a/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart +++ b/packages/uni_app/lib/view/bus_stop_selection/widgets/bus_stop_search.dart @@ -38,13 +38,6 @@ class BusStopSearch extends SearchDelegate { ]; } - @override - ThemeData appBarTheme(BuildContext context) { - return Theme.of(context).copyWith( - scaffoldBackgroundColor: Theme.of(context).colorScheme.surface, - ); - } - @override Widget buildLeading(BuildContext context) { // Back arrow to go back to menu diff --git a/packages/uni_app/lib/view/theme.dart b/packages/uni_app/lib/view/theme.dart index 33ded9772..62c7e4435 100644 --- a/packages/uni_app/lib/view/theme.dart +++ b/packages/uni_app/lib/view/theme.dart @@ -39,6 +39,7 @@ ThemeData applicationLightTheme = ThemeData( onTertiary: Colors.black, ), primaryColor: darkRed, + scaffoldBackgroundColor: _mildWhite, cardColor: Colors.white, dividerColor: _lightGrey, hintColor: _lightGrey, @@ -68,6 +69,7 @@ ThemeData applicationDarkTheme = ThemeData( primaryColor: _lightGrey, cardColor: _mildBlack, dividerColor: _strongGrey, + scaffoldBackgroundColor: _darkBlack, hintColor: _darkishBlack, indicatorColor: _lightGrey, primaryTextTheme: Typography().white, From 139723e607295980738e1515eb90108853c9aadf Mon Sep 17 00:00:00 2001 From: rubuy-74 Date: Fri, 27 Sep 2024 12:14:52 +0000 Subject: [PATCH 96/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index aa31bb552..92ceb6772 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.11+310 +1.10.0-beta.12+311 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 8a809f3db..02f999cfc 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.11+310 +version: 1.10.0-beta.12+311 environment: sdk: ">=3.4.0 <4.0.0" From a3fa5d305b6e5aadc4c7fd2db475e6726898cd2c Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 27 Sep 2024 14:36:56 +0100 Subject: [PATCH 97/99] changing padding of af login button --- packages/uni_app/lib/view/login/widgets/inputs.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/uni_app/lib/view/login/widgets/inputs.dart b/packages/uni_app/lib/view/login/widgets/inputs.dart index 253df62f5..258315b70 100644 --- a/packages/uni_app/lib/view/login/widgets/inputs.dart +++ b/packages/uni_app/lib/view/login/widgets/inputs.dart @@ -91,6 +91,7 @@ Widget createAFLogInButton( ) { return ElevatedButton( style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(7), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25), ), From 88816ea3b71b280093f08454fd7010015b3fe987 Mon Sep 17 00:00:00 2001 From: DGoiana Date: Fri, 27 Sep 2024 13:38:11 +0000 Subject: [PATCH 98/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 92ceb6772..8ec73af6c 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.12+311 +1.10.0-beta.13+312 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 02f999cfc..4d3a49de7 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.12+311 +version: 1.10.0-beta.13+312 environment: sdk: ">=3.4.0 <4.0.0" From d3b03239e54ccc9d900b2e551fd8510373e651b5 Mon Sep 17 00:00:00 2001 From: niaefeup-admin Date: Sun, 29 Sep 2024 10:57:07 +0000 Subject: [PATCH 99/99] Bump app version [no ci] --- packages/uni_app/app_version.txt | 2 +- packages/uni_app/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/uni_app/app_version.txt b/packages/uni_app/app_version.txt index 8ec73af6c..3a7dd4f5f 100644 --- a/packages/uni_app/app_version.txt +++ b/packages/uni_app/app_version.txt @@ -1 +1 @@ -1.10.0-beta.13+312 +1.10.0-beta.14+314 diff --git a/packages/uni_app/pubspec.yaml b/packages/uni_app/pubspec.yaml index 4d3a49de7..b1ac16565 100644 --- a/packages/uni_app/pubspec.yaml +++ b/packages/uni_app/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.10.0-beta.13+312 +version: 1.10.0-beta.14+314 environment: sdk: ">=3.4.0 <4.0.0"