diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index d12932f32..369500799 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -35,6 +35,7 @@ class MessageLookup extends MessageLookupByLibrary { 'restaurantes': 'Restaurants', 'calendario': 'Calendar', 'biblioteca': 'Library', + 'percurso_academico': 'Academic Path', 'uteis': 'Utils', 'other': 'Other', })}"; diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index ecc041c37..fb6a1bcb6 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -35,6 +35,7 @@ class MessageLookup extends MessageLookupByLibrary { 'restaurantes': 'Restaurantes', 'calendario': 'Calendário', 'biblioteca': 'Biblioteca', + 'percurso_academico': 'Percurso Académico', 'uteis': 'Úteis', 'other': 'Outros', })}"; diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 86f8fe8bc..c61bd64be 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -166,7 +166,7 @@ "@min_value_reference": {}, "multimedia_center": "Multimedia center", "@multimedia_center": {}, - "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} uteis{Utils} other{Other}}", + "nav_title": "{title, select, horario{Schedule} exames{Exams} area{Personal Area} cadeiras{Course Units} autocarros{Buses} locais{Places} restaurantes{Restaurants} calendario{Calendar} biblioteca{Library} percurso_academico{Academic Path} uteis{Utils} other{Other}}", "@nav_title": {}, "news": "News", "@news": {}, diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index b674d046f..0dc766131 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -166,7 +166,7 @@ "@min_value_reference": {}, "multimedia_center": "Centro de multimédia", "@multimedia_center": {}, - "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} uteis{Úteis} other{Outros}}", + "nav_title": "{title, select, horario{Horário} exames{Exames} area{Área Pessoal} cadeiras{Cadeiras} autocarros{Autocarros} locais{Locais} restaurantes{Restaurantes} calendario{Calendário} biblioteca{Biblioteca} percurso_academico{Percurso Académico} uteis{Úteis} other{Outros}}", "@nav_title": {}, "news": "Notícias", "@news": {}, diff --git a/uni/lib/main.dart b/uni/lib/main.dart index 1dcbdcdc6..734b2c102 100644 --- a/uni/lib/main.dart +++ b/uni/lib/main.dart @@ -29,6 +29,7 @@ import 'package:uni/model/providers/startup/profile_provider.dart'; import 'package:uni/model/providers/startup/session_provider.dart'; import 'package:uni/model/providers/state_providers.dart'; import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/academic_path/academic_path.dart'; import 'package:uni/view/bus_stop_next_arrivals/bus_stop_next_arrivals.dart'; import 'package:uni/view/calendar/calendar.dart'; import 'package:uni/view/common_widgets/page_transition.dart'; @@ -273,6 +274,11 @@ class ApplicationState extends State { page: const UsefulInfoPageView(), settings: settings, ), + '/${DrawerItem.navAcademicPath.title}': + PageTransition.makePageTransition( + page: const AcademicPathPageView(), + settings: settings, + ), }; return transitions[settings.name]; }, diff --git a/uni/lib/utils/drawer_items.dart b/uni/lib/utils/drawer_items.dart index 09d1e6f7d..52c4e8634 100644 --- a/uni/lib/utils/drawer_items.dart +++ b/uni/lib/utils/drawer_items.dart @@ -8,7 +8,8 @@ enum DrawerItem { navRestaurants('restaurantes'), navCalendar('calendario'), navLibrary('biblioteca', faculties: {'feup'}), - navUsefulInfo('uteis', faculties: {'feup'}); + navUsefulInfo('uteis', faculties: {'feup'}), + navAcademicPath('percurso_academico'); const DrawerItem(this.title, {this.faculties}); diff --git a/uni/lib/view/academic_path/academic_path.dart b/uni/lib/view/academic_path/academic_path.dart new file mode 100644 index 000000000..e06ef1d65 --- /dev/null +++ b/uni/lib/view/academic_path/academic_path.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/academic_path/widgets/course_units_card.dart'; +import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:uni/view/common_widgets/page_title.dart'; +import 'package:uni/view/common_widgets/pages_layouts/general/general.dart'; +import 'package:uni/view/home/widgets/exam_card.dart'; +import 'package:uni/view/home/widgets/schedule_card.dart'; + +class AcademicPathPageView extends StatefulWidget { + const AcademicPathPageView({super.key}); + + @override + State createState() => AcademicPathPageViewState(); +} + +class AcademicPathPageViewState extends GeneralPageViewState { + List academicPathCards = [ + ScheduleCard(), + ExamCard(), + CourseUnitsCard(), + // Add more cards if needed + ]; + + @override + Widget getBody(BuildContext context) { + return ListView( + children: [ + PageTitle( + name: S.of(context).nav_title(DrawerItem.navAcademicPath.title), + ), + Column( + children: academicPathCards, + ), + ], + ); + } + + @override + Future onRefresh(BuildContext context) async { + for (final card in academicPathCards) { + card.onRefresh(context); + } + } +} diff --git a/uni/lib/view/academic_path/widgets/course_units_card.dart b/uni/lib/view/academic_path/widgets/course_units_card.dart new file mode 100644 index 000000000..e2553b683 --- /dev/null +++ b/uni/lib/view/academic_path/widgets/course_units_card.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/model/entities/course_units/course_unit.dart'; +import 'package:uni/model/entities/profile.dart'; +import 'package:uni/model/providers/startup/profile_provider.dart'; +import 'package:uni/utils/drawer_items.dart'; +import 'package:uni/view/common_widgets/generic_card.dart'; +import 'package:uni/view/course_units/widgets/course_unit_card.dart'; +import 'package:uni/view/lazy_consumer.dart'; + +class CourseUnitsCard extends GenericCard { + CourseUnitsCard({super.key}); + + @override + void onRefresh(BuildContext context) { + Provider.of(context, listen: false).forceRefresh(context); + } + + @override + Widget buildCardContent(BuildContext context) { + return LazyConsumer( + builder: (context, profile) { + final courseUnits = profile.courseUnits + .where( + (courseUnit) => + courseUnit.enrollmentIsValid() && courseUnit.grade == '', + ) + .take(5) + .toList(); + return _generateCourseUnitsCards(courseUnits, context); + }, + hasContent: (Profile profile) => profile.courseUnits.isNotEmpty, + onNullContent: Center( + heightFactor: 10, + child: Text( + S.of(context).no_course_units, + style: Theme.of(context).textTheme.titleLarge, + ), + ), + ); + } + + Widget _generateCourseUnitsCards( + List courseUnits, + BuildContext context, + ) { + if (courseUnits.isEmpty) { + return Center( + heightFactor: 3, + child: Text( + S.of(context).no_course_units, + style: Theme.of(context).textTheme.titleLarge, + ), + ); + } + + return Column( + children: courseUnits + .map( + (courseUnit) => Column( + children: [ + Padding( + padding: const EdgeInsets.all(5), + child: CourseUnitCard(courseUnit), + ), + ], + ), + ) + .toList(), + ); + } + + @override + String getTitle(BuildContext context) => + S.of(context).nav_title(DrawerItem.navCourseUnits.title); + + @override + Future onClick(BuildContext context) => + Navigator.pushNamed(context, '/${DrawerItem.navCourseUnits.title}'); +}