timetable performance optimization
This commit is contained in:
@@ -45,7 +45,7 @@ class ForeignTimetableBloc
|
||||
TimetableState fromNothing() {
|
||||
final reference = DateTime.now().addDays(2);
|
||||
return TimetableState(
|
||||
startDate: _startOfWeek(reference),
|
||||
startDate: reference.mondayOfWeek,
|
||||
endDate: _endOfWeek(reference),
|
||||
);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class ForeignTimetableBloc
|
||||
|
||||
void resetWeek() {
|
||||
final reference = DateTime.now().addDays(2);
|
||||
changeWeek(_startOfWeek(reference), _endOfWeek(reference));
|
||||
changeWeek(reference.mondayOfWeek, _endOfWeek(reference));
|
||||
}
|
||||
|
||||
void refresh() => fetch();
|
||||
@@ -180,19 +180,7 @@ class ForeignTimetableBloc
|
||||
}
|
||||
|
||||
void _writeWeekToCache(DateTime weekStart, TimetableGetWeekResponse week) {
|
||||
final key = weekStart.weekKey();
|
||||
add(
|
||||
Emit((s) {
|
||||
final updated = Map<String, TimetableGetWeekResponse>.of(s.weekCache);
|
||||
updated[key] = week;
|
||||
return s.copyWith(weekCache: updated, dataVersion: s.dataVersion + 1);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
static DateTime _startOfWeek(DateTime reference) {
|
||||
final monday = reference.subtractDays(reference.weekday - 1);
|
||||
return DateTime(monday.year, monday.month, monday.day);
|
||||
add(Emit((s) => s.withFetchedWeek(weekStart, week)));
|
||||
}
|
||||
|
||||
static DateTime _endOfWeek(DateTime reference) {
|
||||
|
||||
@@ -36,7 +36,7 @@ class TimetableBloc
|
||||
TimetableState fromNothing() {
|
||||
final reference = DateTime.now().addDays(2);
|
||||
return TimetableState(
|
||||
startDate: _startOfWeek(reference),
|
||||
startDate: reference.mondayOfWeek,
|
||||
endDate: _endOfWeek(reference),
|
||||
);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class TimetableBloc
|
||||
final stored = TimetableState.fromJson(json);
|
||||
final reference = DateTime.now().addDays(2);
|
||||
return stored.copyWith(
|
||||
startDate: _startOfWeek(reference),
|
||||
startDate: reference.mondayOfWeek,
|
||||
endDate: _endOfWeek(reference),
|
||||
accessibleStartDate: null,
|
||||
accessibleEndDate: null,
|
||||
@@ -99,7 +99,7 @@ class TimetableBloc
|
||||
|
||||
void resetWeek() {
|
||||
final reference = DateTime.now().addDays(2);
|
||||
changeWeek(_startOfWeek(reference), _endOfWeek(reference));
|
||||
changeWeek(reference.mondayOfWeek, _endOfWeek(reference));
|
||||
}
|
||||
|
||||
void refresh() => fetch();
|
||||
@@ -245,19 +245,7 @@ class TimetableBloc
|
||||
}
|
||||
|
||||
void _writeWeekToCache(DateTime weekStart, TimetableGetWeekResponse week) {
|
||||
final key = weekStart.weekKey();
|
||||
add(
|
||||
Emit((s) {
|
||||
final updated = Map<String, TimetableGetWeekResponse>.of(s.weekCache);
|
||||
updated[key] = week;
|
||||
return s.copyWith(weekCache: updated, dataVersion: s.dataVersion + 1);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
static DateTime _startOfWeek(DateTime reference) {
|
||||
final monday = reference.subtractDays(reference.weekday - 1);
|
||||
return DateTime(monday.year, monday.month, monday.day);
|
||||
add(Emit((s) => s.withFetchedWeek(weekStart, week)));
|
||||
}
|
||||
|
||||
static DateTime _endOfWeek(DateTime reference) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import '../../../../../api/marianumconnect/queries/timetable_get_subjects/timeta
|
||||
import '../../../../../api/marianumconnect/queries/timetable_get_timegrid/timetable_get_timegrid_response.dart';
|
||||
import '../../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||
import '../../../../../api/mhsl/custom_timetable_event/get/get_custom_timetable_event_response.dart';
|
||||
import 'week_cache.dart';
|
||||
|
||||
part 'timetable_state.freezed.dart';
|
||||
part 'timetable_state.g.dart';
|
||||
@@ -40,6 +41,23 @@ abstract class TimetableState with _$TimetableState {
|
||||
Iterable<McTimetableEntry> getAllKnownLessons() =>
|
||||
weekCache.values.expand((response) => response.entries);
|
||||
|
||||
/// This state with [week] cached, or `this` when its content is unchanged
|
||||
/// (so the emit is dropped as equal).
|
||||
TimetableState withFetchedWeek(
|
||||
DateTime weekStart,
|
||||
TimetableGetWeekResponse week,
|
||||
) {
|
||||
final updated = mergeWeekIntoCache(
|
||||
weekCache,
|
||||
weekStart,
|
||||
week,
|
||||
viewedWeekStart: startDate,
|
||||
now: DateTime.now(),
|
||||
);
|
||||
if (updated == null) return this;
|
||||
return copyWith(weekCache: updated, dataVersion: dataVersion + 1);
|
||||
}
|
||||
|
||||
bool get hasReferenceData =>
|
||||
rooms != null &&
|
||||
subjects != null &&
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user