ARCHITECTURE gains §13 for the alarms screen. The test counts in §8 were written before the review's fixes landed, and M4's instrumentation count was one short; both now match what the gate actually runs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wmy1BpCKi8KeSjaWhYuCPV
114 lines
7.4 KiB
Markdown
114 lines
7.4 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to Clockula are documented here.
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
Tag sections feed the release notes — see [`docs/RELEASING.md`](docs/RELEASING.md).
|
|
|
|
## [Unreleased]
|
|
|
|
### Added
|
|
- Project skeleton: Gradle build, version catalog, Hilt, Compose and the Material 3
|
|
Expressive theme over floret-kit's `identity` module, seeded `#6B7A5C` — the
|
|
third 120° hue rotation of Calendula's slate, completing the family's palette.
|
|
- floret-kit as a git submodule wired in as a Gradle composite build.
|
|
- Crash capture and the report surface via floret-kit's `core-crash`; per-app
|
|
language support via `core-locale`.
|
|
- Launcher and notification icons: a line-art clock face carrying the family's
|
|
Calendula bloom badge.
|
|
- Full release pipeline, Codeberg-canonical from the first commit — CI,
|
|
translations, release (F-Droid repo + Codeberg release + Google Play) and
|
|
Renovate, with the F-Droid reproducibility rules intact.
|
|
- The locked specification: `docs/PLAN.md` and `docs/ROADMAP.md`.
|
|
- Preferences over floret-kit's new `core-prefs`: `SettingsPrefs` holds the
|
|
appearance slice (theme mode, dynamic colour) in a DataStore of Clockula's own,
|
|
under the family's key names. The theme now follows the stored preference —
|
|
light/dark override and dynamic colour persist across launches instead of
|
|
always following the system — and an unrelated preference write no longer
|
|
re-emits it.
|
|
- floret-kit's `core-di` supplies the `@IoDispatcher` the preference store runs
|
|
on, so Clockula no longer declares its own dispatcher qualifier.
|
|
- Clockula's own storage, headless: a Room database with `alarms`, `timers`,
|
|
`world_clocks` and `stopwatch_laps`, its schema exported and committed at
|
|
every version so each migration is reviewable and testable.
|
|
- Plain-Kotlin alarms, timers, world clocks and stopwatch runs behind four
|
|
repository interfaces exposing Flows — nothing above the data layer knows Room
|
|
exists, and a test fails the build if anyone reaches through. A corrupt row
|
|
degrades on read (a clamped time, an unknown ringtone, a rotted zone id)
|
|
rather than crashing the list it appears in.
|
|
- Alarm and timer settings are inherited, not copied: a per-alarm ringtone,
|
|
snooze, vibrate, volume ramp or dismiss challenge is an *override*, so
|
|
changing an app default later reaches every alarm the user never customised.
|
|
- The clock defaults and the stopwatch's running state now live in DataStore
|
|
alongside the appearance preferences, clamped on read as well as on write, so
|
|
a hand-edited or restored file cannot produce a setting the user could never
|
|
have chosen.
|
|
- The wall-clock / elapsed-realtime split, made explicit: alarm records follow
|
|
the system clock, while running timers and the stopwatch are anchored to time
|
|
since boot. Changing the device's time — forwards or backwards — cannot warp
|
|
either, and a timer that survives a reboot falls back to its wall-clock
|
|
estimate and says so instead of vanishing.
|
|
- Alarms that ring. A repeat schedule that is re-resolved against the device's
|
|
zone every time anything moves, so the clock going forwards, backwards or
|
|
through a daylight-saving transition cannot lose one: a 02:30 alarm on a
|
|
spring-forward night rings at 03:30 rather than vanishing, and on a fall-back
|
|
night rings once rather than twice.
|
|
- Skip-next-occurrence that skips exactly one occurrence, snooze with a
|
|
per-alarm interval and limit, and a snooze that is still kept after a reboot.
|
|
- An alarm that keeps ringing through a reboot or a process kill — the ring is
|
|
rebuilt from storage, not from memory — and one that still rings when the
|
|
full-screen-intent or notification permission is denied. The chain of
|
|
fallbacks ends in vibration, never in silence.
|
|
- The post-reboot repair: a running timer no longer counts down from an anchor
|
|
the reboot killed, and the stopwatch no longer invents a segment it never ran.
|
|
- The app shell: four tabs — alarms, timers, stopwatch, world clock — under a
|
|
navigation bar that becomes a rail on a tablet, chosen by the window's size
|
|
rather than by hand. Back from a tab goes home to Alarms; back from Alarms
|
|
leaves the app, and the predictive-back gesture previews whichever of the two
|
|
is actually about to happen.
|
|
- The live pill: whatever is counting is visible from every tab, and pausable
|
|
and stoppable without going to find the row that owns it. It stays up while
|
|
paused — a control that vanishes under the thumb that pressed it is no control
|
|
— shows how many other timers are running behind it, and flips a timer that
|
|
reaches zero to "finished" the moment it does, rather than counting into
|
|
negative time. Stop resets; it never deletes a timer the user configured.
|
|
- The real ring screen, over the lock screen with the display kept on for
|
|
exactly as long as the window lives: the time, the label, snooze, and an
|
|
optional dismiss challenge — a two-term sum, or a two-second hold — that can
|
|
never strand anyone. Three wrong answers or sixty seconds of ringing, either
|
|
one, opens a way out; snooze is never gated; solving the challenge dismisses
|
|
on the spot instead of asking twice; and the hold completes from an
|
|
accessibility click, so a screen reader is not locked out of its own alarm.
|
|
Back cannot silence an alarm.
|
|
- The first Compose motion: fade-through between peer tabs, the kit's springs for
|
|
the pill coming and going and for the challenge block opening, all of which
|
|
already stand down when the system's "remove animations" setting is on.
|
|
- Notification permission is asked for once, on first launch, and the fact that
|
|
it was asked is recorded rather than guessed at.
|
|
- The alarms tab, for real: a list of your alarms that says when each one will
|
|
ring — "in 9h 12m" — and marks the next one to go off, with the repeat days
|
|
and a switch on every row. A switched-off alarm stays where it is, faded
|
|
rather than shuffled to the bottom, and the countdown keeps up on its own
|
|
without anything being saved.
|
|
- Create, edit, delete, enable and disable an alarm, applied as you make them
|
|
rather than behind a Save button: tapping + creates an alarm at the next whole
|
|
hour and opens it, every control writes at once, and back is just back.
|
|
- The Material time picker, with a keypad to type a time and the dial behind one
|
|
toggle, following the device's own 12- or 24-hour setting.
|
|
- A repeat-day selector that starts on your locale's first day of the week, not
|
|
on a hardcoded Monday, and a "skip next alarm" switch for a repeating one —
|
|
so you can sleep in on Thursday without switching the alarm off and
|
|
forgetting to switch it back.
|
|
- A per-alarm sound, vibration, gradual volume, snooze length, snooze limit and
|
|
dismiss challenge — each of which can say "follow the app default" rather than
|
|
silently copying today's default and drifting away from it later. Every row
|
|
shows what it currently resolves to.
|
|
- A ringtone picker with the device's own alarm sounds, a file you choose
|
|
yourself, and a Silent option that still vibrates — because an alarm that does
|
|
literally nothing is not an alarm. You can play a sound before taking it.
|
|
- A sound Clockula cannot read right now says so under the row, and your choice
|
|
is kept rather than quietly replaced with the default: an unmounted card comes
|
|
back. If a file you picked cannot be held onto permanently, that is disclosed
|
|
too instead of being hidden.
|