156 lines
4.3 KiB
Dart
156 lines
4.3 KiB
Dart
import 'package:flutter/material.dart';
|
||
|
||
import '../../../../api/marianumconnect/queries/timetable_get_timegrid/timetable_get_timegrid_response.dart';
|
||
import '../../../../state/app/modules/timetable/bloc/timetable_state.dart';
|
||
|
||
class LessonPeriod {
|
||
final String name;
|
||
final TimeOfDay start;
|
||
final TimeOfDay end;
|
||
final bool isBreak;
|
||
|
||
const LessonPeriod({
|
||
required this.name,
|
||
required this.start,
|
||
required this.end,
|
||
this.isBreak = false,
|
||
});
|
||
|
||
Duration get duration => Duration(
|
||
minutes: (end.hour * 60 + end.minute) - (start.hour * 60 + start.minute),
|
||
);
|
||
|
||
int get _startMinutes => start.hour * 60 + start.minute;
|
||
}
|
||
|
||
class LessonPeriodSchedule {
|
||
final List<LessonPeriod> periods;
|
||
|
||
const LessonPeriodSchedule(this.periods);
|
||
|
||
static LessonPeriodSchedule? fromApi(TimetableGetTimegridResponse response) {
|
||
// The Marianum-Connect endpoint returns one entry per (weekday, unit). The
|
||
// school's bell schedule is identical Mon–Fri, so we pick Monday as the
|
||
// canonical day and fall back to the first available weekday if Monday is
|
||
// missing.
|
||
final monday = response.result
|
||
.where((u) => u.dayOfWeek == McDayOfWeek.monday)
|
||
.toList();
|
||
final source = monday.isNotEmpty ? monday : response.result;
|
||
if (source.isEmpty) return null;
|
||
|
||
final periods =
|
||
source
|
||
.map(
|
||
(u) => LessonPeriod(
|
||
name: u.label,
|
||
start: TimeOfDay(
|
||
hour: u.startTime.hour,
|
||
minute: u.startTime.minute,
|
||
),
|
||
end: TimeOfDay(
|
||
hour: u.endTime.hour,
|
||
minute: u.endTime.minute,
|
||
),
|
||
),
|
||
)
|
||
.toList()
|
||
..sort((a, b) => a._startMinutes.compareTo(b._startMinutes));
|
||
|
||
return LessonPeriodSchedule(periods);
|
||
}
|
||
|
||
static LessonPeriodSchedule fallback() => const LessonPeriodSchedule([
|
||
LessonPeriod(
|
||
name: '0',
|
||
start: TimeOfDay(hour: 7, minute: 10),
|
||
end: TimeOfDay(hour: 7, minute: 53),
|
||
),
|
||
LessonPeriod(
|
||
name: '1',
|
||
start: TimeOfDay(hour: 7, minute: 55),
|
||
end: TimeOfDay(hour: 8, minute: 40),
|
||
),
|
||
LessonPeriod(
|
||
name: '2',
|
||
start: TimeOfDay(hour: 8, minute: 40),
|
||
end: TimeOfDay(hour: 9, minute: 25),
|
||
),
|
||
LessonPeriod(
|
||
name: '3',
|
||
start: TimeOfDay(hour: 9, minute: 30),
|
||
end: TimeOfDay(hour: 10, minute: 15),
|
||
),
|
||
LessonPeriod(
|
||
name: '4',
|
||
start: TimeOfDay(hour: 10, minute: 35),
|
||
end: TimeOfDay(hour: 11, minute: 20),
|
||
),
|
||
LessonPeriod(
|
||
name: '5',
|
||
start: TimeOfDay(hour: 11, minute: 25),
|
||
end: TimeOfDay(hour: 12, minute: 10),
|
||
),
|
||
LessonPeriod(
|
||
name: '6',
|
||
start: TimeOfDay(hour: 12, minute: 15),
|
||
end: TimeOfDay(hour: 13, minute: 0),
|
||
),
|
||
LessonPeriod(
|
||
name: '7',
|
||
start: TimeOfDay(hour: 13, minute: 5),
|
||
end: TimeOfDay(hour: 13, minute: 50),
|
||
),
|
||
LessonPeriod(
|
||
name: '8',
|
||
start: TimeOfDay(hour: 14, minute: 5),
|
||
end: TimeOfDay(hour: 14, minute: 50),
|
||
),
|
||
LessonPeriod(
|
||
name: '9',
|
||
start: TimeOfDay(hour: 14, minute: 50),
|
||
end: TimeOfDay(hour: 15, minute: 35),
|
||
),
|
||
LessonPeriod(
|
||
name: '10',
|
||
start: TimeOfDay(hour: 15, minute: 40),
|
||
end: TimeOfDay(hour: 16, minute: 25),
|
||
),
|
||
LessonPeriod(
|
||
name: '11',
|
||
start: TimeOfDay(hour: 16, minute: 25),
|
||
end: TimeOfDay(hour: 17, minute: 10),
|
||
),
|
||
]);
|
||
|
||
static LessonPeriodSchedule fromState(TimetableState state) {
|
||
final fromApi = state.timegrid != null
|
||
? LessonPeriodSchedule.fromApi(state.timegrid!)
|
||
: null;
|
||
return (fromApi ?? fallback()).withSyntheticBreaks();
|
||
}
|
||
|
||
LessonPeriodSchedule withSyntheticBreaks() {
|
||
final result = <LessonPeriod>[];
|
||
for (var i = 0; i < periods.length; i++) {
|
||
final current = periods[i];
|
||
result.add(current);
|
||
if (i + 1 >= periods.length) continue;
|
||
final next = periods[i + 1];
|
||
final gapMinutes =
|
||
next._startMinutes - (current.end.hour * 60 + current.end.minute);
|
||
if (gapMinutes >= 10) {
|
||
result.add(
|
||
LessonPeriod(
|
||
name: 'Pause',
|
||
start: current.end,
|
||
end: next.start,
|
||
isBreak: true,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
return LessonPeriodSchedule(result);
|
||
}
|
||
}
|