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.
This commit is contained in:
makiolaj committed 2026-10-21 19:40:22 +02:00
1 parent 71875e95e4
commit 6d235e0974
1 file changed
+15 -5
@@ -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)
}
}