73 lines
2.3 KiB
Dart
73 lines
2.3 KiB
Dart
import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
|
|
|
/// Combines back-to-back lessons with identical subject/room/teacher/status
|
|
/// into a single visual block. Shared by the calendar tile builder and the
|
|
/// home-widget data mapper so both surfaces show the same merged spans.
|
|
///
|
|
/// Built as a new list rather than mutating inputs — earlier in-place merges
|
|
/// extended merged blocks further on every rebuild when the same lesson
|
|
/// objects were observed again.
|
|
class LessonMerger {
|
|
const LessonMerger._();
|
|
|
|
static const Duration defaultMaxGap = Duration(minutes: 5);
|
|
|
|
static List<McTimetableEntry> merge(
|
|
List<McTimetableEntry> input, {
|
|
Duration maxGap = defaultMaxGap,
|
|
}) {
|
|
if (input.isEmpty) return const [];
|
|
|
|
final sorted = [...input]
|
|
..sort((a, b) => a.startDateTime.compareTo(b.startDateTime));
|
|
|
|
final merged = <McTimetableEntry>[];
|
|
for (final current in sorted) {
|
|
if (merged.isNotEmpty && _canMerge(merged.last, current, maxGap)) {
|
|
final prev = merged.removeLast();
|
|
merged.add(_extendedEnd(prev, current.endTime));
|
|
} else {
|
|
merged.add(current);
|
|
}
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
static bool _canMerge(
|
|
McTimetableEntry a,
|
|
McTimetableEntry b,
|
|
Duration maxGap,
|
|
) {
|
|
if (a.subjects.firstOrNull != b.subjects.firstOrNull) return false;
|
|
if (a.rooms.firstOrNull != b.rooms.firstOrNull) return false;
|
|
if (a.teachers.firstOrNull?.shortName !=
|
|
b.teachers.firstOrNull?.shortName) {
|
|
return false;
|
|
}
|
|
if (a.status != b.status) return false;
|
|
// Lower bound on the gap — without it, two identical-metadata lessons that
|
|
// overlap in time would silently collapse into one.
|
|
final gap = b.startDateTime.difference(a.endDateTime);
|
|
return !gap.isNegative && gap <= maxGap;
|
|
}
|
|
|
|
static McTimetableEntry _extendedEnd(
|
|
McTimetableEntry source,
|
|
DateTime newEndTime,
|
|
) => McTimetableEntry(
|
|
id: source.id,
|
|
date: source.date,
|
|
startTime: source.startTime,
|
|
endTime: newEndTime,
|
|
subjects: source.subjects,
|
|
teachers: source.teachers,
|
|
rooms: source.rooms,
|
|
classNames: source.classNames,
|
|
lessonType: source.lessonType,
|
|
status: source.status,
|
|
substitutionText: source.substitutionText,
|
|
lessonText: source.lessonText,
|
|
infoText: source.infoText,
|
|
);
|
|
}
|