PM-23305: Replace Vault Screen Toasts with Snackbars (#5468)

This commit is contained in:
David Perez authored and GitHub committed 2025-07-02 19:13:58 +00:00
1 parent e44d63229c
commit f608852dc7
3 files changed
+29 -35

No files matched your search

@@ -1,6 +1,5 @@
package com.x8bit.bitwarden.ui.vault.feature.vault
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
@@ -20,7 +19,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
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.compose.ui.unit.dp
@@ -100,7 +98,6 @@ fun VaultScreen(
appReviewManager: AppReviewManager = LocalAppReviewManager.current,
) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
val context = LocalContext.current
val pullToRefreshState = rememberBitwardenPullToRefreshState(
isEnabled = state.isPullToRefreshEnabled,
isRefreshing = state.isRefreshing,
@@ -164,12 +161,6 @@ fun VaultScreen(
is VaultEvent.NavigateToUrl -> intentManager.launchUri(event.url.toUri())
VaultEvent.NavigateOutOfApp -> exitManager.exitApplication()
is VaultEvent.ShowToast -> {
Toast
.makeText(context, event.message(context.resources), Toast.LENGTH_SHORT)
.show()
}
VaultEvent.NavigateToImportLogins -> onNavigateToImportLogins()
is VaultEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.data)
VaultEvent.PromptForAppReview -> {
@@ -4,6 +4,7 @@ import android.os.Parcelable
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.viewModelScope
import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.core.util.persistentListOfNotNull
import com.bitwarden.data.repository.util.baseIconUrl
import com.bitwarden.network.model.PolicyTypeJson
import com.bitwarden.ui.platform.base.BackgroundEvent
@@ -72,8 +73,6 @@ import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import java.time.Clock
import javax.inject.Inject
import kotlin.collections.emptyList
import kotlin.collections.map
/**
* Manages [VaultState], handles [VaultAction], and launches [VaultEvent] for the [VaultScreen].
@@ -252,15 +251,12 @@ class VaultViewModel @Inject constructor(
private fun handleSelectAddItemType() {
// If policy is enable for any organization, exclude the card option
var excludedOptions =
if (!state.restrictItemTypesPolicyOrgIds.isNullOrEmpty()) {
persistentListOf(
CreateVaultItemType.SSH_KEY,
CreateVaultItemType.CARD,
)
} else {
persistentListOf(CreateVaultItemType.SSH_KEY)
}
val excludedOptions = persistentListOfNotNull(
CreateVaultItemType.SSH_KEY,
CreateVaultItemType.CARD.takeUnless {
state.restrictItemTypesPolicyOrgIds.isNullOrEmpty()
},
)
mutableStateFlow.update {
it.copy(
@@ -816,11 +812,7 @@ class VaultViewModel @Inject constructor(
private fun vaultLoadedReceive(vaultData: DataState.Loaded<VaultData>) {
if (state.dialog == VaultState.DialogState.Syncing) {
sendEvent(
VaultEvent.ShowToast(
message = R.string.syncing_complete.asText(),
),
)
sendEvent(VaultEvent.ShowSnackbar(message = R.string.syncing_complete.asText()))
}
updateVaultState(vaultData.data)
}
@@ -1377,15 +1369,26 @@ sealed class VaultEvent {
*/
data object PromptForAppReview : VaultEvent()
/**
* Show a toast with the given [message].
*/
data class ShowToast(val message: Text) : VaultEvent()
/**
* Show a snackbar with the given [data].
*/
data class ShowSnackbar(val data: BitwardenSnackbarData) : VaultEvent(), BackgroundEvent
data class ShowSnackbar(
val data: BitwardenSnackbarData,
) : VaultEvent(), BackgroundEvent {
constructor(
message: Text,
messageHeader: Text? = null,
actionLabel: Text? = null,
withDismissAction: Boolean = false,
) : this(
data = BitwardenSnackbarData(
message = message,
messageHeader = messageHeader,
actionLabel = actionLabel,
withDismissAction = withDismissAction,
),
)
}
/**
* Navigate to the add folder screen
@@ -862,7 +862,7 @@ class VaultViewModelTest : BaseViewModelTest() {
@Suppress("MaxLineLength")
@Test
fun `vaultDataStateFlow Loaded with items when manually syncing with the sync button should update state to Content, show a success Toast, and dismiss pull to refresh`() =
fun `vaultDataStateFlow Loaded with items when manually syncing with the sync button should update state to Content, show a success Snackbar, and dismiss pull to refresh`() =
runTest {
val expectedState = createMockVaultState(
viewState = VaultState.ViewState.Content(
@@ -898,7 +898,7 @@ class VaultViewModelTest : BaseViewModelTest() {
assertEquals(expectedState, viewModel.stateFlow.value)
assertEquals(
VaultEvent.ShowToast(R.string.syncing_complete.asText()),
VaultEvent.ShowSnackbar(R.string.syncing_complete.asText()),
awaitItem(),
)
}
@@ -925,7 +925,7 @@ class VaultViewModelTest : BaseViewModelTest() {
@Suppress("MaxLineLength")
@Test
fun `vaultDataStateFlow Loaded with empty items when manually syncing with the sync button should update state to NoItems, show a success Toast, and dismiss pull to refresh`() =
fun `vaultDataStateFlow Loaded with empty items when manually syncing with the sync button should update state to NoItems, show a success Snackbar, and dismiss pull to refresh`() =
runTest {
val expectedState = createMockVaultState(
viewState = VaultState.ViewState.NoItems,
@@ -945,7 +945,7 @@ class VaultViewModelTest : BaseViewModelTest() {
assertEquals(expectedState, viewModel.stateFlow.value)
assertEquals(
VaultEvent.ShowToast(R.string.syncing_complete.asText()),
VaultEvent.ShowSnackbar(R.string.syncing_complete.asText()),
awaitItem(),
)
}