migrated timetable integration from WebUntis to the MarianumConnect API, implementing a Dio-based client with bearer token authentication, background session validation, and auto-refresh logic.

This commit is contained in:
2026-05-23 17:32:42 +02:00
parent 2858f910c9
commit 93b9929f8f
106 changed files with 2739 additions and 2624 deletions
@@ -1,5 +1,15 @@
import 'package:intl/intl.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_holidays/timetable_get_holidays.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_holidays/timetable_get_holidays_response.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_rooms/timetable_get_rooms.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_rooms/timetable_get_rooms_response.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_schoolyear/timetable_get_schoolyear.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_schoolyear/timetable_get_schoolyear_response.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_subjects/timetable_get_subjects.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_subjects/timetable_get_subjects_response.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_timegrid/timetable_get_timegrid.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_timegrid/timetable_get_timegrid_response.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
import '../../../../../api/mhsl/custom_timetable_event/add/add_custom_timetable_event.dart';
import '../../../../../api/mhsl/custom_timetable_event/add/add_custom_timetable_event_params.dart';
import '../../../../../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
@@ -11,89 +21,77 @@ import '../../../../../api/mhsl/custom_timetable_event/remove/remove_custom_time
import '../../../../../api/mhsl/custom_timetable_event/update/update_custom_timetable_event.dart';
import '../../../../../api/mhsl/custom_timetable_event/update/update_custom_timetable_event_params.dart';
import '../../../../../api/request_cache.dart';
import '../../../../../api/webuntis/queries/get_current_schoolyear/get_current_schoolyear_cache.dart';
import '../../../../../api/webuntis/queries/get_current_schoolyear/get_current_schoolyear_response.dart';
import '../../../../../api/webuntis/queries/get_holidays/get_holidays_cache.dart';
import '../../../../../api/webuntis/queries/get_holidays/get_holidays_response.dart';
import '../../../../../api/webuntis/queries/get_rooms/get_rooms_cache.dart';
import '../../../../../api/webuntis/queries/get_rooms/get_rooms_response.dart';
import '../../../../../api/webuntis/queries/get_subjects/get_subjects_cache.dart';
import '../../../../../api/webuntis/queries/get_subjects/get_subjects_response.dart';
import '../../../../../api/webuntis/queries/get_timegrid_units/get_timegrid_units_cache.dart';
import '../../../../../api/webuntis/queries/get_timegrid_units/get_timegrid_units_response.dart';
import '../../../../../api/webuntis/queries/get_timetable/get_timetable_cache.dart';
import '../../../../../api/webuntis/queries/get_timetable/get_timetable_response.dart';
import '../../../../../model/account_data.dart';
/// Pulls the timetable from the Marianum-Connect mobile API. Each MC endpoint
/// is its own HTTP call; this provider just exposes the lazy futures so the
/// bloc can chain them without seeing the dio layer. Custom events still come
/// from the MHSL backend and are unchanged.
class TimetableDataProvider {
static final DateFormat _dateFormat = DateFormat('yyyyMMdd');
Future<GetTimetableResponse> getWeek(
Future<TimetableGetWeekResponse> getWeek(
DateTime startDate,
DateTime endDate, {
void Function(Object)? onError,
bool renew = false,
}) => resolveFromCache<GetTimetableResponse>(
(onUpdate, onError) => GetTimetableCache(
startdate: int.parse(_dateFormat.format(startDate)),
enddate: int.parse(_dateFormat.format(endDate)),
renew: renew,
onUpdate: onUpdate,
onError: onError,
),
onError: onError,
operationName: 'getWeek',
);
}) async {
try {
return await TimetableGetWeek().run(from: startDate, until: endDate);
} catch (e) {
onError?.call(e);
rethrow;
}
}
Future<GetRoomsResponse> getRooms({
Future<TimetableGetRoomsResponse> getRooms({
void Function(Object)? onError,
bool renew = false,
}) => resolveFromCache<GetRoomsResponse>(
(onUpdate, onError) =>
GetRoomsCache(renew: renew, onUpdate: onUpdate, onError: onError),
onError: onError,
operationName: 'getRooms',
);
}) async {
try {
return await TimetableGetRooms().run();
} catch (e) {
onError?.call(e);
rethrow;
}
}
Future<GetSubjectsResponse> getSubjects({
Future<TimetableGetSubjectsResponse> getSubjects({
void Function(Object)? onError,
bool renew = false,
}) => resolveFromCache<GetSubjectsResponse>(
(onUpdate, onError) =>
GetSubjectsCache(renew: renew, onUpdate: onUpdate, onError: onError),
onError: onError,
operationName: 'getSubjects',
);
}) async {
try {
return await TimetableGetSubjects().run();
} catch (e) {
onError?.call(e);
rethrow;
}
}
Future<GetHolidaysResponse> getSchoolHolidays({
Future<TimetableGetHolidaysResponse> getSchoolHolidays({
void Function(Object)? onError,
bool renew = false,
}) => resolveFromCache<GetHolidaysResponse>(
(onUpdate, onError) =>
GetHolidaysCache(renew: renew, onUpdate: onUpdate, onError: onError),
onError: onError,
operationName: 'getSchoolHolidays',
);
}) async {
try {
return await TimetableGetHolidays().run();
} catch (e) {
onError?.call(e);
rethrow;
}
}
Future<GetCurrentSchoolyearResponse> getCurrentSchoolyear({
Future<TimetableGetSchoolyearResponse> getCurrentSchoolyear({
void Function(Object)? onError,
bool renew = false,
}) => resolveFromCache<GetCurrentSchoolyearResponse>(
(onUpdate, onError) => GetCurrentSchoolyearCache(
renew: renew,
onUpdate: onUpdate,
onError: onError,
),
onError: onError,
operationName: 'getCurrentSchoolyear',
);
}) async {
try {
return await TimetableGetSchoolyear().run();
} catch (e) {
onError?.call(e);
rethrow;
}
}
Future<GetTimegridUnitsResponse> getTimegrid({bool renew = false}) =>
resolveFromCache<GetTimegridUnitsResponse>(
(onUpdate, _) =>
GetTimegridUnitsCache(renew: renew, onUpdate: onUpdate),
operationName: 'getTimegrid',
);
Future<TimetableGetTimegridResponse> getTimegrid({bool renew = false}) =>
TimetableGetTimegrid().run();
Future<GetCustomTimetableEventResponse> getCustomEvents({
bool renew = false,