improved performance and battery usage on older devices

This commit is contained in:
2026-09-25 23:58:08 +02:00
parent ed8e52f475
commit 56a497985b
70 changed files with 1631 additions and 621 deletions
@@ -1,7 +1,7 @@
import 'package:rrule/rrule.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import '../../../../extensions/date_time.dart';
import '../../../../utils/recurrence_occurrences.dart';
import 'arbitrary_appointment.dart';
import 'calendar_layout.dart';
import 'lesson_period_schedule.dart';
@@ -103,7 +103,6 @@ partitionAppointmentsForWeek(
continue;
}
try {
final parsed = RecurrenceRule.fromString(rule);
final anchorUtc = a.startTime.toUtc();
final duration = a.endTime.difference(a.startTime);
// Day-keyed set of exception dates so occurrences scheduled for one
@@ -112,9 +111,12 @@ partitionAppointmentsForWeek(
final exceptionDayKeys = (a.recurrenceExceptionDates ?? const <DateTime>[])
.map((d) => '${d.year}-${d.month}-${d.day}')
.toSet();
for (final occUtc in parsed.getInstances(start: anchorUtc)) {
if (!occUtc.isBefore(weekEndUtc)) break;
if (occUtc.isBefore(weekStartUtc)) continue;
for (final occUtc in RecurrenceOccurrences.between(
rule,
anchorUtc,
weekStartUtc,
weekEndUtc,
)) {
final occLocal = occUtc.toLocal();
if (exceptionDayKeys.contains(
'${occLocal.year}-${occLocal.month}-${occLocal.day}',
+6 -5
View File
@@ -266,11 +266,12 @@ class _ViewingBanner extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isFavorite = context
.watch<SettingsCubit>()
.val()
.timetableFavoritesSettings
.isFavorite(element.type, element.id);
final isFavorite = context.select(
(SettingsCubit c) => c.state.timetableFavoritesSettings.isFavorite(
element.type,
element.id,
),
);
final onColor = theme.colorScheme.onSecondaryContainer;
// Compact icon button: ~32px square, no extra padding, so the banner stays
@@ -7,10 +7,10 @@ import '../../../../extensions/date_time.dart';
import '../../../../state/app/modules/capabilities/bloc/capabilities_cubit.dart';
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../state/app/modules/timetable/bloc/timetable_state.dart';
import '../../../../storage/timetable_settings.dart';
import '../data/arbitrary_appointment.dart';
import '../data/lesson_period_schedule.dart';
import '../data/timetable_appointment_factory.dart';
import '../data/timetable_name_mode.dart';
import 'custom_workweek_calendar.dart';
import 'special_regions_builder.dart';
@@ -51,9 +51,10 @@ class TimetableCalendarViewState extends State<TimetableCalendarView> {
GlobalKey<CustomWorkWeekCalendarState>();
List<Appointment>? _cachedAppointments;
// TimetableSettings and List define no `==`, so record equality degrades to
// the same identity checks the cache always used.
(int, TimetableSettings, List<CustomTimetableEvent>, bool)? _cacheKey;
// Settings are keyed by the values the factory reads: the settings object is
// re-created on every settings write, so its identity would miss the cache
// for unrelated changes. The event list has no `==` and compares by identity.
(int, bool, TimetableNameMode, List<CustomTimetableEvent>, bool)? _cacheKey;
// Stable identities let the calendar reuse its per-week pages across
// rebuilds; rebuilding these every frame would invalidate that cache.
@@ -71,13 +72,16 @@ class TimetableCalendarViewState extends State<TimetableCalendarView> {
}
List<Appointment> _appointments(TimetableState state) {
final timetableSettings = context
.watch<SettingsCubit>()
.val()
.timetableSettings;
final (connectDoubleLessons, nameMode) = context.select(
(SettingsCubit c) => (
c.state.timetableSettings.connectDoubleLessons,
c.state.timetableSettings.timetableNameMode,
),
);
final key = (
state.dataVersion,
timetableSettings,
connectDoubleLessons,
nameMode,
widget.customEvents,
widget.showClassInsteadOfTeacher,
);
@@ -91,7 +95,7 @@ class TimetableCalendarViewState extends State<TimetableCalendarView> {
customEvents: widget.customEvents,
subjects: state.subjects?.result ?? const [],
holidays: state.schoolHolidays?.result ?? const [],
settings: timetableSettings,
settings: context.read<SettingsCubit>().val().timetableSettings,
now: DateTime.now(),
showClassInsteadOfTeacher: widget.showClassInsteadOfTeacher,
).build();