From 38a651f916b407d0d024088b196b4d569ca3ec48 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 missing period times in the ios widget ruler and unreadable tiles on tinted and clear home screens A .systemLarge widget only gets ~27pt per period, below the 30pt threshold shared with Android, so iOS now shows the times from 24pt with a tighter cell. In non-full-color rendering modes the opaque tiles and the today circle flattened into solid slabs hiding their text; they are drawn translucent with an outline there and use the light-text palette. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../TimetableDayView.swift | 23 +++++++++++++++++-- .../TimetableLayout.swift | 5 +++- .../TimetableWeekView.swift | 15 ++++++++++-- .../TimetableWidgetExtension.swift | 11 +++++---- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/ios/TimetableWidgetExtension/TimetableDayView.swift b/ios/TimetableWidgetExtension/TimetableDayView.swift index 1817a33..68da820 100644 --- a/ios/TimetableWidgetExtension/TimetableDayView.swift +++ b/ios/TimetableWidgetExtension/TimetableDayView.swift @@ -147,7 +147,8 @@ struct PeriodRuler: View { .font(.system(size: timeFont)) .foregroundStyle(palette.textSecondary) .lineLimit(1) - .padding(.vertical, 2) + .minimumScaleFactor(0.8) + .padding(.vertical, 1) } } .frame(width: RULER_WIDTH, height: height) @@ -304,6 +305,8 @@ private struct LessonTile: View { let metrics: TileMetrics let layout: TileTextLayout + @Environment(\.widgetRenderingMode) private var renderingMode + private static let cancelledRed = Color(red: 244 / 255, green: 67 / 255, blue: 54 / 255).opacity(200 / 255) @@ -326,7 +329,7 @@ private struct LessonTile: View { .padding(.vertical, TILE_PADDING_V) .frame(maxWidth: .infinity, alignment: .topLeading) .frame(height: height, alignment: .topLeading) - .background(lesson.tileColor) + .background { tileBackground(shape) } .clipShape(shape) .overlay(alignment: .bottomTrailing) { if let count = lesson.siblingCount, count > 0 { @@ -357,6 +360,22 @@ private struct LessonTile: View { .padding(.horizontal, TILE_MARGIN_H) } + /// Tinted / clear home screens flatten an opaque colour block into a + /// solid slab the white text disappears on; a translucent fill with an + /// outline keeps tile and text apart in every rendering mode. + @ViewBuilder + private func tileBackground(_ shape: RoundedRectangle) -> some View { + if renderingMode == .fullColor { + lesson.tileColor + } else { + ZStack { + shape.fill(Color.white.opacity(0.18)) + shape.strokeBorder(Color.white.opacity(0.55), lineWidth: 1) + } + .widgetAccentable() + } + } + private var titleRow: some View { HStack(alignment: .center, spacing: 3) { Text(layout.title) diff --git a/ios/TimetableWidgetExtension/TimetableLayout.swift b/ios/TimetableWidgetExtension/TimetableLayout.swift index b37b28a..954027b 100644 --- a/ios/TimetableWidgetExtension/TimetableLayout.swift +++ b/ios/TimetableWidgetExtension/TimetableLayout.swift @@ -47,7 +47,10 @@ let TITLE_WRAP_BELOW_FONT: CGFloat = 8 let BADGE_WIDTH: CGFloat = 16 let BADGE_HEIGHT: CGFloat = 11 -let RULER_TIMES_MIN_CELL: CGFloat = 30 +/// Lower than Android's 30dp: a .systemLarge widget only gets ~27pt per +/// period, so iOS packs the ruler cell tighter (see PeriodRuler.cell) +/// instead of dropping the times. +let RULER_TIMES_MIN_CELL: CGFloat = 24 let BREAK_ICON_MIN_HEIGHT: CGFloat = 12 /// Space the holiday column keeps free above and below the rotated name for diff --git a/ios/TimetableWidgetExtension/TimetableWeekView.swift b/ios/TimetableWidgetExtension/TimetableWeekView.swift index 6a55873..1938f51 100644 --- a/ios/TimetableWidgetExtension/TimetableWeekView.swift +++ b/ios/TimetableWidgetExtension/TimetableWeekView.swift @@ -4,6 +4,7 @@ import WidgetKit struct TimetableWeekView: View { let entry: TimetableEntry @Environment(\.widgetPalette) private var palette + @Environment(\.widgetRenderingMode) private var renderingMode var body: some View { ZStack { @@ -115,13 +116,23 @@ struct TimetableWeekView: View { .lineLimit(1) Text("\(Calendar.current.component(.day, from: day))") .font(.system(size: 11, weight: isToday ? .bold : .regular)) - .foregroundStyle(isToday ? palette.onAccent : palette.textPrimary) + .foregroundStyle(isToday ? todayNumberColor : palette.textPrimary) .lineLimit(1) .frame(width: 18, height: 18) - .background(Circle().fill(isToday ? palette.accent : Color.clear)) + .background(Circle().fill(isToday ? todayCircleColor : Color.clear)) } } + // An opaque accent circle flattens to the same shade as its number on + // tinted / clear home screens; keep the circle translucent there. + private var todayCircleColor: Color { + renderingMode == .fullColor ? palette.accent : Color.white.opacity(0.3) + } + + private var todayNumberColor: Color { + renderingMode == .fullColor ? palette.onAccent : palette.textPrimary + } + private func placeholder(_ message: String) -> some View { VStack(spacing: 4) { Text("Marianum Stundenplan") diff --git a/ios/TimetableWidgetExtension/TimetableWidgetExtension.swift b/ios/TimetableWidgetExtension/TimetableWidgetExtension.swift index 97c425f..35bf6be 100644 --- a/ios/TimetableWidgetExtension/TimetableWidgetExtension.swift +++ b/ios/TimetableWidgetExtension/TimetableWidgetExtension.swift @@ -201,12 +201,15 @@ private struct WidgetSurface: View { let entry: TimetableEntry @ViewBuilder let content: () -> Content @Environment(\.colorScheme) private var colorScheme + @Environment(\.widgetRenderingMode) private var renderingMode var body: some View { - let palette = WidgetPalette.resolve( - themeMode: entry.themeMode, - colorScheme: colorScheme - ) + // Tinted / clear home screens map every colour to its luminance, so + // the light palette's near-black text would vanish — use the dark + // palette's light text there regardless of the theme setting. + let palette = renderingMode == .fullColor + ? WidgetPalette.resolve(themeMode: entry.themeMode, colorScheme: colorScheme) + : .dark return AnyView( background(content: content(), palette: palette) .environment(\.widgetPalette, palette)