timetable performance optimization

This commit is contained in:
2026-09-25 22:27:10 +02:00
parent ef7d17033d
commit ed8e52f475
13 changed files with 391 additions and 137 deletions
@@ -0,0 +1,45 @@
import 'package:collection/collection.dart';
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
import '../../../../../extensions/date_time.dart';
/// Weeks kept around the viewed week and around today's week. Everything
/// further away is dropped: every state emit re-serializes the whole cache for
/// HydratedBloc and the calendar rebuilds its appointments from all of it, so
/// an unbounded cache makes week swipes slower the longer the app is used.
const int kWeekCacheRadius = 4;
/// Returns the cache with [week] stored under [weekStart], pruned to the
/// weeks near [viewedWeekStart] or [now]. Returns null when the stored week
/// already has identical content, so callers can skip the emit entirely.
Map<String, TimetableGetWeekResponse>? mergeWeekIntoCache(
Map<String, TimetableGetWeekResponse> cache,
DateTime weekStart,
TimetableGetWeekResponse week, {
required DateTime viewedWeekStart,
required DateTime now,
}) {
final key = weekStart.weekKey();
final existing = cache[key];
if (existing != null &&
const DeepCollectionEquality().equals(existing.toJson(), week.toJson())) {
return null;
}
final viewedMonday = viewedWeekStart.mondayOfWeek;
final todayMonday = now.mondayOfWeek;
bool isNear(DateTime monday, DateTime anchor) =>
monday.difference(anchor).inDays.abs() <= kWeekCacheRadius * 7 + 1;
final updated = <String, TimetableGetWeekResponse>{};
for (final entry in cache.entries) {
final monday = DateTime.tryParse(entry.key);
if (monday == null ||
isNear(monday, viewedMonday) ||
isNear(monday, todayMonday)) {
updated[entry.key] = entry.value;
}
}
updated[key] = week;
return updated;
}