import '../../marianumconnect/queries/timetable_get_holidays/timetable_get_holidays_response.dart'; import '../../marianumconnect/queries/timetable_get_rooms/timetable_get_rooms_response.dart'; import '../../marianumconnect/queries/timetable_get_schoolyear/timetable_get_schoolyear_response.dart'; import '../../marianumconnect/queries/timetable_get_subjects/timetable_get_subjects_response.dart'; import '../../marianumconnect/queries/timetable_get_timegrid/timetable_get_timegrid_response.dart'; import '../../marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart'; import '../../mhsl/custom_timetable_event/get/get_custom_timetable_event_response.dart'; import '../demo_persona.dart'; /// Curated timetable fixtures for the demo mode. Everything is derived from /// [DemoPersona] so subjects, teachers and rooms line up with the rest of the /// demo app, and every week is generated relative to the requested range so /// navigating forward/backward always lands on a populated 10b schedule. class DemoTimetable { const DemoTimetable._(); /// Period → (startHour, startMinute, endHour, endMinute). static const Map _periods = { 1: (7, 55, 8, 40), 2: (8, 40, 9, 25), 3: (9, 45, 10, 30), 4: (10, 30, 11, 15), 5: (11, 35, 12, 20), 6: (12, 20, 13, 5), 7: (13, 50, 14, 35), 8: (14, 35, 15, 20), }; /// Weekday (DateTime.monday..friday) → period → subject short code. static const Map> _plan = { DateTime.monday: {1: 'M', 2: 'M', 3: 'D', 4: 'E', 5: 'BIO', 6: 'GE', 7: 'SP', 8: 'SP'}, DateTime.tuesday: {1: 'E', 2: 'E', 3: 'PH', 4: 'M', 5: 'D', 6: 'REL', 7: 'GE'}, DateTime.wednesday: {1: 'BIO', 2: 'BIO', 3: 'M', 4: 'D', 5: 'E', 6: 'PH'}, DateTime.thursday: {1: 'D', 2: 'GE', 3: 'M', 4: 'M', 5: 'REL', 6: 'BIO', 7: 'SP', 8: 'SP'}, DateTime.friday: {1: 'PH', 2: 'PH', 3: 'E', 4: 'M', 5: 'D', 6: 'GE'}, }; static const Map _roomBySubject = { 'M': 'A101', 'D': 'A101', 'E': 'A102', 'BIO': 'B201', 'PH': 'B203', 'GE': 'A101', 'SP': 'Turnhalle 1', 'REL': 'C305', }; static TimetableGetWeekResponse week(DateTime from, DateTime until) { final monday = _mondayOf(from); final entries = []; var id = 1; for (final weekday in _plan.keys) { final date = monday.add(Duration(days: weekday - DateTime.monday)); final day = _plan[weekday]!; for (final entry in day.entries) { entries.add(_entry(id++, date, weekday, entry.key, entry.value)); } } return TimetableGetWeekResponse(from: from, until: until, entries: entries); } static McTimetableEntry _entry( int id, DateTime date, int weekday, int period, String subjectShort, ) { final times = _periods[period]!; final teacher = _teacherFor(subjectShort); // A couple of recurring irregularities so the demo shows off the cancelled // and substitution rendering. final cancelled = weekday == DateTime.monday && period == 4; final substituted = weekday == DateTime.tuesday && period == 3; return McTimetableEntry( id: id, date: date, startTime: DateTime(1970, 1, 1, times.$1, times.$2), endTime: DateTime(1970, 1, 1, times.$3, times.$4), subjects: [subjectShort], teachers: [ if (substituted) McTimetableTeacher( shortName: 'MÜL', displayName: 'Herr Müller', originalShortName: teacher.short, originalDisplayName: teacher.name, ) else McTimetableTeacher(shortName: teacher.short, displayName: teacher.name), ], rooms: [_roomBySubject[subjectShort] ?? DemoPersona.rooms.first], classNames: [DemoPersona.className], lessonType: 'LESSON', status: cancelled ? 'CANCELLED' : substituted ? 'IRREGULAR' : 'REGULAR', substitutionText: substituted ? 'Vertretung für ${teacher.name}' : null, lessonText: null, infoText: cancelled ? 'Fällt aus' : null, ); } static TimetableGetRoomsResponse rooms() => TimetableGetRoomsResponse( result: [ for (var i = 0; i < DemoPersona.rooms.length; i++) McRoom(id: i + 1, shortName: DemoPersona.rooms[i], longName: DemoPersona.rooms[i]), ], ); static TimetableGetSubjectsResponse subjects() => TimetableGetSubjectsResponse( result: [ for (var i = 0; i < DemoPersona.subjects.length; i++) McSubject( id: i + 1, shortName: DemoPersona.subjects[i].short, longName: DemoPersona.subjects[i].name, ), ], ); static TimetableGetTimegridResponse timegrid() { final units = []; for (final day in _weekdays) { for (final period in _periods.entries) { final t = period.value; units.add( McTimegridUnit( dayOfWeek: day, label: '${period.key}', startTime: DateTime(1970, 1, 1, t.$1, t.$2), endTime: DateTime(1970, 1, 1, t.$3, t.$4), ), ); } } return TimetableGetTimegridResponse(result: units); } static TimetableGetSchoolyearResponse schoolyear() { final startYear = _schoolyearStart(DateTime.now()); return TimetableGetSchoolyearResponse( id: 1, name: '$startYear/${startYear + 1}', startDate: DateTime(startYear, 8, 1), endDate: DateTime(startYear + 1, 7, 31), ); } static TimetableGetHolidaysResponse holidays() { final startYear = _schoolyearStart(DateTime.now()); return TimetableGetHolidaysResponse( result: [ McHoliday( shortName: 'Herbst', longName: 'Herbstferien', startDate: DateTime(startYear, 10, 20), endDate: DateTime(startYear, 10, 31), ), McHoliday( shortName: 'Weihnachten', longName: 'Weihnachtsferien', startDate: DateTime(startYear, 12, 22), endDate: DateTime(startYear + 1, 1, 6), ), ], ); } static GetCustomTimetableEventResponse customEvents() => GetCustomTimetableEventResponse([]); static const List _weekdays = [ McDayOfWeek.monday, McDayOfWeek.tuesday, McDayOfWeek.wednesday, McDayOfWeek.thursday, McDayOfWeek.friday, ]; static DemoTeacher _teacherFor(String subjectShort) { final subjectName = DemoPersona.subjects .firstWhere((s) => s.short == subjectShort) .name; return DemoPersona.teachers.firstWhere((t) => t.subject == subjectName); } static DateTime _mondayOf(DateTime date) { final day = DateTime(date.year, date.month, date.day); return day.subtract(Duration(days: day.weekday - DateTime.monday)); } static int _schoolyearStart(DateTime now) => now.month >= 8 ? now.year : now.year - 1; }