migrated custom timetable events to Marianum-Connect and refactored push notification handling

This commit is contained in:
2026-07-12 14:31:48 +02:00
parent c444ed54a5
commit 91a6216f66
28 changed files with 474 additions and 212 deletions
@@ -1,5 +1,6 @@
import 'package:syncfusion_flutter_calendar/calendar.dart';
import '../../../../api/marianumconnect/models/mc_holiday.dart';
import '../../../../api/marianumconnect/queries/timetable_get_subjects/timetable_get_subjects_response.dart';
import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
import '../../../../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
@@ -16,6 +17,7 @@ class TimetableAppointmentFactory {
final List<McTimetableEntry> lessons;
final List<CustomTimetableEvent> customEvents;
final List<McSubject> subjects;
final List<McHoliday> holidays;
final TimetableSettings settings;
final DateTime now;
@@ -25,6 +27,7 @@ class TimetableAppointmentFactory {
required this.subjects,
required this.settings,
required this.now,
this.holidays = const [],
});
List<Appointment> build() {
@@ -98,6 +101,14 @@ class TimetableAppointmentFactory {
),
)
.toList();
// Ferien ausblenden ist nur für Serien sinnvoll; Syncfusion matcht
// Ausnahmen über recurrenceExceptionDates. Überzählige Ferientage, an denen
// gar keine Occurrence liegt, ignoriert es folgenlos — daher genügt es, für
// jeden Ferientag ein Ausnahmedatum zur Terminzeit einzustreuen, ohne die
// RRULE selbst expandieren zu müssen.
if (event.skipHolidays && parsed.rule.isNotEmpty) {
exceptionDates.addAll(_holidayExceptionDates(event));
}
return Appointment(
id: CustomAppointment(event),
startTime: event.startDate,
@@ -128,6 +139,36 @@ class TimetableAppointmentFactory {
);
}
List<DateTime> _holidayExceptionDates(CustomTimetableEvent event) {
final result = <DateTime>[];
for (final holiday in holidays) {
var day = DateTime(
holiday.startDate.year,
holiday.startDate.month,
holiday.startDate.day,
);
final last = DateTime(
holiday.endDate.year,
holiday.endDate.month,
holiday.endDate.day,
);
while (!day.isAfter(last)) {
result.add(
DateTime(
day.year,
day.month,
day.day,
event.startDate.hour,
event.startDate.minute,
event.startDate.second,
),
);
day = DateTime(day.year, day.month, day.day + 1);
}
}
return result;
}
/// All-day convention: a `CustomTimetableEvent` is treated as all-day when
/// its `startDate` and `endDate` both land on midnight of the same day.
/// Keeps the backend schema unchanged — the editor stores all-day events as