fix(worldclock): leave a fitting margin and drop the zone-cache reset
The fitted seconds size keeps five percent spare, since hinted glyph advances do not scale exactly. The receiver no longer resets the process's default zone: that was speculative, and it changed global state from a UI flow. The settings state takes the seconds flag without a default, and a garbled KDoc sentence is fixed.
This commit is contained in:
1 parent
6d235e0974
commit
78da94d775
5 files changed
+9
-13
No files matched your search
@@ -10,7 +10,6 @@ import de.jeanlucmakiola.clockula.domain.time.ClockChanges
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@@ -28,11 +27,6 @@ class AndroidClockChanges @Inject constructor(
|
||||
override fun changes(): Flow<Unit> = callbackFlow {
|
||||
val receiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
// The process's cached default zone is reset by a separate
|
||||
// one-way call that can land after this broadcast; resetting it
|
||||
// here too (as ActivityThread does) means the rebuild this
|
||||
// triggers reads the new zone, not the old one.
|
||||
if (intent.action == Intent.ACTION_TIMEZONE_CHANGED) TimeZone.setDefault(null)
|
||||
trySend(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ internal sealed interface SettingsUiState {
|
||||
val defaults: ClockDefaults,
|
||||
val selfCheckProblemCount: Int? = null,
|
||||
/** The world clock's "Display time with seconds" (#23); not a clock default. */
|
||||
val worldClockSeconds: Boolean = false,
|
||||
val worldClockSeconds: Boolean,
|
||||
) : SettingsUiState
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,8 @@ internal data class RowTimeStyle(val style: TextStyle, val maxWidth: Dp) {
|
||||
val capped: Boolean get() = maxWidth != Dp.Infinity
|
||||
}
|
||||
|
||||
private const val FitMargin = 0.95f
|
||||
|
||||
/** Wide enough for "12:59:59 PM" at the default scale; the city keeps the rest. */
|
||||
private val SecondsMaxWidth = 168.dp
|
||||
|
||||
@@ -209,7 +211,8 @@ internal fun rememberRowTimeStyle(showSeconds: Boolean, formatTime: (LocalTime)
|
||||
val fitted = if (width <= cap) {
|
||||
style
|
||||
} else {
|
||||
style.copy(fontSize = with(density) { (style.fontSize.toPx() * cap / width).toSp() })
|
||||
// A few percent spare: hinted glyph advances do not scale exactly.
|
||||
style.copy(fontSize = with(density) { (style.fontSize.toPx() * FitMargin * cap / width).toSp() })
|
||||
}
|
||||
RowTimeStyle(fitted, SecondsMaxWidth)
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ internal class WorldClockSource @Inject constructor(
|
||||
/**
|
||||
* The tab's state. Both the instant and the device zone are re-read on
|
||||
* **every tick**. [ClockChanges] restarts the tick, so `TIME_SET` and
|
||||
* `TIMEZONE_CHANGED` show at once rather than at the next minute, the next
|
||||
* wait is measured against the clock as it now reads. It sits
|
||||
* `TIMEZONE_CHANGED` show at once rather than at the next minute, and the
|
||||
* restarted ticker measures its next wait against the clock as it now
|
||||
* reads. It sits
|
||||
* outside the `flatMapLatest`, so its receiver is registered once per
|
||||
* subscription rather than once per list edit, and `onStart` lets the
|
||||
* first state through without waiting for a broadcast. [refreshes] does
|
||||
|
||||
@@ -2464,9 +2464,7 @@ arrive with the tab on screen (a network zone change on landing, split
|
||||
screen). So `ClockChanges` (`AndroidClockChanges`, a receiver registered only
|
||||
while the tab collects) restarts the tick: those two make the state re-read
|
||||
the clock and the zone at once, and the restarted ticker measures its next
|
||||
wait against the clock as it now reads. On `TIMEZONE_CHANGED` the receiver
|
||||
also resets the process's cached default zone itself, since the system's own
|
||||
reset is a separate call that can land after the broadcast. The signal is combined
|
||||
wait against the clock as it now reads. The signal is combined
|
||||
with the stored list, the home zone and the setting *outside* the
|
||||
`flatMapLatest`, so the receiver is registered once per subscription, not
|
||||
once per list edit. Each broadcast costs one extra `build`, which
|
||||
|
||||
Reference in new issue
Block a user