docs: mark M8 done
This commit is contained in:
+87
-13
@@ -10,18 +10,20 @@ Status legend: ✅ done · 🚧 in progress · ⬜ not started
|
||||
|
||||
## Current state (one line)
|
||||
|
||||
✅ **M7 done.** The Stopwatch tab is real: start, pause and reset, a readout to
|
||||
hundredths whose fraction is drawn smaller than its seconds, laps with their
|
||||
split and their running total newest-first with the fastest and slowest marked,
|
||||
the lap in progress as its own counting row, and a silent `specialUse`
|
||||
foreground service whose Lap and Pause work with the app closed — its ticking
|
||||
drawn by the system, so it costs no battery to keep accurate. A stopwatch that
|
||||
meets a reboot comes back **paused at what it banked**, with every lap intact,
|
||||
rather than inventing the time it lost; a clock change cannot move it at all.
|
||||
M0's promise that the big-readout typography would be settled against a working
|
||||
stopwatch is kept, and every readout in the app now sits in fixed columns. One
|
||||
tab is still an empty state: **M8** (world clock — the zone list, ICU names,
|
||||
offsets and the analog face) is next.
|
||||
✅ **M8 done.** The World clock tab is real, and **every tab now has its own
|
||||
content** — no empty state is left anywhere in the app. A hero analog face shows
|
||||
your home zone, and its dial morphs between a circle and a sun with the hour
|
||||
there, so a glance answers "is it the middle of the night" without a line of
|
||||
text saying so — the app's one deliberate `MaterialShapes` showpiece, spent on
|
||||
information rather than decoration. Cities come from the device's own tzdata,
|
||||
named and localised through ICU behind a seam, searched by word-prefix over
|
||||
folded text so ASCII finds São Paulo; each row carries its time, its offset and
|
||||
its day difference **relative to home**, all read at the instant so both sides
|
||||
of a daylight-saving change are right on the day. The list reorders by drag or
|
||||
by a move-up/move-down action a screen reader can reach, and the home zone is
|
||||
set by hand or left following the device. **M9** (system interop — the full
|
||||
`android.provider.AlarmClock` contract and its hostile-input validation) is
|
||||
next.
|
||||
|
||||
---
|
||||
|
||||
@@ -411,12 +413,84 @@ M7 owns only how the paused result is presented.
|
||||
the gate but have **never run on hardware**, as no device was attached — the
|
||||
same caveat M5's seven and M6's four carry.
|
||||
|
||||
### ⬜ M8 — World clock
|
||||
### ✅ M8 — World clock
|
||||
IANA zone list with search, ICU-localised city and zone display names, offset and
|
||||
day-difference relative to home, reorder, home-zone handling. The analog face
|
||||
built from `MaterialShapes` / `androidx.graphics.shapes` — the app's one
|
||||
deliberate showpiece.
|
||||
|
||||
✅ 1 139 JVM tests, 171 of them new, and **still no Robolectric** — kept now
|
||||
for a fourth screen, and this was the milestone most tempted to break it,
|
||||
because ICU and `Canvas` both look like they need a device. They do not:
|
||||
everything ICU answers is behind `ZoneNames` (faked, with per-method call
|
||||
counters and a `failEverything` flag), everything the face draws is
|
||||
`DrawScope` calls over `AnalogFace`'s angles and `DayNight`'s fraction — two
|
||||
pure objects asserted at every minute of the day without a pixel — and
|
||||
everything the list and the picker decide is `WorldClockRows`,
|
||||
`ZonePickerRows`, `ZoneSearch`, `ZoneComparisons`, `ZoneCatalog` and
|
||||
`WorldClocks`. Every write is a `WorldClockViewModel` method over the **real**
|
||||
`WorldClockRepositoryImpl` across `FakeWorldClockDao` (so `addIfAbsent` and
|
||||
`reorder`'s real transactions run) and a real DataStore under a `@TempDir`.
|
||||
Three new `ArchitectureRulesTest` rules; the four new instrumentation tests
|
||||
bring the compiled total to 40.
|
||||
|
||||
The decisions worth knowing: **there is no engine and must not be one** — a
|
||||
world clock owns no AlarmManager slot, no service and no ring session, so a
|
||||
fourth engine would be three empty seams and a `Mutex` guarding nothing; the
|
||||
tab reads the **wall clock**, and re-reads both the instant and the device
|
||||
zone on **every tick**, which is what makes `TIME_SET` and `TIMEZONE_CHANGED`
|
||||
free (no new receiver branch); the zone **ids** stay pure (through a new
|
||||
`ZoneProvider.available()`) while only the **names** cross the ICU seam, which
|
||||
is one file, `runCatching`-guarded end to end and pinned there by a build
|
||||
rule; the catalog keeps only region-based ids that are **their own canonical
|
||||
id** — so the tzdata's own canonicalisation drops Asia/Calcutta in favour of
|
||||
Asia/Kolkata and no table of ours can rot — unless the canonical id is not on
|
||||
the device at all, since ICU and tzdata are separately updatable APEX modules
|
||||
that can disagree, plus `UTC` by name; search is
|
||||
**word-prefix over folded text**, so "erl" deliberately does not find Berlin;
|
||||
the offset and day are computed **at the instant** from both zones' rules, the
|
||||
same discipline `AlarmOccurrences` uses, so Berlin↔Sydney is ten hours in
|
||||
January and eight in July; labels are **data, not strings**, so Kathmandu is
|
||||
`Ahead(4, 45)` rather than a signed 285 for a translator to interpret; the
|
||||
cadence is **200 ms** with the state truncated to the second (face) and the
|
||||
minute (rows) and `distinctUntilChanged` over it; the list is capped at
|
||||
**24**, with the cap spelled out on the screen once it is reached, because
|
||||
M3's `ExtendedFloatingActionButton` has no `enabled` to dim; and
|
||||
reduce-motion snaps the morph but **never stops the second hand**,
|
||||
because a clock whose second hand stops is a broken clock.
|
||||
|
||||
Three things outside the checklist were changed anyway, and are recorded in
|
||||
`ARCHITECTURE.md`: **`ZoneProvider` gained `available()`**, because
|
||||
`ZoneId.getAvailableZoneIds()` at a call site is the same ambient read
|
||||
`PLAN.md` §5 bans for `now()`; **`ui/common/AlarmTimeFormatter.kt` gained
|
||||
`rememberLocalTimeFormatter`** with the existing function delegating to it, so
|
||||
M5's "one 12/24-hour formatter" survives a fourth caller instead of growing a
|
||||
second answer; and **`ShellDefaults.EmptyTabScreen` was deleted**, its own
|
||||
KDoc having said it existed only until each of M5–M8 replaced its own tab —
|
||||
the world clock was its last caller.
|
||||
|
||||
No schema change at all (the database stays at v2; `WorldClockEntity`, its
|
||||
DAO, its mapper and its repository are not edited), **no new permission and no
|
||||
manifest entry**, **one** new dependency coordinate —
|
||||
`androidx.graphics:graphics-shapes:1.0.1`, pinned to the version that already
|
||||
resolved transitively, because M8 imports that package directly — and **no
|
||||
floret-kit change**: the kit stays at 0.6.0, untouched, with
|
||||
`ReorderableColumn`, `GroupedSurface`, `FullScreenPicker`, `InlineTextField`
|
||||
and `CollapsingScaffold`'s FAB slot already covering the screen.
|
||||
|
||||
Knowingly open: no rename UI for `world_clocks.label` — the column is honoured
|
||||
on read and M10's backup import will carry labels; no automatic "home" row
|
||||
while travelling (a separate feature with its own preference, and the hero
|
||||
face already follows the device); no per-city detail screen, map,
|
||||
sunrise/sunset or day-length bar — `DayNight` is a stated convention for a
|
||||
shape morph, not an ephemeris; no live times or long zone names in the picker;
|
||||
no seeded data, so a fresh install really has an empty list; no reordering by
|
||||
anything but `sort_order`; and no `MaterialShapes` on the ring screen or timer
|
||||
progress, which `PLAN.md` §8 also sanctions — the build rule makes widening
|
||||
that allowlist a deliberate edit. The four new instrumentation tests compile
|
||||
in the gate but have **never run on hardware**, as no device was attached —
|
||||
the same caveat M5's seven, M6's four and M7's four carry.
|
||||
|
||||
### ⬜ M9 — System interop
|
||||
The full `android.provider.AlarmClock` contract (`PLAN.md` §6): `SET_ALARM`,
|
||||
`SET_TIMER`, `SHOW_ALARMS`, `SHOW_TIMERS`, `DISMISS_ALARM`, `SNOOZE_ALARM`, plus
|
||||
|
||||
Reference in New Issue
Block a user