fix(alarms): let a silent alarm-set announcement go for good
An announcement whose alarm has nothing to say, such as one switched on and straight back off, is now dropped when a screen reads it. Before, it stood, and something else switching the alarm back on, such as an AlarmClock intent, would have announced it after all. A settle job that was cancelled while waiting for the monitor no longer writes. Refs #19
This commit is contained in:
1 parent
9516dc1198
commit
d2e73901c1
2 files changed
+34
-4
No files matched your search
@@ -24,11 +24,12 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -100,8 +101,12 @@ internal class AlarmSetAnnouncer @Inject constructor(
|
||||
} else {
|
||||
engine.upcoming().map { upcoming ->
|
||||
val entry = upcoming.firstOrNull { it.alarm.id == announcement.alarmId }
|
||||
AlarmSetCountdown.of(entry, wall.now())
|
||||
?.let { AlarmSetNotice(announcement.alarmId, it, announcement.sequence) }
|
||||
val countdown = AlarmSetCountdown.of(entry, wall.now())
|
||||
// Nothing to say is the answer for good: an announcement
|
||||
// left standing would speak up later, long after the
|
||||
// action, should something else switch the alarm back on.
|
||||
if (countdown == null) dropIfCurrent(announcement)
|
||||
countdown?.let { AlarmSetNotice(announcement.alarmId, it, announcement.sequence) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +126,9 @@ internal class AlarmSetAnnouncer @Inject constructor(
|
||||
pending = appScope.launch {
|
||||
delay(settle)
|
||||
synchronized(this@AlarmSetAnnouncer) {
|
||||
current.value = Announcement(alarmId, elapsed.elapsedRealtime(), ++sequence)
|
||||
// A retract or a newer request may have cancelled this one
|
||||
// after its delay, while it waited for the monitor.
|
||||
if (isActive) current.value = Announcement(alarmId, elapsed.elapsedRealtime(), ++sequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +154,10 @@ internal class AlarmSetAnnouncer @Inject constructor(
|
||||
current.update { standing -> standing?.takeUnless { it.sequence == notice.sequence } }
|
||||
}
|
||||
|
||||
private fun dropIfCurrent(announcement: Announcement) {
|
||||
current.update { standing -> standing?.takeUnless { it.sequence == announcement.sequence } }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
/** Comfortably longer than a short snackbar, so a hand-over between screens fits. */
|
||||
val FRESH_FOR = 10.seconds
|
||||
|
||||
@@ -281,6 +281,25 @@ class AlarmsViewModelTest {
|
||||
assertThat(viewModel.alarmSetNotice.first()?.alarmId).isEqualTo(1L)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an announcement that fell silent does not speak up when something else re-enables the alarm`(
|
||||
@TempDir tempDir: Path,
|
||||
) = runTest(main.dispatcher) {
|
||||
val harness = alarmEngineHarness(tempDir)
|
||||
harness.givenAlarm(id = 1L, hour = 7, enabled = false)
|
||||
val viewModel = viewModel(harness)
|
||||
advanceUntilIdle()
|
||||
viewModel.onToggleEnabled(1L, enabled = true)
|
||||
viewModel.onToggleEnabled(1L, enabled = false)
|
||||
advanceUntilIdle()
|
||||
check(viewModel.alarmSetNotice.first() == null)
|
||||
|
||||
// An AlarmClock intent switching it back on: intents never announce.
|
||||
harness.alarms.setEnabled(1L, enabled = true)
|
||||
|
||||
assertThat(viewModel.alarmSetNotice.first()).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `adding an alarm leaves the announcement to the editor`(@TempDir tempDir: Path) =
|
||||
runTest(main.dispatcher) {
|
||||
|
||||
Reference in new issue
Block a user