From bf2d0629df491dcc8f8e3199ba6fd6b00042c12e Mon Sep 17 00:00:00 2001 From: Erick Date: Tue, 24 Sep 2024 12:02:10 +0300 Subject: [PATCH] feat: courses background task to notify users upcoming classes daily --- lib/constants/common.dart | 24 ++++++ lib/models/core/course/course_model.dart | 75 ++++++++++++++++++- lib/pages/courses/courses.dart | 1 + .../service/courses_background_service.dart | 37 +++++++++ lib/storage/schemas.dart | 4 +- lib/workers/background_worker.dart | 30 +++++--- lib/workers/workers.dart | 1 + 7 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 lib/pages/courses/service/courses_background_service.dart diff --git a/lib/constants/common.dart b/lib/constants/common.dart index e0c2678..0a2b984 100644 --- a/lib/constants/common.dart +++ b/lib/constants/common.dart @@ -108,3 +108,27 @@ double calculateSemesterPercent(DateTime start, DateTime end) { return percentage; } } + +// Extension method to convert weekday number to string +extension WeekdayToString on DateTime { + String weekdayToString() { + switch (weekday) { + case DateTime.monday: + return "MONDAY"; + case DateTime.tuesday: + return "TUESDAY"; + case DateTime.wednesday: + return "WEDNESDAY"; + case DateTime.thursday: + return "THURSDAY"; + case DateTime.friday: + return "FRIDAY"; + case DateTime.saturday: + return "SATURDAY"; + case DateTime.sunday: + return "SUNDAY"; + default: + return ""; + } + } +} diff --git a/lib/models/core/course/course_model.dart b/lib/models/core/course/course_model.dart index 702d72f..9f93a6e 100644 --- a/lib/models/core/course/course_model.dart +++ b/lib/models/core/course/course_model.dart @@ -1,12 +1,64 @@ +// /// The course model represents a course just as its name implies +// class Course { +// final String unit; +// final String section; +// final String dayOfWeek; +// final String period; +// final String campus; +// final String room; +// final String lecturer; +// +// Course({ +// required this.unit, +// required this.section, +// required this.dayOfWeek, +// required this.period, +// required this.campus, +// required this.room, +// required this.lecturer, +// }); +// +// // Method to convert Course instance to a Map (JSON format) +// Map toJson() { +// return { +// 'unit': unit, +// 'section': section, +// 'day_of_the_week': dayOfWeek, +// 'period': period, +// 'campus': campus, +// 'room': room, +// 'lecturer': lecturer, +// }; +// } +// +// // Static method to create a Course instance from a Map (JSON format) +// static Course fromJson(Map json) { +// return Course( +// unit: json['unit'], +// section: json['section'], +// dayOfWeek: json['day_of_the_week'], +// period: json['period'], +// campus: json['campus'], +// room: json['room'], +// lecturer: json['lecturer'], +// ); +// } +// } + +import 'package:intl/intl.dart'; + /// The course model represents a course just as its name implies class Course { final String unit; final String section; final String dayOfWeek; - final String period; + final String + period; // This contains the time range (e.g., "02:10 PM-05:10 PM") final String campus; final String room; final String lecturer; + late DateTime startTime; + late DateTime stopTime; Course({ required this.unit, @@ -16,7 +68,9 @@ class Course { required this.campus, required this.room, required this.lecturer, - }); + }) { + extractTimesFromPeriod(period); + } // Method to convert Course instance to a Map (JSON format) Map toJson() { @@ -28,6 +82,8 @@ class Course { 'campus': campus, 'room': room, 'lecturer': lecturer, + 'start_time': startTime.toIso8601String(), + 'stop_time': stopTime.toIso8601String(), }; } @@ -41,6 +97,19 @@ class Course { campus: json['campus'], room: json['room'], lecturer: json['lecturer'], - ); + )..extractTimesFromPeriod(json['period']); + } + + // Private method to extract start and stop times from the period string + void extractTimesFromPeriod(String period) { + // Split the period by the dash ('-') + List times = period.split('-'); + + // Define a DateFormat to parse the time strings + DateFormat formatter = DateFormat("hh:mm a"); + + // Parse start and stop times + startTime = formatter.parse(times[0].trim()); + stopTime = formatter.parse(times[1].trim()); } } diff --git a/lib/pages/courses/courses.dart b/lib/pages/courses/courses.dart index d32fade..d12d17d 100644 --- a/lib/pages/courses/courses.dart +++ b/lib/pages/courses/courses.dart @@ -1 +1,2 @@ export 'courses_page.dart'; +export 'service/courses_background_service.dart'; diff --git a/lib/pages/courses/service/courses_background_service.dart b/lib/pages/courses/service/courses_background_service.dart new file mode 100644 index 0000000..d886bdf --- /dev/null +++ b/lib/pages/courses/service/courses_background_service.dart @@ -0,0 +1,37 @@ +import 'package:academia/exports/barrel.dart'; +import 'package:academia/models/core/course/course.dart'; +import 'package:academia/notifier/local_notification_channel.dart'; +import 'package:academia/notifier/local_notification_status_manager.dart'; +import 'package:academia/notifier/local_notifier_service.dart'; + +class CoursesBackgroundService { + static final CoursesBackgroundService _instance = + CoursesBackgroundService._internal(); + + factory CoursesBackgroundService() { + return _instance; + } + + /// Private named constructor that prevents external instantiation. + CoursesBackgroundService._internal(); + + void notifyTodaysCourses() { + CourseModelHelper().queryAll().then((value) { + int coursestoday = 0; + value.map((e) { + final course = Course.fromJson(e); + if (course.dayOfWeek == DateTime.now().weekdayToString()) { + coursestoday++; + } + }); + + LocalNotifierService().showNotification( + id: LocalNotificationStatusManager().getNextId(), + title: "Class! Class! Class! ${Emojis.building_school}", + body: + "Hey, you have $coursestoday classes today ${Emojis.smile_face_screaming_in_fear}", + channelKey: LocalNotificationChannelType.reminders.channelKey, + ); + }); + } +} diff --git a/lib/storage/schemas.dart b/lib/storage/schemas.dart index 957076a..8459145 100644 --- a/lib/storage/schemas.dart +++ b/lib/storage/schemas.dart @@ -38,7 +38,9 @@ const schemas = { period TEXT NOT NULL, campus TEXT NOT NULL, room TEXT NOT NULL, - lecturer TEXT NOT NULL + lecturer TEXT NOT NULL, + start_time TEXT NOT NULL, + stop_time TEXT NOT NULL ); """, diff --git a/lib/workers/background_worker.dart b/lib/workers/background_worker.dart index 5093f78..178ffe3 100644 --- a/lib/workers/background_worker.dart +++ b/lib/workers/background_worker.dart @@ -1,7 +1,4 @@ import 'package:academia/exports/barrel.dart'; -import 'package:academia/notifier/local_notification_channel.dart'; -import 'package:academia/notifier/local_notification_status_manager.dart'; -import 'package:academia/notifier/local_notifier_service.dart'; // background services @pragma('vm:entry-point') @@ -11,18 +8,21 @@ void callbackDispatcher() { case BackgroundConfig.todosIDentifier: TodoBackgroundService().notifyPendingTasks(); break; + case BackgroundConfig.coursesIDentifier: + CoursesBackgroundService().notifyTodaysCourses(); + break; default: } - LocalNotifierService().showNotification( - id: LocalNotificationStatusManager().getNextId(), - title: "Dick", - body: "How are you doing pussy", - channelKey: LocalNotificationChannelType.general.channelKey, - ); return Future.value(true); }); } +Duration timeUntilNextTarget(DateTime targetTime) { + DateTime now = DateTime.now(); + Duration difference = targetTime.difference(now); + return difference; +} + class BackgroundWorker { static final BackgroundWorker _instance = BackgroundWorker._internal(); @@ -40,6 +40,18 @@ class BackgroundWorker { isInDebugMode: true, ); + DateTime now = DateTime.now(); + + /// Courses background service + Workmanager().registerPeriodicTask( + BackgroundConfig.coursesIDentifier, + BackgroundConfig.coursesIDentifier, + initialDelay: timeUntilNextTarget( + DateTime(now.year, now.month, now.day, 12, 0, 0), + ), + frequency: const Duration(minutes: 15), + ); + /// Todos task that is suppossed to run after every 24 hours at 8 am Workmanager().registerPeriodicTask( BackgroundConfig.todosIDentifier, diff --git a/lib/workers/workers.dart b/lib/workers/workers.dart index c5cf1cf..7ab23a1 100644 --- a/lib/workers/workers.dart +++ b/lib/workers/workers.dart @@ -4,4 +4,5 @@ export 'background_worker.dart'; class BackgroundConfig { static const String todosIDentifier = "com.dita.academia.todos"; + static const String coursesIDentifier = "com.dita.academia.courses"; }