PM-20400: Display snackbar confirming log deletion (#5088)

This commit is contained in:
David Perez
2025-04-23 14:53:44 -05:00
committed by GitHub
parent 54983bc92e
commit 37a0d19efc
5 changed files with 49 additions and 5 deletions

View File

@@ -46,6 +46,9 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialo
import com.x8bit.bitwarden.ui.platform.components.model.CardStyle
import com.x8bit.bitwarden.ui.platform.components.model.IconData
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
import com.x8bit.bitwarden.ui.platform.components.snackbar.rememberBitwardenSnackbarHostState
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
@@ -64,12 +67,19 @@ fun RecordedLogsScreen(
intentManager: IntentManager = LocalIntentManager.current,
) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
val snackbarHostState = rememberBitwardenSnackbarHostState()
EventsEffect(viewModel) { event ->
when (event) {
RecordedLogsEvent.NavigateBack -> onNavigateBack()
is RecordedLogsEvent.ShareLog -> {
intentManager.shareFile(fileUri = event.uri.toUri())
}
is RecordedLogsEvent.ShowSnackbar -> {
snackbarHostState.showSnackbar(
snackbarData = BitwardenSnackbarData(message = event.text),
)
}
}
}
@@ -104,6 +114,7 @@ fun RecordedLogsScreen(
},
)
},
snackbarHost = { BitwardenSnackbarHost(bitwardenHostState = snackbarHostState) },
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
) {
when (val viewState = state.viewState) {

View File

@@ -74,6 +74,7 @@ class RecordedLogsViewModel @Inject constructor(
private fun handleDeleteAllClick() {
settingsRepository.deleteAllLogs()
sendEvent(RecordedLogsEvent.ShowSnackbar(text = R.string.all_logs_deleted.asText()))
}
private fun handleDeleteClick(action: RecordedLogsAction.DeleteClick) {
@@ -81,7 +82,10 @@ class RecordedLogsViewModel @Inject constructor(
.flightRecorderData
.data
.find { it.id == action.item.id }
?.let { settingsRepository.deleteLog(data = it) }
?.let {
settingsRepository.deleteLog(data = it)
sendEvent(RecordedLogsEvent.ShowSnackbar(text = R.string.log_deleted.asText()))
}
}
private fun handleShareAllClick() {
@@ -256,6 +260,11 @@ sealed class RecordedLogsEvent {
* Shares the logs are the given [uri].
*/
data class ShareLog(val uri: String) : RecordedLogsEvent()
/**
* Displays a snackbar with the given [text].
*/
data class ShowSnackbar(val text: Text) : RecordedLogsEvent()
}
/**

View File

@@ -1256,4 +1256,6 @@ Do you want to switch to this account?</string>
<string name="flight_recorder_banner_title">Flight recorder on</string>
<string name="flight_recorder_banner_message">Flight recorder will be active until %1$s at %2$s. Return to settings to deactivate now.</string>
<string name="go_to_settings">Go to settings</string>
<string name="all_logs_deleted">All logs deleted</string>
<string name="log_deleted">Log deleted</string>
</resources>

View File

@@ -81,6 +81,16 @@ class RecordedLogsScreenTest : BaseComposeTest() {
assertTrue(onNavigateBackCalled)
}
@Test
fun `on ShowSnackbar event should display the snackbar with the correct message`() {
val message = "Test Snackbar Message"
mutableEventFlow.tryEmit(RecordedLogsEvent.ShowSnackbar(text = message.asText()))
composeTestRule
.onNodeWithText(text = message)
.assertIsDisplayed()
}
@Test
fun `on ShareLog event should invoke shareFile on intent manager`() {
val stringUri = "/logs"

View File

@@ -257,16 +257,22 @@ class RecordedLogsViewModelTest : BaseViewModelTest() {
}
@Test
fun `on DeleteAllClick action should call deleteAllLogs`() {
fun `on DeleteAllClick action should call deleteAllLogs`() = runTest {
val viewModel = createViewModel()
viewModel.trySendAction(RecordedLogsAction.DeleteAllClick)
viewModel.eventFlow.test {
viewModel.trySendAction(RecordedLogsAction.DeleteAllClick)
assertEquals(
RecordedLogsEvent.ShowSnackbar(R.string.all_logs_deleted.asText()),
awaitItem(),
)
}
verify(exactly = 1) {
settingsRepository.deleteAllLogs()
}
}
@Test
fun `on DeleteClick action should call deleteLog`() {
fun `on DeleteClick action should call deleteLog`() = runTest {
val data = mockk<FlightRecorderDataSet.FlightRecorderData> {
every { id } returns "50"
}
@@ -276,7 +282,13 @@ class RecordedLogsViewModelTest : BaseViewModelTest() {
val item = mockk<RecordedLogsState.DisplayItem> {
every { id } returns "50"
}
viewModel.trySendAction(RecordedLogsAction.DeleteClick(item = item))
viewModel.eventFlow.test {
viewModel.trySendAction(RecordedLogsAction.DeleteClick(item = item))
assertEquals(
RecordedLogsEvent.ShowSnackbar(R.string.log_deleted.asText()),
awaitItem(),
)
}
verify(exactly = 1) {
settingsRepository.deleteLog(data = data)
}