implemented DST-safe date arithmetic with new addDays and subtractDays extensions, updated timetable state to reset view and scroll boundaries on initialization to prevent stale views, added hard caps to calendar navigation, and updated version to 1.0.3+52
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncfusion_flutter_calendar/calendar.dart';
|
||||
|
||||
import '../../../extensions/date_time.dart';
|
||||
import '../../../routing/app_routes.dart';
|
||||
import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart';
|
||||
import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
|
||||
@@ -34,7 +35,7 @@ class _TimetableState extends State<Timetable> {
|
||||
int? _lastDataVersion;
|
||||
TimetableSettings? _lastTimetableSettings;
|
||||
|
||||
DateTime _initialDisplayDate() => DateTime.now().add(const Duration(days: 2));
|
||||
DateTime _initialDisplayDate() => DateTime.now().addDays(2);
|
||||
|
||||
void _jumpToToday() {
|
||||
_calendarKey.currentState?.jumpToDate(_initialDisplayDate());
|
||||
@@ -82,16 +83,8 @@ class _TimetableState extends State<Timetable> {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isOnInitialWeek(TimetableState state) {
|
||||
final target = _initialDisplayDate();
|
||||
final targetMonday = target.subtract(Duration(days: target.weekday - 1));
|
||||
final mondayOnly = DateTime(
|
||||
targetMonday.year,
|
||||
targetMonday.month,
|
||||
targetMonday.day,
|
||||
);
|
||||
return state.startDate == mondayOnly;
|
||||
}
|
||||
bool _isOnInitialWeek(TimetableState state) =>
|
||||
state.startDate == _mondayOf(_initialDisplayDate());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -178,11 +171,20 @@ class _TimetableState extends State<Timetable> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Hard caps applied on top of whatever Webuntis would allow. Even if the
|
||||
/// school year (or a stale persisted bound) would let the user scroll
|
||||
/// further, we never expose more than this much around the current week —
|
||||
/// containment for any future date-math bug that might otherwise teleport
|
||||
/// the user months away from today.
|
||||
static const int _maxWeeksBack = 4;
|
||||
static const int _maxWeeksForward = 2;
|
||||
|
||||
/// Returns the (minDate, maxDate) the user is allowed to scroll between.
|
||||
/// Starts from the Webuntis school year (or a tight window when that
|
||||
/// hasn't loaded yet) and tightens by anything the bloc has learned
|
||||
/// from `-7004 no allowed date` errors during scroll — so the user
|
||||
/// can't slide off into territory Webuntis would refuse anyway.
|
||||
/// hasn't loaded yet), tightens by anything the bloc has learned from
|
||||
/// `-7004 no allowed date` errors during scroll — so the user can't
|
||||
/// slide off into territory Webuntis would refuse anyway — and finally
|
||||
/// clamps to a fixed window around today.
|
||||
///
|
||||
/// minDate is snapped *forward* to the next Monday because the calendar's
|
||||
/// internal `_mondayOf()` would otherwise pull a mid-week minDate back
|
||||
@@ -198,8 +200,8 @@ class _TimetableState extends State<Timetable> {
|
||||
baseMax = WebuntisTime.parse(year.endDate, 0);
|
||||
} else {
|
||||
final now = DateTime.now();
|
||||
baseMin = now.subtract(const Duration(days: 14));
|
||||
baseMax = now.add(const Duration(days: 7));
|
||||
baseMin = now.subtractDays(14);
|
||||
baseMax = now.addDays(7);
|
||||
}
|
||||
final effectiveMin = state.accessibleStartDate != null
|
||||
? (state.accessibleStartDate!.isAfter(baseMin)
|
||||
@@ -211,9 +213,25 @@ class _TimetableState extends State<Timetable> {
|
||||
? state.accessibleEndDate!
|
||||
: baseMax)
|
||||
: baseMax;
|
||||
final todayMonday = _mondayOf(DateTime.now());
|
||||
final cappedMin = effectiveMin.isBefore(
|
||||
todayMonday.subtractDays(_maxWeeksBack * 7),
|
||||
)
|
||||
? todayMonday.subtractDays(_maxWeeksBack * 7)
|
||||
: effectiveMin;
|
||||
final cappedMax = effectiveMax.isAfter(
|
||||
todayMonday.addDays(_maxWeeksForward * 7 + 6),
|
||||
)
|
||||
? todayMonday.addDays(_maxWeeksForward * 7 + 6)
|
||||
: effectiveMax;
|
||||
final daysToMonday =
|
||||
(DateTime.monday - effectiveMin.weekday) % DateTime.daysPerWeek;
|
||||
final mondayMin = effectiveMin.add(Duration(days: daysToMonday));
|
||||
return (mondayMin, effectiveMax);
|
||||
(DateTime.monday - cappedMin.weekday) % DateTime.daysPerWeek;
|
||||
final mondayMin = cappedMin.addDays(daysToMonday);
|
||||
return (mondayMin, cappedMax);
|
||||
}
|
||||
|
||||
static DateTime _mondayOf(DateTime d) {
|
||||
final monday = d.subtractDays(d.weekday - 1);
|
||||
return DateTime(monday.year, monday.month, monday.day);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user