From 6d235e097420c4b63b4f83c8e13ee549efc5ea37 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Wed, 21 Oct 2026 19:40:22 +0200 Subject: [PATCH] fix(worldclock): fit the seconds time through px, and leave the default wrapping From Android 14 large font scales are non-linear, so scaling the sp size by the width ratio still overflowed the cap; the size is now worked out in px and converted back. Without seconds the row's time wraps as it did before instead of ellipsizing. --- .../clockula/ui/worldclock/WorldClockRow.kt | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/de/jeanlucmakiola/clockula/ui/worldclock/WorldClockRow.kt b/app/src/main/java/de/jeanlucmakiola/clockula/ui/worldclock/WorldClockRow.kt index 7bf6ef4..61a884d 100644 --- a/app/src/main/java/de/jeanlucmakiola/clockula/ui/worldclock/WorldClockRow.kt +++ b/app/src/main/java/de/jeanlucmakiola/clockula/ui/worldclock/WorldClockRow.kt @@ -148,9 +148,11 @@ internal fun WorldClockRow( // Tabular, because M7 made the headline role tabular // app-wide: a column of times must not jitter as it ticks. style = timeStyle.style, - maxLines = 1, - softWrap = false, - overflow = TextOverflow.Ellipsis, + // One line only when capped (seconds on); without seconds + // the time wraps at a huge font scale, as it always did. + maxLines = if (timeStyle.capped) 1 else Int.MAX_VALUE, + softWrap = !timeStyle.capped, + overflow = if (timeStyle.capped) TextOverflow.Ellipsis else TextOverflow.Clip, // The row's description already says the time, to the // minute; the ticking text itself stays out of the tree. modifier = Modifier @@ -169,7 +171,9 @@ internal fun WorldClockRow( /** How a row draws its time; the same for every row, so the screen builds it once. */ @Immutable -internal data class RowTimeStyle(val style: TextStyle, val maxWidth: Dp) +internal data class RowTimeStyle(val style: TextStyle, val maxWidth: Dp) { + val capped: Boolean get() = maxWidth != Dp.Infinity +} /** Wide enough for "12:59:59 PM" at the default scale; the city keeps the rest. */ private val SecondsMaxWidth = 168.dp @@ -200,7 +204,13 @@ internal fun rememberRowTimeStyle(showSeconds: Boolean, formatTime: (LocalTime) measurer.measure(formatTime(sample), style, maxLines = 1, softWrap = false).size.width } val cap = with(density) { SecondsMaxWidth.toPx() } - val fitted = if (width <= cap) style else style.copy(fontSize = style.fontSize * (cap / width)) + // Through px and back, not by scaling the sp value: from Android 14 + // large font scales are non-linear, so sp and px are not proportional. + val fitted = if (width <= cap) { + style + } else { + style.copy(fontSize = with(density) { (style.fontSize.toPx() * cap / width).toSp() }) + } RowTimeStyle(fitted, SecondsMaxWidth) } }