From 6239ca047794f7e8462d3f93929e68eb3594a97d Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Wed, 21 Oct 2026 19:45:44 +0200 Subject: [PATCH] refactor(settings): read a silence-after of an hour or more as Never A stored value of 60 minutes or more now reads as Never, which rings that long anyway. The picker no longer shows both "60 minutes" and "Never" for the same window. Also drops a redundant null check in TimerRingPolicy. Refs #17 --- .../de/jeanlucmakiola/clockula/domain/ring/SilenceAfter.kt | 7 ++++--- .../clockula/domain/timer/TimerRingPolicy.kt | 2 +- .../jeanlucmakiola/clockula/data/prefs/ClockPrefsTest.kt | 2 +- .../clockula/data/prefs/SettingsPrefsTest.kt | 3 ++- docs/ARCHITECTURE.md | 4 ++-- docs/BACKUP.md | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/de/jeanlucmakiola/clockula/domain/ring/SilenceAfter.kt b/app/src/main/java/de/jeanlucmakiola/clockula/domain/ring/SilenceAfter.kt index a61b9ab..0137a19 100644 --- a/app/src/main/java/de/jeanlucmakiola/clockula/domain/ring/SilenceAfter.kt +++ b/app/src/main/java/de/jeanlucmakiola/clockula/domain/ring/SilenceAfter.kt @@ -44,13 +44,14 @@ object SilenceAfter { /** * What a stored value is read and written as, from a picker, a hand-edited - * file or a backup. Too long is the hard stop, which is what it would ring - * for anyway. Negative is nothing anyone chose, so it is the default rather + * file or a backup. The hard stop or longer is "Never", which rings that + * long anyway, so the picker never shows two names for one window. Negative is nothing anyone chose, so it is the default rather * than the clamp's floor, which would be "Never". */ fun sanitise(minutes: Int): Int = when { minutes < MINUTES.first -> DEFAULT_MINUTES - else -> minutes.coerceAtMost(MINUTES.last) + minutes >= HARD_STOP_MINUTES -> NEVER + else -> minutes } /** The ring window [minutes] stands for, sanitised first so the engines never see an unofferable value. */ diff --git a/app/src/main/java/de/jeanlucmakiola/clockula/domain/timer/TimerRingPolicy.kt b/app/src/main/java/de/jeanlucmakiola/clockula/domain/timer/TimerRingPolicy.kt index d55a816..2b67e41 100644 --- a/app/src/main/java/de/jeanlucmakiola/clockula/domain/timer/TimerRingPolicy.kt +++ b/app/src/main/java/de/jeanlucmakiola/clockula/domain/timer/TimerRingPolicy.kt @@ -68,7 +68,7 @@ object TimerRingPolicy { // Auto-silence before suppression: a window that has run out stays run // out, and an alarm ringing over it must not hand it a fresh one. val window = defaults.timerSilenceAfter - if (soundingSince != null && isLapsed(soundingSince, now, window)) { + if (soundingSince != null && now - soundingSince >= window) { return TimerRingOutcome( TimerRingDecision.AutoSilenced(subject.timer.id), // Raising the setting later cannot start a silenced timer ringing again. diff --git a/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/ClockPrefsTest.kt b/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/ClockPrefsTest.kt index 11817ca..f52c7cc 100644 --- a/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/ClockPrefsTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/ClockPrefsTest.kt @@ -161,7 +161,7 @@ class ClockPrefsTest { prefs.setAlarmSilenceAfterMinutes(999) prefs.setTimerSilenceAfterMinutes(-3) - assertThat(prefs.defaults.first().alarmSilenceAfterMinutes).isEqualTo(60) + assertThat(prefs.defaults.first().alarmSilenceAfterMinutes).isEqualTo(SilenceAfter.NEVER) assertThat(prefs.defaults.first().timerSilenceAfterMinutes).isEqualTo(SilenceAfter.DEFAULT_MINUTES) dataStore.updateData { stored -> diff --git a/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/SettingsPrefsTest.kt b/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/SettingsPrefsTest.kt index 2abb2d3..084ee05 100644 --- a/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/SettingsPrefsTest.kt +++ b/app/src/test/java/de/jeanlucmakiola/clockula/data/prefs/SettingsPrefsTest.kt @@ -7,6 +7,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import de.jeanlucmakiola.clockula.domain.ClockDefaults +import de.jeanlucmakiola.clockula.domain.ring.SilenceAfter import de.jeanlucmakiola.clockula.domain.backup.BackupSettings import de.jeanlucmakiola.floret.prefs.Appearance import de.jeanlucmakiola.floret.prefs.PrefStore @@ -91,7 +92,7 @@ class SettingsPrefsTest { assertThat(prefs.currentDefaults().volumeRampSeconds).isEqualTo(60) assertThat(prefs.currentDefaults().alarmRingtoneUri).isNull() assertThat(prefs.currentDefaults().alarmSilenceAfterMinutes).isEqualTo(25) - assertThat(prefs.currentDefaults().timerSilenceAfterMinutes).isEqualTo(60) + assertThat(prefs.currentDefaults().timerSilenceAfterMinutes).isEqualTo(SilenceAfter.NEVER) assertThat(prefs.timerPresets.first()).containsExactly(1.minutes, 5.minutes).inOrder() } diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0148559..f4eff10 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1175,8 +1175,8 @@ from ringing until its battery is flat, what bounds the ring services' wake locks, and what keeps a reboot hours later from resuming a ring nobody was there for. So "Never" maps to `SilenceAfter.HARD_STOP` (60 minutes), longer than any finite choice, and the settings hint says so in words. Stored values -go through `SilenceAfter.sanitise` on read, on write and from a backup: over 60 -is 60, so no value can make a ring outlast the hard stop, and a negative one is +go through `SilenceAfter.sanitise` on read, on write and from a backup: 60 or more +is "Never", so no value can make a ring outlast the hard stop, and a negative one is the default rather than the clamp's floor, which would be "Never". Changing the setting mid-ring applies at once. The settings screen writes it diff --git a/docs/BACKUP.md b/docs/BACKUP.md index c5d7799..ff25d84 100644 --- a/docs/BACKUP.md +++ b/docs/BACKUP.md @@ -151,8 +151,8 @@ other unknown field. are how long a ringing alarm or a finished timer keeps going before it stops on its own: whole minutes, with `0` meaning "Never" (which still stops after an hour). A file without them, from before the setting existed, imports as `10`, -the value it was made with. A value over 60 reads as 60 (which is what Never -rings for anyway); a negative one reads as the default, 10. +the value it was made with. A value of 60 or more reads as 0, "Never" (which +rings for that long anyway); a negative one reads as the default, 10. Every numeric/duration value is clamped on *apply* using the same ranges and encoding as the existing preference setters, never on parse.