From b413fe05de839faa8042ea99f354ab87f8ebfd73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Mon, 28 Sep 2026 12:51:28 +0200 Subject: [PATCH] fixed timetable ruler and day header overflowing at large system text sizes Both have fixed geometry, so their text scaling is capped at 1.3. Ruler times shrink instead of wrapping into the period number and are only shown when they fit at the current scale. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../widgets/calendar/day_header.dart | 22 +++--- .../timetable/widgets/calendar/week_grid.dart | 70 +++++++++++++------ 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/lib/view/pages/timetable/widgets/calendar/day_header.dart b/lib/view/pages/timetable/widgets/calendar/day_header.dart index 57cb421..0d6545d 100644 --- a/lib/view/pages/timetable/widgets/calendar/day_header.dart +++ b/lib/view/pages/timetable/widgets/calendar/day_header.dart @@ -13,17 +13,19 @@ class _DayHeaderStrip extends StatelessWidget { }); @override - Widget build(BuildContext context) => Row( - children: [ - SizedBox(width: rulerWidth), - for (var d = 0; d < 5; d++) - Expanded( - child: _DayHeaderCell( - date: weekStart.addDays(d), - today: today, + // Fixed-height strip with a 28px day circle: unclamped accessibility + // sizes overflow it. + Widget build(BuildContext context) => MediaQuery.withClampedTextScaling( + maxScaleFactor: 1.3, + child: Row( + children: [ + SizedBox(width: rulerWidth), + for (var d = 0; d < 5; d++) + Expanded( + child: _DayHeaderCell(date: weekStart.addDays(d), today: today), ), - ), - ], + ], + ), ); } diff --git a/lib/view/pages/timetable/widgets/calendar/week_grid.dart b/lib/view/pages/timetable/widgets/calendar/week_grid.dart index e2c6e0e..7e36196 100644 --- a/lib/view/pages/timetable/widgets/calendar/week_grid.dart +++ b/lib/view/pages/timetable/widgets/calendar/week_grid.dart @@ -95,20 +95,24 @@ class _PeriodRuler extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - return SizedBox( - width: width, - child: Stack( - clipBehavior: Clip.none, - children: [ - for (final period in schedule.periods) - Positioned( - top: layout.topOf(period), - height: layout.heightOf(period), - left: 0, - right: 0, - child: _PeriodLabel(period: period, theme: theme), - ), - ], + // Fixed ruler width and period heights: past this the labels overlap. + return MediaQuery.withClampedTextScaling( + maxScaleFactor: 1.3, + child: SizedBox( + width: width, + child: Stack( + clipBehavior: Clip.none, + children: [ + for (final period in schedule.periods) + Positioned( + top: layout.topOf(period), + height: layout.heightOf(period), + left: 0, + right: 0, + child: _PeriodLabel(period: period, theme: theme), + ), + ], + ), ), ); } @@ -155,7 +159,11 @@ class _PeriodLabel extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { - final showTimes = constraints.maxHeight >= 38; + // Both times plus the number, at the current text scale (9 + 9 + 14 + // plus the 3px insets and some air — 38px at scale 1). + final scaler = MediaQuery.textScalerOf(context); + final needed = 2 * scaler.scale(9) + scaler.scale(14) + 6; + final showTimes = constraints.maxHeight >= needed; return DecoratedBox( decoration: BoxDecoration( border: Border(top: BorderSide(color: dividerColor, width: 0.5)), @@ -169,11 +177,10 @@ class _PeriodLabel extends StatelessWidget { top: 3, left: 0, right: 0, - child: Text( + child: _timeText( _format(period.start), - style: timeStyle, - textAlign: TextAlign.center, - textHeightBehavior: tightTextHeight, + timeStyle, + tightTextHeight, ), ), Text( @@ -191,11 +198,10 @@ class _PeriodLabel extends StatelessWidget { bottom: 3, left: 0, right: 0, - child: Text( + child: _timeText( _format(period.end), - style: timeStyle, - textAlign: TextAlign.center, - textHeightBehavior: tightTextHeight, + timeStyle, + tightTextHeight, ), ), ], @@ -205,6 +211,24 @@ class _PeriodLabel extends StatelessWidget { ); } + /// The ruler is narrow: a scaled-up time must shrink, never wrap into the + /// period number. + static Widget _timeText( + String text, + TextStyle? style, + TextHeightBehavior heightBehavior, + ) => FittedBox( + fit: BoxFit.scaleDown, + child: Text( + text, + style: style, + maxLines: 1, + softWrap: false, + textAlign: TextAlign.center, + textHeightBehavior: heightBehavior, + ), + ); + static String _format(TimeOfDay t) => '${t.hour.toString().padLeft(2, '0')}:${t.minute.toString().padLeft(2, '0')}'; }