implemented current schoolyear API and dynamic timetable scroll boundaries, added handling for out-of-range errors to narrow accessible dates, optimized holiday region rendering by collapsing overlaps, and refined holiday tile UI
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:intl/intl.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 '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc.dart';
|
||||
import '../../../infrastructure/utility_widgets/loadable_hydrated_bloc/loadable_hydrated_bloc_event.dart';
|
||||
import '../repository/timetable_repository.dart';
|
||||
@@ -124,20 +127,65 @@ 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) {
|
||||
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.add(const Duration(days: 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.subtract(const Duration(days: 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,
|
||||
}) async {
|
||||
try {
|
||||
final (rooms, subjects, schoolHolidays) = await (
|
||||
final (rooms, subjects, schoolHolidays, schoolyear) = await (
|
||||
repo.data.getRooms(onError: onError, renew: renew),
|
||||
repo.data.getSubjects(onError: onError, renew: renew),
|
||||
repo.data.getSchoolHolidays(onError: onError, renew: renew),
|
||||
repo.data.getCurrentSchoolyear(onError: onError, renew: renew),
|
||||
).wait;
|
||||
|
||||
add(
|
||||
@@ -146,6 +194,7 @@ class TimetableBloc
|
||||
rooms: rooms,
|
||||
subjects: subjects,
|
||||
schoolHolidays: schoolHolidays,
|
||||
schoolyear: schoolyear,
|
||||
dataVersion: s.dataVersion + 1,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user