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) <noreply@anthropic.com>
This commit is contained in:
2026-09-28 12:51:28 +02:00
co-authored by Claude Opus 5.5
parent f98a6979fb
commit 38a651f916
4 changed files with 45 additions and 9 deletions
@@ -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)
@@ -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
@@ -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")
@@ -201,12 +201,15 @@ private struct WidgetSurface<Content: View>: 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)