mirror of
https://github.com/bitwarden/android.git
synced 2026-08-30 17:33:42 -05:00
PM-23503: Update Move to Organization toasts to be snackbars (#5489)
This commit is contained in:
@@ -10,6 +10,7 @@ import kotlinx.serialization.Serializable
|
||||
@Serializable
|
||||
enum class SnackbarRelay {
|
||||
CIPHER_DELETED,
|
||||
CIPHER_MOVED_TO_ORGANIZATION,
|
||||
CIPHER_RESTORED,
|
||||
LOGIN_APPROVAL,
|
||||
LOGINS_IMPORTED,
|
||||
|
||||
@@ -68,6 +68,8 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialo
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.radio.BitwardenRadioButton
|
||||
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.components.text.BitwardenClickableText
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalBiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalCredentialProviderCompletionManager
|
||||
@@ -124,6 +126,7 @@ fun VaultAddEditScreen(
|
||||
orderedList = AddEditItemCoachMark.entries,
|
||||
)
|
||||
val scope = rememberCoroutineScope()
|
||||
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is VaultAddEditEvent.NavigateToQrCodeScan -> {
|
||||
@@ -189,6 +192,8 @@ fun VaultAddEditScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is VaultAddEditEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,6 +399,9 @@ fun VaultAddEditScreen(
|
||||
},
|
||||
)
|
||||
},
|
||||
snackbarHost = {
|
||||
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||
},
|
||||
) {
|
||||
when (val viewState = state.viewState) {
|
||||
is VaultAddEditState.ViewState.Content -> {
|
||||
|
||||
+35
-1
@@ -53,7 +53,10 @@ import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.RegisterFido2CredentialResult
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import com.x8bit.bitwarden.ui.platform.manager.resource.ResourceManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldType
|
||||
@@ -108,12 +111,13 @@ private const val KEY_STATE = "state"
|
||||
@Suppress("TooManyFunctions", "LargeClass", "LongParameterList", "LongMethod")
|
||||
class VaultAddEditViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
generatorRepository: GeneratorRepository,
|
||||
snackbarRelayManager: SnackbarRelayManager,
|
||||
private val authRepository: AuthRepository,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val policyManager: PolicyManager,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val bitwardenCredentialManager: BitwardenCredentialManager,
|
||||
generatorRepository: GeneratorRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||
private val resourceManager: ResourceManager,
|
||||
@@ -255,6 +259,12 @@ class VaultAddEditViewModel @Inject constructor(
|
||||
}
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
snackbarRelayManager
|
||||
.getSnackbarDataFlow(SnackbarRelay.CIPHER_MOVED_TO_ORGANIZATION)
|
||||
.map { VaultAddEditAction.Internal.SnackbarDataReceived(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: VaultAddEditAction) {
|
||||
@@ -1548,9 +1558,19 @@ class VaultAddEditViewModel @Inject constructor(
|
||||
is VaultAddEditAction.Internal.AvailableFoldersReceive -> {
|
||||
handleAvailableFoldersReceive(action)
|
||||
}
|
||||
|
||||
is VaultAddEditAction.Internal.SnackbarDataReceived -> {
|
||||
handleSnackbarDataReceived(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSnackbarDataReceived(
|
||||
action: VaultAddEditAction.Internal.SnackbarDataReceived,
|
||||
) {
|
||||
sendEvent(VaultAddEditEvent.ShowSnackbar(action.data))
|
||||
}
|
||||
|
||||
private fun handleAvailableFoldersReceive(
|
||||
action: VaultAddEditAction.Internal.AvailableFoldersReceive,
|
||||
) {
|
||||
@@ -2715,6 +2735,13 @@ data class VaultAddEditState(
|
||||
* Each subclass of this sealed class denotes a distinct event that can occur.
|
||||
*/
|
||||
sealed class VaultAddEditEvent {
|
||||
/**
|
||||
* Shows a snackbar with the given [data].
|
||||
*/
|
||||
data class ShowSnackbar(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : VaultAddEditEvent(), BackgroundEvent
|
||||
|
||||
/**
|
||||
* Shows a toast with the given [message].
|
||||
*/
|
||||
@@ -3372,6 +3399,13 @@ sealed class VaultAddEditAction {
|
||||
val generatorResult: GeneratorResult,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that snackbar data has been received.
|
||||
*/
|
||||
data class SnackbarDataReceived(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that the vault item data has been received.
|
||||
*/
|
||||
|
||||
+20
-1
@@ -9,6 +9,7 @@ import com.bitwarden.core.data.repository.util.combineDataStates
|
||||
import com.bitwarden.core.data.repository.util.mapNullable
|
||||
import com.bitwarden.core.util.persistentListOfNotNull
|
||||
import com.bitwarden.data.repository.util.baseIconUrl
|
||||
import com.bitwarden.ui.platform.base.BackgroundEvent
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.platform.components.icon.model.IconData
|
||||
import com.bitwarden.ui.util.Text
|
||||
@@ -216,6 +217,12 @@ class VaultItemViewModel @Inject constructor(
|
||||
.map { VaultItemAction.Internal.IsIconLoadingDisabledUpdateReceive(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
snackbarRelayManager
|
||||
.getSnackbarDataFlow(SnackbarRelay.CIPHER_MOVED_TO_ORGANIZATION)
|
||||
.map { VaultItemAction.Internal.SnackbarDataReceived(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: VaultItemAction) {
|
||||
@@ -937,6 +944,7 @@ class VaultItemViewModel @Inject constructor(
|
||||
when (action) {
|
||||
is VaultItemAction.Internal.CopyValue -> handleCopyValue(action)
|
||||
is VaultItemAction.Internal.PasswordBreachReceive -> handlePasswordBreachReceive(action)
|
||||
is VaultItemAction.Internal.SnackbarDataReceived -> handleSnackbarDataReceived(action)
|
||||
is VaultItemAction.Internal.VaultDataReceive -> handleVaultDataReceive(action)
|
||||
is VaultItemAction.Internal.DeleteCipherReceive -> handleDeleteCipherReceive(action)
|
||||
is VaultItemAction.Internal.RestoreCipherReceive -> handleRestoreCipherReceive(action)
|
||||
@@ -958,6 +966,10 @@ class VaultItemViewModel @Inject constructor(
|
||||
clipboardManager.setText(action.value)
|
||||
}
|
||||
|
||||
private fun handleSnackbarDataReceived(action: VaultItemAction.Internal.SnackbarDataReceived) {
|
||||
sendEvent(VaultItemEvent.ShowSnackbar(action.data))
|
||||
}
|
||||
|
||||
private fun handlePasswordBreachReceive(
|
||||
action: VaultItemAction.Internal.PasswordBreachReceive,
|
||||
) {
|
||||
@@ -1784,7 +1796,7 @@ sealed class VaultItemEvent {
|
||||
*/
|
||||
data class ShowSnackbar(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : VaultItemEvent() {
|
||||
) : VaultItemEvent(), BackgroundEvent {
|
||||
constructor(
|
||||
message: Text,
|
||||
messageHeader: Text? = null,
|
||||
@@ -2107,6 +2119,13 @@ sealed class VaultItemAction {
|
||||
val result: BreachCountResult,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that snackbar data has been received.
|
||||
*/
|
||||
data class SnackbarDataReceived(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that the vault item data has been received.
|
||||
*/
|
||||
|
||||
-7
@@ -1,6 +1,5 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.movetoorganization
|
||||
|
||||
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
|
||||
@@ -37,14 +35,9 @@ fun VaultMoveToOrganizationScreen(
|
||||
onNavigateBack: () -> Unit,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is VaultMoveToOrganizationEvent.NavigateBack -> onNavigateBack()
|
||||
is VaultMoveToOrganizationEvent.ShowToast -> {
|
||||
Toast.makeText(context, event.text(resources), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
VaultMoveToOrganizationScaffold(
|
||||
|
||||
+12
-12
@@ -16,6 +16,9 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
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.ShareCipherResult
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import com.x8bit.bitwarden.ui.vault.feature.movetoorganization.util.toViewState
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCollection
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -37,8 +40,9 @@ private const val KEY_STATE = "state"
|
||||
@Suppress("MaxLineLength", "TooManyFunctions")
|
||||
class VaultMoveToOrganizationViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val vaultRepository: VaultRepository,
|
||||
authRepository: AuthRepository,
|
||||
private val snackbarRelayManager: SnackbarRelayManager,
|
||||
private val vaultRepository: VaultRepository,
|
||||
) : BaseViewModel<VaultMoveToOrganizationState, VaultMoveToOrganizationEvent, VaultMoveToOrganizationAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
?: run {
|
||||
@@ -165,8 +169,11 @@ class VaultMoveToOrganizationViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is ShareCipherResult.Success -> {
|
||||
snackbarRelayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(message = action.message),
|
||||
relay = SnackbarRelay.CIPHER_MOVED_TO_ORGANIZATION,
|
||||
)
|
||||
sendEvent(VaultMoveToOrganizationEvent.NavigateBack)
|
||||
sendEvent(VaultMoveToOrganizationEvent.ShowToast(action.successToast))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,7 +309,7 @@ class VaultMoveToOrganizationViewModel @Inject constructor(
|
||||
cipherView = cipherView,
|
||||
collectionIds = collectionIds,
|
||||
),
|
||||
successToast = R.string.item_updated.asText(),
|
||||
message = R.string.item_updated.asText(),
|
||||
)
|
||||
} else {
|
||||
VaultMoveToOrganizationAction.Internal.ShareCipherResultReceive(
|
||||
@@ -312,7 +319,7 @@ class VaultMoveToOrganizationViewModel @Inject constructor(
|
||||
cipherView = cipherView,
|
||||
collectionIds = collectionIds,
|
||||
),
|
||||
successToast = R.string.moved_item_to_org.asText(
|
||||
message = R.string.moved_item_to_org.asText(
|
||||
requireNotNull(contentState.cipherToMove).name,
|
||||
contentState.selectedOrganization.name,
|
||||
),
|
||||
@@ -444,13 +451,6 @@ sealed class VaultMoveToOrganizationEvent {
|
||||
* Navigates back to the previous screen.
|
||||
*/
|
||||
data object NavigateBack : VaultMoveToOrganizationEvent()
|
||||
|
||||
/**
|
||||
* Show a toast with the given message.
|
||||
*
|
||||
* @property text the text to display.
|
||||
*/
|
||||
data class ShowToast(val text: Text) : VaultMoveToOrganizationEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,7 +508,7 @@ sealed class VaultMoveToOrganizationAction {
|
||||
*/
|
||||
data class ShareCipherResultReceive(
|
||||
val shareCipherResult: ShareCipherResult,
|
||||
val successToast: Text,
|
||||
val message: Text,
|
||||
) : Internal()
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -54,6 +54,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.CredentialProviderCompletionManager
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.RegisterFido2CredentialResult
|
||||
import com.x8bit.bitwarden.ui.platform.base.BitwardenComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
@@ -138,6 +139,15 @@ class VaultAddEditScreenTest : BitwardenComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on ShowSnackbar should display snackbar content`() {
|
||||
val message = "message"
|
||||
val data = BitwardenSnackbarData(message = message.asText())
|
||||
composeTestRule.onNodeWithText(text = message).assertDoesNotExist()
|
||||
mutableEventFlow.tryEmit(VaultAddEditEvent.ShowSnackbar(data = data))
|
||||
composeTestRule.onNodeWithText(text = message).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on ExitApp event should call the exitApplication of ExitManager`() {
|
||||
mutableEventFlow.tryEmit(VaultAddEditEvent.ExitApp)
|
||||
|
||||
+21
@@ -71,7 +71,9 @@ import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateCipherResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.ui.credentials.manager.model.RegisterFido2CredentialResult
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import com.x8bit.bitwarden.ui.platform.manager.resource.ResourceManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.model.CustomFieldType
|
||||
@@ -197,6 +199,13 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
||||
every { getFeatureFlag(key = FlagKey.RestrictCipherItemDeletion) } returns false
|
||||
}
|
||||
private val mutableSnackbarDataFlow: MutableSharedFlow<BitwardenSnackbarData> =
|
||||
bufferedMutableSharedFlow()
|
||||
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||
every {
|
||||
getSnackbarDataFlow(relay = any(), relays = anyVararg())
|
||||
} returns mutableSnackbarDataFlow
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
@@ -501,6 +510,16 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `snackbar relay emission should send ShowSnackbar`() = runTest {
|
||||
val viewModel = createAddVaultItemViewModel()
|
||||
val snackbarData = mockk<BitwardenSnackbarData>()
|
||||
viewModel.eventFlow.test {
|
||||
mutableSnackbarDataFlow.emit(snackbarData)
|
||||
assertEquals(VaultAddEditEvent.ShowSnackbar(snackbarData), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `AttachmentsClick should emit NavigateToAttachments`() = runTest {
|
||||
val vaultAddEditType = VaultAddEditType.EditItem(DEFAULT_EDIT_ITEM_ID)
|
||||
@@ -3474,6 +3493,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||
bitwardenCredentialManager = bitwardenCredentialManager,
|
||||
generatorRepository = generatorRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
snackbarRelayManager = snackbarRelayManager,
|
||||
specialCircumstanceManager = specialCircumstanceManager,
|
||||
resourceManager = resourceManager,
|
||||
clock = fixedClock,
|
||||
@@ -4860,6 +4880,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
||||
bitwardenCredentialManager = bitwardenCredentialManager,
|
||||
generatorRepository = generatorRepo,
|
||||
settingsRepository = settingsRepository,
|
||||
snackbarRelayManager = snackbarRelayManager,
|
||||
specialCircumstanceManager = specialCircumstanceManager,
|
||||
resourceManager = bitwardenResourceManager,
|
||||
clock = clock,
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.bitwarden.ui.util.onNodeWithTextAfterScroll
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.ui.platform.base.BitwardenComposeTest
|
||||
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.addedit.VaultAddEditArgs
|
||||
import com.x8bit.bitwarden.ui.vault.feature.item.model.TotpCodeItemData
|
||||
@@ -137,6 +138,15 @@ class VaultItemScreenTest : BitwardenComposeTest() {
|
||||
assertEquals(id, onNavigateToPasswordHistoryId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on ShowSnackbar should display snackbar content`() {
|
||||
val message = "message"
|
||||
val data = BitwardenSnackbarData(message = message.asText())
|
||||
composeTestRule.onNodeWithText(text = message).assertDoesNotExist()
|
||||
mutableEventFlow.tryEmit(VaultItemEvent.ShowSnackbar(data = data))
|
||||
composeTestRule.onNodeWithText(text = message).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on close click should send CloseClick`() {
|
||||
composeTestRule.onNodeWithContentDescription(label = "Close").performClick()
|
||||
|
||||
+17
@@ -4,6 +4,7 @@ import android.net.Uri
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.data.repository.model.Environment
|
||||
import com.bitwarden.data.repository.util.baseIconUrl
|
||||
import com.bitwarden.network.model.OrganizationType
|
||||
@@ -63,6 +64,7 @@ import io.mockk.runs
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
@@ -120,7 +122,12 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
||||
private val featureFlagManager: FeatureFlagManager = mockk {
|
||||
every { getFeatureFlag(key = FlagKey.RestrictCipherItemDeletion) } returns false
|
||||
}
|
||||
private val mutableSnackbarDataFlow: MutableSharedFlow<BitwardenSnackbarData> =
|
||||
bufferedMutableSharedFlow()
|
||||
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||
every {
|
||||
getSnackbarDataFlow(relay = any(), relays = anyVararg())
|
||||
} returns mutableSnackbarDataFlow
|
||||
every { sendSnackbarData(data = any(), relay = any()) } just runs
|
||||
}
|
||||
|
||||
@@ -173,6 +180,16 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `snackbar relay emission should send ShowSnackbar`() = runTest {
|
||||
val viewModel = createViewModel(DEFAULT_STATE)
|
||||
val snackbarData = mockk<BitwardenSnackbarData>()
|
||||
viewModel.eventFlow.test {
|
||||
mutableSnackbarDataFlow.emit(snackbarData)
|
||||
assertEquals(VaultItemEvent.ShowSnackbar(snackbarData), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class CommonActions {
|
||||
private lateinit var viewModel: VaultItemViewModel
|
||||
|
||||
+22
-7
@@ -20,14 +20,20 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.ShareCipherResult
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import com.x8bit.bitwarden.ui.vault.feature.movetoorganization.util.createMockOrganizationList
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultCollection
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.runs
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
@@ -57,6 +63,10 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
}
|
||||
|
||||
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||
every { sendSnackbarData(data = any(), relay = any()) } just runs
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(SavedStateHandle::toVaultMoveToOrganizationArgs)
|
||||
@@ -394,14 +404,16 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
|
||||
VaultMoveToOrganizationEvent.NavigateBack,
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultMoveToOrganizationEvent.ShowToast(
|
||||
text = R.string.moved_item_to_org.asText(
|
||||
}
|
||||
verify {
|
||||
snackbarRelayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(
|
||||
message = R.string.moved_item_to_org.asText(
|
||||
"mockName-1",
|
||||
"mockOrganizationName-1",
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
relay = SnackbarRelay.CIPHER_MOVED_TO_ORGANIZATION,
|
||||
)
|
||||
}
|
||||
coVerify {
|
||||
@@ -439,9 +451,11 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
|
||||
VaultMoveToOrganizationEvent.NavigateBack,
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
VaultMoveToOrganizationEvent.ShowToast(R.string.item_updated.asText()),
|
||||
awaitItem(),
|
||||
}
|
||||
verify {
|
||||
snackbarRelayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(message = R.string.item_updated.asText()),
|
||||
relay = SnackbarRelay.CIPHER_MOVED_TO_ORGANIZATION,
|
||||
)
|
||||
}
|
||||
coVerify {
|
||||
@@ -461,6 +475,7 @@ class VaultMoveToOrganizationViewModelTest : BaseViewModelTest() {
|
||||
savedStateHandle = savedStateHandle,
|
||||
authRepository = authRepo,
|
||||
vaultRepository = vaultRepo,
|
||||
snackbarRelayManager = snackbarRelayManager,
|
||||
)
|
||||
|
||||
private fun createSavedStateHandleWithState(
|
||||
|
||||
Reference in New Issue
Block a user