fix(alarms): open the ring screen when the editor's Delete is refused
Deleting a ringing alarm from the editor is refused, and a refused tap did nothing visible. It now opens the ring screen, the same way out the list's card offers.
This commit is contained in:
1 parent
7adda73a79
commit
ddec2d8ed1
4 files changed
+31
-2
No files matched your search
@@ -1,5 +1,6 @@
|
||||
package de.jeanlucmakiola.clockula.ui.alarms
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -19,6 +20,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -27,6 +29,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import de.jeanlucmakiola.clockula.R
|
||||
import de.jeanlucmakiola.clockula.domain.TimeOfDay
|
||||
import de.jeanlucmakiola.clockula.ui.common.RingtonePickerScreen
|
||||
import de.jeanlucmakiola.clockula.ui.ring.AlarmRingActivity
|
||||
import de.jeanlucmakiola.clockula.ui.common.rememberAlarmTimeFormatter
|
||||
import de.jeanlucmakiola.clockula.ui.shell.LocalLivePillInset
|
||||
import de.jeanlucmakiola.floret.components.CollapsingScaffold
|
||||
@@ -75,6 +78,17 @@ fun AlarmEditorScreen(
|
||||
if (state is AlarmEditorUiState.Gone) onBack()
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(viewModel) {
|
||||
// Delete is refused while the alarm rings; its ring screen, with the
|
||||
// dismiss challenge, is the way out, as it is from the list's card.
|
||||
viewModel.openRingScreen.collect {
|
||||
context.startActivity(
|
||||
Intent(context, AlarmRingActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
CollapsingScaffold(
|
||||
title = stringResource(R.string.editor_title),
|
||||
onBack = onBack,
|
||||
|
||||
@@ -18,11 +18,14 @@ import de.jeanlucmakiola.clockula.ui.common.RingtonePicker
|
||||
import de.jeanlucmakiola.clockula.ui.common.RingtonePickerUiState
|
||||
import de.jeanlucmakiola.floret.di.ApplicationScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.time.DayOfWeek
|
||||
import javax.inject.Inject
|
||||
@@ -62,6 +65,12 @@ class AlarmEditorViewModel @Inject internal constructor(
|
||||
|
||||
private val _state = MutableStateFlow<AlarmEditorUiState>(AlarmEditorUiState.Loading)
|
||||
|
||||
// Conflated: two refused taps open the ring screen once.
|
||||
private val ringScreenRequests = Channel<Unit>(Channel.CONFLATED)
|
||||
|
||||
/** One-shot: a Delete refused because the alarm is ringing; the screen opens the ring screen. */
|
||||
val openRingScreen: Flow<Unit> = ringScreenRequests.receiveAsFlow()
|
||||
|
||||
val state: StateFlow<AlarmEditorUiState> = _state.asStateFlow()
|
||||
|
||||
private val _ringtonePicker = MutableStateFlow<RingtonePickerUiState?>(null)
|
||||
@@ -224,9 +233,13 @@ class AlarmEditorViewModel @Inject internal constructor(
|
||||
// A ringing alarm is not deleted from here either: with no
|
||||
// confirmation in the way, one tap would silence it round its
|
||||
// dismiss challenge. Its ring screen is the way out.
|
||||
engine.delete(alarmId, unlessRinging = true)?.let { deleted ->
|
||||
val deleted = engine.delete(alarmId, unlessRinging = true)
|
||||
if (deleted != null) {
|
||||
undo.offer(deleted)
|
||||
_state.value = AlarmEditorUiState.Gone
|
||||
} else if (alarms.find(alarmId) != null) {
|
||||
// Refused because it rings: take the user to where it stops.
|
||||
ringScreenRequests.trySend(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.jeanlucmakiola.clockula.ui.alarms
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import de.jeanlucmakiola.clockula.data.alarms.AlarmMapper
|
||||
import de.jeanlucmakiola.clockula.domain.DismissChallenge
|
||||
@@ -656,6 +657,7 @@ class AlarmEditorViewModelTest {
|
||||
assertThat(listOf(harness.ring.ringing.value, harness.alarmDao.stored.map { it.id }))
|
||||
.isEqualTo(listOf(1L, listOf(1L)))
|
||||
assertThat(viewModel.state.value).isInstanceOf(AlarmEditorUiState.Editing::class.java)
|
||||
viewModel.openRingScreen.test { assertThat(awaitItem()).isEqualTo(Unit) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1725,7 +1725,7 @@ challenge. The engine re-checks under its lock (`delete(id, unlessRinging = true
|
||||
so a swipe released just as the alarm fires, before the list has caught up,
|
||||
deletes nothing and the card slides back. The editor's Delete passes the same
|
||||
flag: with its confirmation gone, one tap there would otherwise do what the
|
||||
swipe is kept from doing, so a ringing alarm is dealt with on its ring screen. Each is followed by a snackbar on the list ("07:00 alarm deleted",
|
||||
swipe is kept from doing, so a refused tap opens the ring screen instead, where the alarm is dealt with. Each is followed by a snackbar on the list ("07:00 alarm deleted",
|
||||
**Undo**), as in Google Clock. v1 asked before instead, on the argument that a
|
||||
mistaken delete is found at 07:00 rather than now. But a dialog catches no more
|
||||
than the snackbar does: both only catch the slip noticed in the moment, and a
|
||||
|
||||
Reference in new issue
Block a user