PM-23308: Replace Toasts with Snackbar in AttachmentsScreen (#5469)

This commit is contained in:
David Perez
2025-07-02 19:25:28 +00:00
committed by GitHub
parent f608852dc7
commit a2507c317d
3 changed files with 32 additions and 18 deletions
@@ -1,6 +1,5 @@
package com.x8bit.bitwarden.ui.vault.feature.attachments
import android.widget.Toast
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarDefaults
@@ -10,7 +9,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
@@ -27,6 +25,8 @@ import com.x8bit.bitwarden.ui.platform.components.content.BitwardenLoadingConten
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
import com.x8bit.bitwarden.ui.platform.components.snackbar.rememberBitwardenSnackbarHostState
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.vault.feature.attachments.handlers.AttachmentsHandlers
@@ -49,7 +49,7 @@ fun AttachmentsScreen(
attachmentsHandlers.onFileChoose(it)
}
}
val context = LocalContext.current
val snackbarHostState = rememberBitwardenSnackbarHostState()
EventsEffect(viewModel = viewModel) { event ->
when (event) {
AttachmentsEvent.NavigateBack -> onNavigateBack()
@@ -60,11 +60,7 @@ fun AttachmentsScreen(
)
}
is AttachmentsEvent.ShowToast -> {
Toast
.makeText(context, event.message(context.resources), Toast.LENGTH_SHORT)
.show()
}
is AttachmentsEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.data)
}
}
@@ -96,6 +92,9 @@ fun AttachmentsScreen(
},
)
},
snackbarHost = {
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
},
) {
when (val viewState = state.viewState) {
is AttachmentsState.ViewState.Content -> AttachmentsContent(
@@ -16,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.repository.model.UserState
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.data.vault.repository.model.CreateAttachmentResult
import com.x8bit.bitwarden.data.vault.repository.model.DeleteAttachmentResult
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.vault.feature.attachments.util.toViewState
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -281,7 +282,7 @@ class AttachmentsViewModel @Inject constructor(
is CreateAttachmentResult.Success -> {
mutableStateFlow.update { it.copy(dialogState = null) }
sendEvent(AttachmentsEvent.ShowToast(R.string.save_attachment_success.asText()))
sendEvent(AttachmentsEvent.ShowSnackbar(R.string.save_attachment_success.asText()))
}
}
}
@@ -302,7 +303,7 @@ class AttachmentsViewModel @Inject constructor(
DeleteAttachmentResult.Success -> {
mutableStateFlow.update { it.copy(dialogState = null) }
sendEvent(AttachmentsEvent.ShowToast(R.string.attachment_deleted.asText()))
sendEvent(AttachmentsEvent.ShowSnackbar(R.string.attachment_deleted.asText()))
}
}
}
@@ -430,11 +431,25 @@ sealed class AttachmentsEvent {
data object ShowChooserSheet : AttachmentsEvent()
/**
* Displays the given [message] as a toast.
* Displays the given [data] as a snackbar.
*/
data class ShowToast(
val message: Text,
) : AttachmentsEvent()
data class ShowSnackbar(
val data: BitwardenSnackbarData,
) : AttachmentsEvent() {
constructor(
message: Text,
messageHeader: Text? = null,
actionLabel: Text? = null,
withDismissAction: Boolean = false,
) : this(
data = BitwardenSnackbarData(
message = message,
messageHeader = messageHeader,
actionLabel = actionLabel,
withDismissAction = withDismissAction,
),
)
}
}
/**
@@ -334,7 +334,7 @@ class AttachmentsViewModelTest : BaseViewModelTest() {
}
@Test
fun `SaveClick should send ShowToast when createAttachment succeeds`() = runTest {
fun `SaveClick should send ShowSnackbar when createAttachment succeeds`() = runTest {
val cipherView = createMockCipherView(number = 1)
val fileName = "test.png"
val uri = mockk<Uri>()
@@ -373,7 +373,7 @@ class AttachmentsViewModelTest : BaseViewModelTest() {
viewModel.eventFlow.test {
viewModel.trySendAction(AttachmentsAction.SaveClick)
assertEquals(
AttachmentsEvent.ShowToast(R.string.save_attachment_success.asText()),
AttachmentsEvent.ShowSnackbar(R.string.save_attachment_success.asText()),
awaitItem(),
)
}
@@ -480,7 +480,7 @@ class AttachmentsViewModelTest : BaseViewModelTest() {
}
@Test
fun `DeleteClick with deleteCipherAttachment success should emit ShowToast`() = runTest {
fun `DeleteClick with deleteCipherAttachment success should emit ShowSnackbar`() = runTest {
val cipherId = "mockId-1"
val attachmentId = "mockId-1"
val cipherView = createMockCipherView(number = 1)
@@ -497,7 +497,7 @@ class AttachmentsViewModelTest : BaseViewModelTest() {
viewModel.eventFlow.test {
viewModel.trySendAction(AttachmentsAction.DeleteClick(cipherId))
assertEquals(
AttachmentsEvent.ShowToast(R.string.attachment_deleted.asText()),
AttachmentsEvent.ShowSnackbar(R.string.attachment_deleted.asText()),
awaitItem(),
)
}