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:
@@ -2,9 +2,8 @@ import 'dart:developer';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||
import '../../../../../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
|
||||
import '../../../../../api/webuntis/queries/get_timetable/get_timetable_response.dart';
|
||||
import '../../../../../api/webuntis/webuntis_error.dart';
|
||||
import '../../../../../extensions/date_time.dart';
|
||||
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart';
|
||||
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart';
|
||||
@@ -46,12 +45,8 @@ class TimetableBloc
|
||||
}
|
||||
|
||||
/// Persisted state may carry a stale `startDate`/`endDate` from the user's
|
||||
/// last view as well as `accessibleStartDate`/`accessibleEndDate` learned
|
||||
/// from `-7004 no allowed date` errors during scroll. Both must reset on
|
||||
/// every cold start: otherwise the calendar can mount on a months-old week
|
||||
/// (e.g. last December's Christmas holidays) or get permanently clamped
|
||||
/// inside a window Webuntis once refused — even though the server would
|
||||
/// happily serve the user's current week now.
|
||||
/// last view. Reset on every cold start so the calendar always mounts on
|
||||
/// the current week, not on whatever week the user closed the app on.
|
||||
@override
|
||||
TimetableState fromStorage(Map<String, dynamic> json) {
|
||||
final stored = TimetableState.fromJson(json);
|
||||
@@ -142,55 +137,12 @@ class TimetableBloc
|
||||
);
|
||||
if (_lastWeekRequestStart.isAfter(requestStart)) return;
|
||||
_writeWeekToCache(startDate, week);
|
||||
} on WebuntisError catch (e) {
|
||||
if (e.code == _outOfRangeErrorCode) {
|
||||
_narrowAccessibleRange(startDate, endDate);
|
||||
// Out-of-range is expected when the user scrolls into territory
|
||||
// Webuntis doesn't grant access to — surface to UI as a normal
|
||||
// empty week instead of letting the loadable state escalate it
|
||||
// into a red error screen.
|
||||
return;
|
||||
}
|
||||
log(
|
||||
'Webuntis getWeek error: code=${e.code} message="${e.message}" '
|
||||
'for $startDate–$endDate',
|
||||
);
|
||||
onError?.call(e);
|
||||
} catch (e) {
|
||||
log('getWeek error for $startDate–$endDate: $e');
|
||||
onError?.call(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Webuntis returns this for weeks the user has no access to (typically
|
||||
/// before the active enrolment / after a teacher's planning window).
|
||||
static const int _outOfRangeErrorCode = -7004;
|
||||
|
||||
/// Pulls the calendar's permitted scroll range inward based on a denied
|
||||
/// week. We don't know the exact cutoff — only that *this* week is out
|
||||
/// of reach — so we always pick the tighter of the existing bound and
|
||||
/// the newly discovered one. Pre-now denials shrink the lower bound,
|
||||
/// post-now denials the upper.
|
||||
void _narrowAccessibleRange(DateTime startDate, DateTime endDate) {
|
||||
final now = DateTime.now();
|
||||
final isPast = endDate.isBefore(now);
|
||||
add(
|
||||
Emit((s) {
|
||||
if (isPast) {
|
||||
final candidate = endDate.addDays(1);
|
||||
final current = s.accessibleStartDate;
|
||||
if (current != null && !candidate.isAfter(current)) return s;
|
||||
return s.copyWith(accessibleStartDate: candidate);
|
||||
}
|
||||
// Treat anything not strictly past as a forward-direction denial,
|
||||
// including the rare case where startDate == now.
|
||||
final candidate = startDate.subtractDays(1);
|
||||
final current = s.accessibleEndDate;
|
||||
if (current != null && !candidate.isBefore(current)) return s;
|
||||
return s.copyWith(accessibleEndDate: candidate);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _loadStaticReferenceData({
|
||||
void Function(Object)? onError,
|
||||
bool renew = false,
|
||||
@@ -271,11 +223,11 @@ class TimetableBloc
|
||||
.catchError((_) {});
|
||||
}
|
||||
|
||||
void _writeWeekToCache(DateTime weekStart, GetTimetableResponse week) {
|
||||
void _writeWeekToCache(DateTime weekStart, TimetableGetWeekResponse week) {
|
||||
final key = _weekKeyFormat.format(weekStart);
|
||||
add(
|
||||
Emit((s) {
|
||||
final updated = Map<String, GetTimetableResponse>.of(s.weekCache);
|
||||
final updated = Map<String, TimetableGetWeekResponse>.of(s.weekCache);
|
||||
updated[key] = week;
|
||||
return s.copyWith(weekCache: updated, dataVersion: s.dataVersion + 1);
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user