fix(worldclock): name offset-set zones by their real offset everywhere
The Etc/GMT-n naming fix only covered the local row. A home that follows a device set by UTC offset still put "GMT-9" under a UTC+9 face. The rule now lives in the one place every row and the face take their city from.
This commit is contained in:
1 parent
f46b7e1e37
commit
40b4c9e2e4
3 files changed
+30
-24
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package de.jeanlucmakiola.clockula.ui.worldclock
|
||||
|
||||
import de.jeanlucmakiola.clockula.domain.WorldClock
|
||||
import de.jeanlucmakiola.clockula.domain.Zones
|
||||
import de.jeanlucmakiola.clockula.domain.isKnownZone
|
||||
import de.jeanlucmakiola.clockula.domain.worldclock.DayLabel
|
||||
import de.jeanlucmakiola.clockula.domain.worldclock.DayNight
|
||||
@@ -88,7 +89,7 @@ internal object WorldClockRows {
|
||||
WorldClockRowState(
|
||||
id = clock.id,
|
||||
zoneId = clock.zoneId,
|
||||
name = clock.label ?: cityOf(clock.zoneId, entries),
|
||||
name = clock.label ?: cityOf(clock.zoneId, entries, now),
|
||||
time = comparison?.localDateTime?.toLocalTime()?.truncatedTo(ChronoUnit.MINUTES),
|
||||
offset = comparison?.let { ZoneOffsetFormat.labelFor(it.offsetMinutes) },
|
||||
day = comparison?.let { ZoneOffsetFormat.dayLabelFor(it.dayDifference) },
|
||||
@@ -101,10 +102,6 @@ internal object WorldClockRows {
|
||||
* The automatic local clock's row for [deviceZone], read against home like
|
||||
* any other row. Its [WorldClockRowState.id] is [LOCAL_ROW_ID], which no
|
||||
* stored row can have.
|
||||
*
|
||||
* A device set by UTC offset rather than by city (Android 13+ offers it)
|
||||
* reports an id like `Etc/GMT-9`, whose last segment is no city and has
|
||||
* its sign reversed, so such a row is named by its offset ("GMT+9").
|
||||
*/
|
||||
fun local(
|
||||
deviceZone: ZoneId,
|
||||
@@ -112,20 +109,13 @@ internal object WorldClockRows {
|
||||
now: Instant,
|
||||
entries: Map<String, ZoneEntry>,
|
||||
zoneNames: Map<String, String?>,
|
||||
): WorldClockRowState {
|
||||
val name = if (ZoneCatalog.hasPlaceName(deviceZone.id)) {
|
||||
null
|
||||
} else {
|
||||
ZoneOffsetFormat.gmtLabel(ZoneComparisons.utcOffsetMinutes(deviceZone, now))
|
||||
}
|
||||
return from(
|
||||
clocks = listOf(WorldClock(id = LOCAL_ROW_ID, zoneId = deviceZone.id, label = name, sortOrder = 0)),
|
||||
homeZone = homeZone,
|
||||
now = now,
|
||||
entries = entries,
|
||||
zoneNames = zoneNames,
|
||||
).single()
|
||||
}
|
||||
): WorldClockRowState = from(
|
||||
clocks = listOf(WorldClock(id = LOCAL_ROW_ID, zoneId = deviceZone.id, label = null, sortOrder = 0)),
|
||||
homeZone = homeZone,
|
||||
now = now,
|
||||
entries = entries,
|
||||
zoneNames = zoneNames,
|
||||
).single()
|
||||
|
||||
/** Room ids start at 1, so a row with this id is never a stored one. */
|
||||
const val LOCAL_ROW_ID: Long = -1L
|
||||
@@ -143,13 +133,22 @@ internal object WorldClockRows {
|
||||
val local = now.toJavaInstant().atZone(homeZone).toLocalTime().truncatedTo(ChronoUnit.SECONDS)
|
||||
return HomeFaceState(
|
||||
zoneId = homeZone.id,
|
||||
city = cityOf(homeZone.id, entries),
|
||||
city = cityOf(homeZone.id, entries, now),
|
||||
zoneName = zoneNames[homeZone.id],
|
||||
time = local,
|
||||
dayFraction = DayNight.fractionAt(local),
|
||||
)
|
||||
}
|
||||
|
||||
private fun cityOf(zoneId: String, entries: Map<String, ZoneEntry>): String =
|
||||
entries[zoneId]?.city ?: ZoneCatalog.cityFallbackFor(zoneId)
|
||||
/**
|
||||
* A device set by UTC offset rather than by city (Android 13+ offers it)
|
||||
* reports an id like `Etc/GMT-9`, whose last segment is no place and has
|
||||
* its sign reversed, so such a zone is named by its real offset ("GMT+9").
|
||||
*/
|
||||
private fun cityOf(zoneId: String, entries: Map<String, ZoneEntry>, now: Instant): String =
|
||||
if (!ZoneCatalog.hasPlaceName(zoneId) && Zones.isValid(zoneId)) {
|
||||
ZoneOffsetFormat.gmtLabel(ZoneComparisons.utcOffsetMinutes(ZoneId.of(zoneId), now))
|
||||
} else {
|
||||
entries[zoneId]?.city ?: ZoneCatalog.cityFallbackFor(zoneId)
|
||||
}
|
||||
}
|
||||
@@ -265,4 +265,11 @@ class WorldClockRowsTest {
|
||||
assertThat(local.name).isEqualTo("GMT+9")
|
||||
assertThat(local.offset).isEqualTo(OffsetLabel.Ahead(8, 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a home that follows a device set by UTC offset is named by its real offset`() {
|
||||
val home = WorldClockRows.home(ZoneId.of("Etc/GMT-9"), T0, entries, emptyMap())
|
||||
|
||||
assertThat(home.city).isEqualTo("GMT+9")
|
||||
}
|
||||
}
|
||||
@@ -2406,8 +2406,8 @@ that city already shows the local time. Home that follows the device can never
|
||||
differ from it, so with no stored home the rule is always null, and Settings ›
|
||||
Clock says so under the switch rather than hiding it. A device set by UTC
|
||||
offset rather than by city reports an id like `Etc/GMT-9`, whose last segment
|
||||
has its sign reversed, so that row is named by its real offset ("GMT+9")
|
||||
instead (`ZoneCatalog.hasPlaceName`).
|
||||
has its sign reversed, so that zone is named by its real offset ("GMT+9")
|
||||
instead, on the local row and on the face alike (`ZoneCatalog.hasPlaceName`).
|
||||
|
||||
The row is not stored. It is `WorldClockUiState.Loaded.local`, built per tick
|
||||
by the source from the same `zones.current()` read the face uses, so a
|
||||
|
||||
Reference in new issue
Block a user