From 1ebbced93265fd583b1d98310808be5fa514910a Mon Sep 17 00:00:00 2001 From: thePeras Date: Sun, 3 Nov 2024 09:42:01 +0000 Subject: [PATCH] Academyc page tabs and exams timeline --- .../lib/view/academic_path/academic_path.dart | 45 ++++-- .../lib/view/academic_path/exam_page.dart | 144 ++++++++++++++++++ 2 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 packages/uni_app/lib/view/academic_path/exam_page.dart diff --git a/packages/uni_app/lib/view/academic_path/academic_path.dart b/packages/uni_app/lib/view/academic_path/academic_path.dart index 243b6aa08..e4e69c7be 100644 --- a/packages/uni_app/lib/view/academic_path/academic_path.dart +++ b/packages/uni_app/lib/view/academic_path/academic_path.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; import 'package:uni/generated/l10n.dart'; import 'package:uni/utils/navigation_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/academic_path/exam_page.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}); @@ -15,28 +12,44 @@ class AcademicPathPageView extends StatefulWidget { } class AcademicPathPageViewState extends GeneralPageViewState { - List academicPathCards = [ - ScheduleCard(), - ExamCard(), - CourseUnitsCard(), - // Add more cards if needed - ]; - @override String? getTitle() => S.of(context).nav_title(NavigationItem.navAcademicPath.route); @override Widget getBody(BuildContext context) { - return ListView( - children: academicPathCards, + return DefaultTabController( + length: 3, + child: Scaffold( + appBar: AppBar( + title: Text( + S.of(context).nav_title(NavigationItem.navAcademicPath.route), + ), + bottom: const TabBar( + tabs: [ + Tab(text: 'Schedule'), + Tab(text: 'Exams'), + Tab(text: 'Courses'), + ], + ), + ), + body: const TabBarView( + children: [ + Center( + child: Text('To be implemented'), + ), + ExamsPage(), + Center( + child: Text('To be implemented'), + ), + ], + ), + ), ); } @override Future onRefresh(BuildContext context) async { - for (final card in academicPathCards) { - card.onRefresh(context); - } + // TODO: implement onRefresh } } diff --git a/packages/uni_app/lib/view/academic_path/exam_page.dart b/packages/uni_app/lib/view/academic_path/exam_page.dart new file mode 100644 index 000000000..7d541697a --- /dev/null +++ b/packages/uni_app/lib/view/academic_path/exam_page.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:uni/controller/local_storage/preferences_controller.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/model/entities/exam.dart'; +import 'package:uni/model/providers/lazy/exam_provider.dart'; +import 'package:uni/view/common_widgets/expanded_image_label.dart'; +import 'package:uni/view/lazy_consumer.dart'; +import 'package:uni_ui/cards/exam_card.dart'; +import 'package:uni_ui/timeline/timeline.dart'; + +class ExamsPage extends StatefulWidget { + const ExamsPage({super.key}); + + @override + State createState() => _ExamsPageState(); +} + +class _ExamsPageState extends State { + List hiddenExams = PreferencesController.getHiddenExams(); + Map filteredExamTypes = + PreferencesController.getFilteredExams(); + + @override + Widget build(BuildContext context) { + const months = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + /* + If we want to filters exams again + filteredExamTypes[Exam.getExamTypeLong(exam.examType)] ?? + */ + + return LazyConsumer>( + builder: (context, exams) => Timeline( + tabs: _examsByMonth(exams) + .keys + .map( + (key) => Column( + children: [ + Text(months[int.parse(key.split('-')[1]) - 1]), + Text(key.split('-')[1]), + ], + ), + ) + .toList(), + content: _examsByMonth(exams) + .entries + .map( + (entry) => ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: entry.value.length, + prototypeItem: const ExamCard( + //TODO(thePeras): Solve this at parser level + name: 'Computer Laboratory', + acronym: 'LCOM', + rooms: ['B315', 'B224', 'B207'], + type: 'MT', + startTime: '12:00', + ), + itemBuilder: (context, index) { + final exam = entry.value[index]; + return ExamCard( + name: 'Subject Name', + acronym: exam.subject, + //TODO(thePeras): Solve this at parser level + rooms: exam.rooms.where((room) => room.isNotEmpty).toList(), + type: exam.examType, + startTime: exam.formatTime(exam.start), + isInvisible: hiddenExams.contains(exam.id), + iconAction: () { + setState(() { + if (hiddenExams.contains(exam.id)) { + hiddenExams.remove(exam.id); + } else { + hiddenExams.add(exam.id); + } + + setState(() { + PreferencesController.saveHiddenExams( + hiddenExams, + ); + }); + }); + }, + ); + }, + ), + ) + .toList(), + ), + hasContent: (exams) => exams.isNotEmpty, + onNullContent: Center( + heightFactor: 1.2, + child: ImageLabel( + imagePath: 'assets/images/vacation.png', + label: S.of(context).no_exams_label, + labelTextStyle: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + color: Theme.of(context).colorScheme.primary, + ), + sublabel: S.of(context).no_exams, + sublabelTextStyle: const TextStyle(fontSize: 15), + ), + ), + ); + } + + Map> _examsByMonth(List exams) { + final months = >{}; + for (final exam in exams) { + final month = '${exam.start.year}-${exam.start.month}'; + months.putIfAbsent(month, () => []).add(exam); + } + return months; + } + + /* + @override + Widget? getTopRightButton(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: ExamFilterButton( + () => setState(() { + filteredExamTypes = PreferencesController.getFilteredExams(); + }), + ), + ); + } + */ +}