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
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
@@ -11,16 +12,19 @@ class AppointmentTile extends StatelessWidget {
final Appointment appointment;
final bool crossedOut;
/// Ticking clock; only the tile background listens, so a lesson fades to
/// the "past" look without rebuilding the text layout.
final ValueListenable<DateTime> now;
const AppointmentTile({
super.key,
required this.appointment,
required this.now,
this.crossedOut = false,
});
@override
Widget build(BuildContext context) {
final isPast = appointment.endTime.isBefore(DateTime.now());
final color = appointment.color.withAlpha(isPast ? 160 : 255);
final isCustom = appointment.id is CustomAppointment;
final description = appointment.location ?? '';
@@ -29,13 +33,19 @@ class AppointmentTile extends StatelessWidget {
child: Stack(
children: [
Positioned.fill(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
alignment: Alignment.topLeft,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: _radius,
color: color,
child: ValueListenableBuilder<DateTime>(
valueListenable: now,
builder: (context, now, child) => Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
alignment: Alignment.topLeft,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: _radius,
color: appointment.color.withAlpha(
appointment.endTime.isBefore(now) ? 160 : 255,
),
),
child: child,
),
child: _TileContent(
title: appointment.subject,
@@ -100,8 +110,10 @@ class _TileContent extends StatelessWidget {
// entirely; the coloured rectangle is enough.
if (available < titleLineHeight) return const SizedBox.shrink();
final remaining =
(available - titleLineHeight).clamp(0.0, double.infinity);
final remaining = (available - titleLineHeight).clamp(
0.0,
double.infinity,
);
final bodyLineCapacity = (remaining / bodyLineHeight).floor();
if (isCustom) {
@@ -187,7 +199,9 @@ class _AdaptiveTitle extends StatelessWidget {
maxLines: 1,
textScaler: textScaler,
)..layout();
if (probe.width > constraints.maxWidth) {
final overflows = probe.width > constraints.maxWidth;
probe.dispose();
if (overflows) {
return Text(
text,
style: baseStyle.copyWith(fontSize: minFontSize),