Files
clockula/CHANGELOG.md
T
makiolaj 319d176ae8 docs: the timers, and the counts checked against the gate
ARCHITECTURE gains §14 for timers and the ring package's new shape. The test
counts were written before the review's fixes landed; they now match what the
gate actually runs.
2026-09-12 16:49:05 +02:00

9.3 KiB

Changelog

All notable changes to Clockula are documented here.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. Tag sections feed the release notes — see 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.
  • The timers tab, for real: several timers at once, each with its own label, length and sound, and a keypad that sets one in a couple of taps — with saved presets you can add to and remove from as you go. A timer starts the moment you press Start, so an accidental tap leaves nothing behind to delete.
  • Pause, resume, reset and "+1 min" on every timer, from the row, from the live pill and from the notification — and "+1 min" on a timer that has just rung starts it again with a whole minute, rather than handing back a paused timer you have to press Start on.
  • A notification that counts the timer down without waking the device every second: the system draws the ticking, so Clockula posts once when something actually changes. It carries the same two buttons the row does, and they work with the app closed.
  • A timer keeps counting across a reboot and rings when you come back — the countdown is anchored on the device's uptime, so changing the system clock cannot move it in either direction. Change the clock while a timer runs and the notification's countdown follows the change instead of going wrong.
  • Two timers finishing together share one sound and one ten-minute window, and each is stopped on its own, so you can still tell which one you have dealt with. A timer left ringing goes quiet after ten minutes but stays finished, so you can come back and add a minute to it — and the next timer to finish rings for itself rather than inheriting that silence.
  • A timer that finishes while an alarm is ringing waits its turn instead of talking over it: it is still marked finished, its notification says so, and it starts sounding the moment the alarm is done.
  • Progress on each timer card is drawn by the Expressive wavy indicator, and the wave itself is the state — it flattens when you pause and when the timer is done.