From e652ab6e59eb067b8aaf639d28c6f3a563bc47ec Mon Sep 17 00:00:00 2001 From: nohack Date: Thu, 13 Jun 2024 22:07:08 +0800 Subject: [PATCH 1/2] Add filtering to courses --- lib/src/common/services/constants.dart | 1 + lib/src/common/services/moodle_extra.dart | 3 ++ lib/src/common/services/moodle_managers.dart | 33 ++++++++++++++++++ lib/src/common/services/settings.dart | 1 + lib/src/routes/courses/courses.dart | 34 +++++++++++++++++++ .../routes/courses/courses_collection.dart | 2 ++ pubspec.lock | 24 ++++++------- 7 files changed, 86 insertions(+), 12 deletions(-) diff --git a/lib/src/common/services/constants.dart b/lib/src/common/services/constants.dart index cf23b3d..127eae1 100644 --- a/lib/src/common/services/constants.dart +++ b/lib/src/common/services/constants.dart @@ -36,6 +36,7 @@ class Constants { static const kMoodleUrlOpenLoading = 'Launching Moodle website...'; static const kMorePanelGrouping = 'Group By'; static const kMorePanelSorting = 'Sort By'; + static const kMorePanelFiltering = 'Filter By'; static const kMorePanelSync = 'Sync With Moodle'; static const kMorePanelAddEvent = 'Add Custom Event'; static const kAddReminder = 'Add Reminder'; diff --git a/lib/src/common/services/moodle_extra.dart b/lib/src/common/services/moodle_extra.dart index d5af713..1d442d6 100644 --- a/lib/src/common/services/moodle_extra.dart +++ b/lib/src/common/services/moodle_extra.dart @@ -12,6 +12,9 @@ enum MoodleEventGroupingType { byTime, byCourse, none } /// Moodle courses sorting type. enum MoodleCourseSortingType { byCourseCode, byLastAccessed } +/// Moodle courses filtering type. +enum MoodleCourseFilteringType { none, byLatestSemester } + /// Moodle storage keys. class MoodleStorageKeys { static const wstoken = 'moodle_wstoken'; diff --git a/lib/src/common/services/moodle_managers.dart b/lib/src/common/services/moodle_managers.dart index 79898f6..322a253 100644 --- a/lib/src/common/services/moodle_managers.dart +++ b/lib/src/common/services/moodle_managers.dart @@ -61,6 +61,7 @@ class MoodleCourseManager with ChangeNotifier { /// Sorted courses given a sorting type. List sortedCourses( {MoodleCourseSortingType sortBy = MoodleCourseSortingType.byCourseCode, + MoodleCourseFilteringType filterBy = MoodleCourseFilteringType.none, bool showFavoriteOnly = false}) { late List sortedCourses; if (_sortedCoursesCache[sortBy] != null) { @@ -84,7 +85,39 @@ class MoodleCourseManager with ChangeNotifier { if (showFavoriteOnly) { sortedCourses = sortedCourses.where((c) => c.customFavorite ?? false).toList(); + } else if (filterBy == MoodleCourseFilteringType.byLatestSemester) { + int? latestYear, latestSemester; + Map> coursesYearAndSemester = {}; + + for (final course in sortedCourses) { + var groups = + RegExp(r'^(.*)_(\w{0,3})_(\d{4})$').firstMatch(course.idnumber); + final sem = int.tryParse(groups?.group(2)?[0] ?? "0"); + final year = int.tryParse(groups?.group(3) ?? "0"); + + if (year != null && sem != null) { + coursesYearAndSemester[course.id] = [year, sem]; + + if (latestYear == null || year > latestYear) { + latestYear = year; + latestSemester = sem; + } else if (year == latestYear && sem > latestSemester!) { + latestSemester = sem; + } + } + } + + // TODO should this be cached ? + if (latestYear != null) { + sortedCourses = sortedCourses + .where((c) => + coursesYearAndSemester.containsKey(c.id) && + coursesYearAndSemester[c.id]!.first == latestYear && + coursesYearAndSemester[c.id]!.last == latestSemester) + .toList(); + } } + return sortedCourses; } diff --git a/lib/src/common/services/settings.dart b/lib/src/common/services/settings.dart index 7ec3463..545a53a 100644 --- a/lib/src/common/services/settings.dart +++ b/lib/src/common/services/settings.dart @@ -13,6 +13,7 @@ class SettingsKey { static const String deadlineDisplay = 'settings_deadline_display'; static const String eventGroupingType = 'settings_event_grouping'; static const String courseSortingType = 'settings_course_sorting'; + static const String courseFilteringType = 'settings_course_filtering'; static const String onlyShowResourcesInCourses = 'settings_only_show_resources'; static const String showFavoriteCoursesByDefault = diff --git a/lib/src/routes/courses/courses.dart b/lib/src/routes/courses/courses.dart index 0053d52..c1d1de6 100644 --- a/lib/src/routes/courses/courses.dart +++ b/lib/src/routes/courses/courses.dart @@ -84,6 +84,40 @@ class _CoursesPageState extends State { ), ), ), + if (!_showFavorite) + MorePanelElement( + title: Constants.kMorePanelFiltering, + icon: const Icon(Icons.filter_alt_outlined), + extendedView: Padding( + padding: const EdgeInsets.only(bottom: 3.0), + child: SizedBox( + height: 35, + width: double.infinity, + child: ToggleSwitch( + minWidth: double.infinity, + customTextStyles: [TextStylePresets.body()], + initialLabelIndex: context.settingsValue( + SettingsKey.courseFilteringType) ?? + 0, + dividerColor: Colors.transparent, + activeBgColor: const [ColorPresets.primary], + activeFgColor: Colors.white, + inactiveBgColor: context.cuckooTheme.secondaryTransBg, + inactiveFgColor: context.cuckooTheme.primaryText, + totalSwitches: 2, + radiusStyle: true, + cornerRadius: 10.0, + labels: const ['None', 'Latest Semester'], + onToggle: (index) { + if (index != null) { + Settings() + .set(SettingsKey.courseFilteringType, index); + } + }, + ), + ), + ), + ), MorePanelElement( title: Constants.kMorePanelSync, icon: const Icon(Icons.sync_rounded), diff --git a/lib/src/routes/courses/courses_collection.dart b/lib/src/routes/courses/courses_collection.dart index 531649b..5260680 100644 --- a/lib/src/routes/courses/courses_collection.dart +++ b/lib/src/routes/courses/courses_collection.dart @@ -53,6 +53,8 @@ class _MoodleCourseCollectionViewState courses = context.courseManager.sortedCourses( sortBy: MoodleCourseSortingType.values[ context.settingsValue(SettingsKey.courseSortingType) ?? 0], + filterBy: MoodleCourseFilteringType.values[ + context.settingsValue(SettingsKey.courseFilteringType) ?? 0], showFavoriteOnly: widget.showFavoriteOnly); if (courses.isEmpty) { diff --git a/pubspec.lock b/pubspec.lock index 3afdf11..c4fec32 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -540,26 +540,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: @@ -612,10 +612,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" mime: dependency: transitive description: @@ -1025,10 +1025,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" timezone: dependency: "direct main" description: @@ -1201,10 +1201,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" watcher: dependency: transitive description: From 927a83219804fd3ded6ff7b75b16d521560fc751 Mon Sep 17 00:00:00 2001 From: nohack Date: Thu, 13 Jun 2024 22:48:15 +0800 Subject: [PATCH 2/2] Fix the problem of not recognizing summer semester --- lib/src/common/services/moodle_managers.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/common/services/moodle_managers.dart b/lib/src/common/services/moodle_managers.dart index 322a253..040004b 100644 --- a/lib/src/common/services/moodle_managers.dart +++ b/lib/src/common/services/moodle_managers.dart @@ -92,9 +92,17 @@ class MoodleCourseManager with ChangeNotifier { for (final course in sortedCourses) { var groups = RegExp(r'^(.*)_(\w{0,3})_(\d{4})$').firstMatch(course.idnumber); - final sem = int.tryParse(groups?.group(2)?[0] ?? "0"); + final year = int.tryParse(groups?.group(3) ?? "0"); + String? semString = groups?.group(2)?[0]; + // Check if it is summer semester + if (semString != null && semString.toLowerCase() == "s") { + semString = "3"; + } + + final sem = int.tryParse(semString ?? "0"); + if (year != null && sem != null) { coursesYearAndSemester[course.id] = [year, sem];