mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 09:56:45 -06:00
PM-23292: Migrate toasts to snackbars (#5940)
This commit is contained in:
parent
7bf4acbb28
commit
d5d4caea62
@ -1,6 +1,5 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.completeregistration
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -26,7 +25,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
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.text.input.ImeAction
|
||||
@ -48,6 +46,9 @@ import com.bitwarden.ui.platform.components.field.BitwardenPasswordField
|
||||
import com.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.rememberBitwardenSnackbarHostState
|
||||
import com.bitwarden.ui.platform.components.text.BitwardenClickableText
|
||||
import com.bitwarden.ui.platform.components.toggle.BitwardenSwitch
|
||||
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
@ -74,16 +75,15 @@ fun CompleteRegistrationScreen(
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val handler = rememberCompleteRegistrationHandler(viewModel = viewModel)
|
||||
val context = LocalContext.current
|
||||
|
||||
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||
// route OS back actions through the VM to clear the special circumstance
|
||||
BackHandler(onBack = handler.onBackClick)
|
||||
|
||||
EventsEffect(viewModel) { event ->
|
||||
when (event) {
|
||||
is CompleteRegistrationEvent.NavigateBack -> onNavigateBack.invoke()
|
||||
is CompleteRegistrationEvent.ShowToast -> {
|
||||
Toast.makeText(context, event.message(context.resources), Toast.LENGTH_SHORT).show()
|
||||
is CompleteRegistrationEvent.ShowSnackbar -> {
|
||||
snackbarHostState.showSnackbar(BitwardenSnackbarData(message = event.message))
|
||||
}
|
||||
|
||||
CompleteRegistrationEvent.NavigateToMakePasswordStrong -> onNavigateToPasswordGuidance()
|
||||
@ -143,6 +143,7 @@ fun CompleteRegistrationScreen(
|
||||
onNavigationIconClick = handler.onBackClick,
|
||||
)
|
||||
},
|
||||
snackbarHost = { BitwardenSnackbarHost(bitwardenHostState = snackbarHostState) },
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
||||
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.completeregistration
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.manager.toast.ToastManager
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.platform.base.util.isValidEmail
|
||||
import com.bitwarden.ui.platform.resource.BitwardenPlurals
|
||||
@ -54,6 +55,7 @@ class CompleteRegistrationViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||
private val toastManager: ToastManager,
|
||||
) : BaseViewModel<CompleteRegistrationState, CompleteRegistrationEvent, CompleteRegistrationAction>(
|
||||
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||
val args = savedStateHandle.toCompleteRegistrationArgs()
|
||||
@ -146,9 +148,7 @@ class CompleteRegistrationViewModel @Inject constructor(
|
||||
|
||||
viewModelScope.launch {
|
||||
sendEvent(
|
||||
CompleteRegistrationEvent.ShowToast(
|
||||
message = BitwardenString.email_verified.asText(),
|
||||
),
|
||||
CompleteRegistrationEvent.ShowSnackbar(BitwardenString.email_verified.asText()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -243,11 +243,7 @@ class CompleteRegistrationViewModel @Inject constructor(
|
||||
|
||||
private fun handleLoginResult(action: Internal.ReceiveLoginResult) {
|
||||
clearDialogState()
|
||||
sendEvent(
|
||||
CompleteRegistrationEvent.ShowToast(
|
||||
message = BitwardenString.account_created_success.asText(),
|
||||
),
|
||||
)
|
||||
toastManager.show(messageId = BitwardenString.account_created_success)
|
||||
|
||||
authRepository.setOnboardingStatus(
|
||||
status = OnboardingStatus.NOT_STARTED,
|
||||
@ -504,9 +500,9 @@ sealed class CompleteRegistrationEvent {
|
||||
data object NavigateBack : CompleteRegistrationEvent()
|
||||
|
||||
/**
|
||||
* Show a toast with the given message.
|
||||
* Show a snackbar with the given message.
|
||||
*/
|
||||
data class ShowToast(
|
||||
data class ShowSnackbar(
|
||||
val message: Text,
|
||||
) : CompleteRegistrationEvent()
|
||||
|
||||
|
||||
@ -33,6 +33,8 @@ import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent
|
||||
import com.bitwarden.ui.platform.components.fab.BitwardenFloatingActionButton
|
||||
import com.bitwarden.ui.platform.components.row.BitwardenTextRow
|
||||
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.rememberBitwardenSnackbarHostState
|
||||
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.bitwarden.ui.platform.resource.BitwardenDrawable
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
@ -54,6 +56,7 @@ fun FoldersScreen(
|
||||
viewModel: FoldersViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state = viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is FoldersEvent.NavigateBack -> onNavigateBack()
|
||||
@ -61,6 +64,8 @@ fun FoldersScreen(
|
||||
is FoldersEvent.NavigateToEditFolderScreen -> {
|
||||
onNavigateToEditFolderScreen(event.folderId)
|
||||
}
|
||||
|
||||
is FoldersEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +97,7 @@ fun FoldersScreen(
|
||||
.navigationBarsPadding(),
|
||||
)
|
||||
},
|
||||
snackbarHost = { BitwardenSnackbarHost(bitwardenHostState = snackbarHostState) },
|
||||
) {
|
||||
when (val viewState = state.value.viewState) {
|
||||
is FoldersState.ViewState.Content -> {
|
||||
|
||||
@ -3,7 +3,9 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.folders
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.ui.platform.base.BackgroundEvent
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -11,8 +13,11 @@ import com.bitwarden.ui.util.concat
|
||||
import com.bitwarden.vault.FolderView
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.model.FolderDisplayItem
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@ -25,6 +30,7 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class FoldersViewModel @Inject constructor(
|
||||
vaultRepository: VaultRepository,
|
||||
snackbarRelayManager: SnackbarRelayManager,
|
||||
) : BaseViewModel<FoldersState, FoldersEvent, FoldersAction>(
|
||||
initialState = FoldersState(viewState = FoldersState.ViewState.Loading),
|
||||
) {
|
||||
@ -33,15 +39,31 @@ class FoldersViewModel @Inject constructor(
|
||||
.foldersStateFlow
|
||||
.onEach { sendAction(FoldersAction.Internal.VaultDataReceive(it)) }
|
||||
.launchIn(viewModelScope)
|
||||
snackbarRelayManager
|
||||
.getSnackbarDataFlow(
|
||||
SnackbarRelay.FOLDER_CREATED,
|
||||
SnackbarRelay.FOLDER_DELETED,
|
||||
SnackbarRelay.FOLDER_UPDATED,
|
||||
)
|
||||
.map { FoldersAction.Internal.SnackbarDataReceived(it) }
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: FoldersAction): Unit = when (action) {
|
||||
is FoldersAction.AddFolderButtonClick -> handleAddFolderButtonClicked()
|
||||
is FoldersAction.CloseButtonClick -> handleCloseButtonClicked()
|
||||
is FoldersAction.Internal.VaultDataReceive -> handleVaultDataReceive(action)
|
||||
is FoldersAction.Internal -> handleInternalAction(action)
|
||||
is FoldersAction.FolderClick -> handleFolderClick(action)
|
||||
}
|
||||
|
||||
private fun handleInternalAction(action: FoldersAction.Internal) {
|
||||
when (action) {
|
||||
is FoldersAction.Internal.SnackbarDataReceived -> handleSnackbarDataReceived(action)
|
||||
is FoldersAction.Internal.VaultDataReceive -> handleVaultDataReceive(action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFolderClick(action: FoldersAction.FolderClick) {
|
||||
sendEvent(FoldersEvent.NavigateToEditFolderScreen(action.folderId))
|
||||
}
|
||||
@ -54,6 +76,10 @@ class FoldersViewModel @Inject constructor(
|
||||
sendEvent(FoldersEvent.NavigateBack)
|
||||
}
|
||||
|
||||
private fun handleSnackbarDataReceived(action: FoldersAction.Internal.SnackbarDataReceived) {
|
||||
sendEvent(FoldersEvent.ShowSnackbar(action.data))
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun handleVaultDataReceive(action: FoldersAction.Internal.VaultDataReceive) {
|
||||
when (val vaultDataState = action.vaultDataState) {
|
||||
@ -180,6 +206,13 @@ sealed class FoldersEvent {
|
||||
* Navigates to the screen to edit a folder.
|
||||
*/
|
||||
data class NavigateToEditFolderScreen(val folderId: String) : FoldersEvent()
|
||||
|
||||
/**
|
||||
* Show a snackbar.
|
||||
*/
|
||||
data class ShowSnackbar(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : FoldersEvent(), BackgroundEvent
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,6 +238,12 @@ sealed class FoldersAction {
|
||||
* Actions for internal use by the ViewModel.
|
||||
*/
|
||||
sealed class Internal : FoldersAction() {
|
||||
/**
|
||||
* Indicates that the vault folders data has been received.
|
||||
*/
|
||||
data class SnackbarDataReceived(
|
||||
val data: BitwardenSnackbarData,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates that the vault folders data has been received.
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.folders.addedit
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -18,7 +17,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
|
||||
@ -55,16 +53,10 @@ fun FolderAddEditScreen(
|
||||
viewModel: FolderAddEditViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
|
||||
var shouldShowConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is FolderAddEditEvent.NavigateBack -> onNavigateBack.invoke()
|
||||
is FolderAddEditEvent.ShowToast -> {
|
||||
Toast.makeText(context, event.message(context.resources), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.DateTime
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -16,6 +17,8 @@ import com.x8bit.bitwarden.data.vault.repository.model.CreateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateFolderResult
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.model.FolderAddEditType
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@ -35,6 +38,7 @@ private const val KEY_STATE = "state"
|
||||
class FolderAddEditViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val relayManager: SnackbarRelayManager,
|
||||
) : BaseViewModel<FolderAddEditState, FolderAddEditEvent, FolderAddEditAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
@ -263,7 +267,10 @@ class FolderAddEditViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is UpdateFolderResult.Success -> {
|
||||
sendEvent(FolderAddEditEvent.ShowToast(BitwardenString.folder_updated.asText()))
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_updated.asText()),
|
||||
relay = SnackbarRelay.FOLDER_UPDATED,
|
||||
)
|
||||
sendEvent(FolderAddEditEvent.NavigateBack)
|
||||
}
|
||||
}
|
||||
@ -289,7 +296,10 @@ class FolderAddEditViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is CreateFolderResult.Success -> {
|
||||
sendEvent(FolderAddEditEvent.ShowToast(BitwardenString.folder_created.asText()))
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_created.asText()),
|
||||
relay = SnackbarRelay.FOLDER_CREATED,
|
||||
)
|
||||
sendEvent(FolderAddEditEvent.NavigateBack)
|
||||
}
|
||||
}
|
||||
@ -312,7 +322,10 @@ class FolderAddEditViewModel @Inject constructor(
|
||||
|
||||
DeleteFolderResult.Success -> {
|
||||
mutableStateFlow.update { it.copy(dialog = null) }
|
||||
sendEvent(FolderAddEditEvent.ShowToast(BitwardenString.folder_deleted.asText()))
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_deleted.asText()),
|
||||
relay = SnackbarRelay.FOLDER_DELETED,
|
||||
)
|
||||
sendEvent(event = FolderAddEditEvent.NavigateBack)
|
||||
}
|
||||
}
|
||||
@ -416,11 +429,6 @@ sealed class FolderAddEditEvent {
|
||||
* Navigate back to previous screen.
|
||||
*/
|
||||
data object NavigateBack : FolderAddEditEvent()
|
||||
|
||||
/**
|
||||
* Shows a toast with the given [message].
|
||||
*/
|
||||
data class ShowToast(val message: Text) : FolderAddEditEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -16,6 +16,9 @@ enum class SnackbarRelay {
|
||||
CIPHER_RESTORED,
|
||||
CIPHER_UPDATED,
|
||||
ENVIRONMENT_SAVED,
|
||||
FOLDER_CREATED,
|
||||
FOLDER_DELETED,
|
||||
FOLDER_UPDATED,
|
||||
LOGIN_APPROVAL,
|
||||
LOGIN_SUCCESS,
|
||||
LOGINS_IMPORTED,
|
||||
|
||||
@ -189,6 +189,7 @@ class VaultViewModel @Inject constructor(
|
||||
SnackbarRelay.CIPHER_DELETED_SOFT,
|
||||
SnackbarRelay.CIPHER_RESTORED,
|
||||
SnackbarRelay.CIPHER_UPDATED,
|
||||
SnackbarRelay.FOLDER_CREATED,
|
||||
SnackbarRelay.LOGINS_IMPORTED,
|
||||
),
|
||||
)
|
||||
|
||||
@ -70,6 +70,14 @@ class CompleteRegistrationScreenTest : BitwardenComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on ShowSnackbar should display snackbar content`() {
|
||||
val message = "message"
|
||||
composeTestRule.onNodeWithText(text = message).assertDoesNotExist()
|
||||
mutableEventFlow.tryEmit(CompleteRegistrationEvent.ShowSnackbar(message = message.asText()))
|
||||
composeTestRule.onNodeWithText(text = message).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `close click should send CloseClick action`() {
|
||||
composeTestRule.onNodeWithContentDescription("Back").performClick()
|
||||
|
||||
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.auth.feature.completeregistration
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.data.manager.toast.ToastManager
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager
|
||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
@ -38,6 +39,7 @@ 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
|
||||
@ -46,7 +48,6 @@ import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@ -60,13 +61,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
private val mutableUserStateFlow = MutableStateFlow<UserState?>(null)
|
||||
private val mockAuthRepository = mockk<AuthRepository> {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
coEvery {
|
||||
login(
|
||||
email = any(),
|
||||
password = any(),
|
||||
)
|
||||
} returns LoginResult.Success
|
||||
|
||||
coEvery { login(email = any(), password = any()) } returns LoginResult.Success
|
||||
coEvery {
|
||||
register(
|
||||
email = any(),
|
||||
@ -77,10 +72,10 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
isMasterPasswordStrong = any(),
|
||||
)
|
||||
} returns RegisterResult.Success
|
||||
|
||||
coEvery {
|
||||
setOnboardingStatus(OnboardingStatus.NOT_STARTED)
|
||||
} just Runs
|
||||
coEvery { setOnboardingStatus(OnboardingStatus.NOT_STARTED) } just Runs
|
||||
}
|
||||
private val toastManager: ToastManager = mockk {
|
||||
every { show(messageId = any(), duration = any()) } just runs
|
||||
}
|
||||
|
||||
private val fakeEnvironmentRepository = FakeEnvironmentRepository()
|
||||
@ -155,21 +150,18 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
)
|
||||
} returns RegisterResult.Success
|
||||
val viewModel = createCompleteRegistrationViewModel(VALID_INPUT_STATE)
|
||||
viewModel.stateEventFlow(backgroundScope) { stateFlow, eventFlow ->
|
||||
assertEquals(VALID_INPUT_STATE, stateFlow.awaitItem())
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(VALID_INPUT_STATE, awaitItem())
|
||||
viewModel.trySendAction(CompleteRegistrationAction.CallToActionClick)
|
||||
assertEquals(
|
||||
VALID_INPUT_STATE.copy(dialog = CompleteRegistrationDialog.Loading),
|
||||
stateFlow.awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
CompleteRegistrationEvent.ShowToast(
|
||||
BitwardenString.account_created_success.asText(),
|
||||
),
|
||||
eventFlow.awaitItem(),
|
||||
awaitItem(),
|
||||
)
|
||||
// Make sure loading dialog is hidden:
|
||||
assertEquals(VALID_INPUT_STATE, stateFlow.awaitItem())
|
||||
assertEquals(VALID_INPUT_STATE, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
toastManager.show(messageId = BitwardenString.account_created_success)
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +216,6 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
val viewModel = createCompleteRegistrationViewModel(VALID_INPUT_STATE)
|
||||
viewModel.trySendAction(CompleteRegistrationAction.CallToActionClick)
|
||||
viewModel.eventFlow.test {
|
||||
assertTrue(awaitItem() is CompleteRegistrationEvent.ShowToast)
|
||||
expectNoEvents()
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
@ -246,7 +237,6 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
val viewModel = createCompleteRegistrationViewModel(VALID_INPUT_STATE)
|
||||
viewModel.trySendAction(CompleteRegistrationAction.CallToActionClick)
|
||||
viewModel.eventFlow.test {
|
||||
assertTrue(awaitItem() is CompleteRegistrationEvent.ShowToast)
|
||||
assertEquals(
|
||||
CompleteRegistrationEvent.NavigateToLogin(EMAIL),
|
||||
awaitItem(),
|
||||
@ -404,13 +394,13 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `On init should show toast if from email is true`() = runTest {
|
||||
fun `On init should show snackbar if from email is true`() = runTest {
|
||||
val viewModel = createCompleteRegistrationViewModel(
|
||||
DEFAULT_STATE.copy(fromEmail = true),
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
CompleteRegistrationEvent.ShowToast(BitwardenString.email_verified.asText()),
|
||||
CompleteRegistrationEvent.ShowSnackbar(BitwardenString.email_verified.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
@ -666,6 +656,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
specialCircumstanceManager = specialCircumstanceManager,
|
||||
generatorRepository = generatorRepository,
|
||||
toastManager = toastManager,
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@ -3,13 +3,16 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.folders
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.DateTime
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.bitwarden.ui.util.concat
|
||||
import com.bitwarden.vault.FolderView
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.model.FolderDisplayItem
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@ -25,6 +28,26 @@ class FoldersViewModelTest : BaseViewModelTest() {
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { foldersStateFlow } returns mutableFoldersStateFlow
|
||||
}
|
||||
private val mutableSnackbarDataFlow = bufferedMutableSharedFlow<BitwardenSnackbarData>()
|
||||
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||
every {
|
||||
getSnackbarDataFlow(relay = any(), relays = anyVararg())
|
||||
} returns mutableSnackbarDataFlow
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on snackbar data received should emit ShowSnackbar`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
val data = BitwardenSnackbarData(message = "Snackbar!".asText())
|
||||
viewModel.eventFlow.test {
|
||||
mutableSnackbarDataFlow.emit(data)
|
||||
assertEquals(
|
||||
FoldersEvent.ShowSnackbar(data = data),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `BackClick should emit NavigateBack`() = runTest {
|
||||
@ -161,6 +184,7 @@ class FoldersViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private fun createViewModel(): FoldersViewModel = FoldersViewModel(
|
||||
vaultRepository = vaultRepository,
|
||||
snackbarRelayManager = snackbarRelayManager,
|
||||
)
|
||||
|
||||
private fun createFolderState(
|
||||
|
||||
@ -5,6 +5,7 @@ import app.cash.turbine.test
|
||||
import com.bitwarden.core.DateTime
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
|
||||
import com.bitwarden.ui.platform.resource.BitwardenString
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.bitwarden.ui.util.concat
|
||||
@ -14,11 +15,15 @@ import com.x8bit.bitwarden.data.vault.repository.model.CreateFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.DeleteFolderResult
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.UpdateFolderResult
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.model.FolderAddEditType
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||
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
|
||||
@ -38,6 +43,9 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { getVaultFolderStateFlow(DEFAULT_EDIT_ITEM_ID) } returns mutableFoldersStateFlow
|
||||
}
|
||||
private val relayManager: SnackbarRelayManager = mockk {
|
||||
every { sendSnackbarData(data = any(), relay = any()) } just runs
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
@ -125,15 +133,17 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
viewModel.trySendAction(FolderAddEditAction.DeleteClick)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(
|
||||
FolderAddEditEvent.ShowToast(BitwardenString.folder_deleted.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
FolderAddEditEvent.NavigateBack,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_deleted.asText()),
|
||||
relay = SnackbarRelay.FOLDER_DELETED,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@ -180,6 +190,12 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
assertEquals(stateWithDialog, awaitItem())
|
||||
assertEquals(stateWithoutDialog, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_deleted.asText()),
|
||||
relay = SnackbarRelay.FOLDER_DELETED,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@ -322,6 +338,12 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
assertEquals(stateWithDialog, awaitItem())
|
||||
assertEquals(stateWithoutDialog, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_created.asText()),
|
||||
relay = SnackbarRelay.FOLDER_CREATED,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@ -348,9 +370,7 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
vaultRepository.createFolder(any())
|
||||
} returns CreateFolderResult.Success(mockk())
|
||||
viewModel.trySendAction(FolderAddEditAction.SaveClick)
|
||||
coVerify(
|
||||
exactly = 1,
|
||||
) {
|
||||
coVerify(exactly = 1) {
|
||||
vaultRepository.createFolder(
|
||||
folderView = FolderView(
|
||||
name = DEFAULT_FOLDER_NAME,
|
||||
@ -359,6 +379,12 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
),
|
||||
)
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_created.asText()),
|
||||
relay = SnackbarRelay.FOLDER_CREATED,
|
||||
)
|
||||
}
|
||||
unmockkStatic(DateTime::class)
|
||||
}
|
||||
|
||||
@ -387,9 +413,7 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
vaultRepository.createFolder(any())
|
||||
} returns CreateFolderResult.Success(mockk())
|
||||
viewModel.trySendAction(FolderAddEditAction.SaveClick)
|
||||
coVerify(
|
||||
exactly = 1,
|
||||
) {
|
||||
coVerify(exactly = 1) {
|
||||
vaultRepository.createFolder(
|
||||
folderView = FolderView(
|
||||
name = "$parentFolderName/$DEFAULT_FOLDER_NAME",
|
||||
@ -398,6 +422,12 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
),
|
||||
)
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_created.asText()),
|
||||
relay = SnackbarRelay.FOLDER_CREATED,
|
||||
)
|
||||
}
|
||||
unmockkStatic(DateTime::class)
|
||||
}
|
||||
|
||||
@ -483,6 +513,12 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
assertEquals(stateWithDialog, awaitItem())
|
||||
assertEquals(stateWithoutDialog, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
relayManager.sendSnackbarData(
|
||||
data = BitwardenSnackbarData(BitwardenString.folder_updated.asText()),
|
||||
relay = SnackbarRelay.FOLDER_UPDATED,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -758,6 +794,7 @@ class FolderAddEditViewModelTest : BaseViewModelTest() {
|
||||
): FolderAddEditViewModel = FolderAddEditViewModel(
|
||||
savedStateHandle = savedStateHandle,
|
||||
vaultRepository = vaultRepository,
|
||||
relayManager = relayManager,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user