mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Use a DialogState in LandingState (#341)
This commit is contained in:
parent
ed970f1956
commit
5ffe9c914d
4 changed files with 74 additions and 31 deletions
|
@ -47,6 +47,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAccountSwitcher
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
||||
|
@ -84,12 +86,21 @@ fun LandingScreen(
|
|||
}
|
||||
}
|
||||
|
||||
BitwardenBasicDialog(
|
||||
visibilityState = state.errorDialogState,
|
||||
onDismissRequest = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.ErrorDialogDismiss) }
|
||||
},
|
||||
)
|
||||
when (val dialog = state.dialog) {
|
||||
is LandingState.DialogState.Error -> {
|
||||
BitwardenBasicDialog(
|
||||
visibilityState = BasicDialogState.Shown(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = dialog.message,
|
||||
),
|
||||
onDismissRequest = remember(viewModel) {
|
||||
{ viewModel.trySendAction(LandingAction.DialogDismiss) }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
null -> Unit
|
||||
}
|
||||
|
||||
val isAppBarVisible = state.accountSummaries.isNotEmpty()
|
||||
var isAccountMenuVisible by rememberSaveable { mutableStateOf(false) }
|
||||
|
|
|
@ -8,9 +8,9 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.isValidEmail
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toAccountSummaries
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
@ -37,7 +37,7 @@ class LandingViewModel @Inject constructor(
|
|||
isContinueButtonEnabled = authRepository.rememberedEmailAddress != null,
|
||||
isRememberMeEnabled = authRepository.rememberedEmailAddress != null,
|
||||
selectedEnvironmentType = environmentRepository.environment.type,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
dialog = null,
|
||||
accountSummaries = authRepository.userStateFlow.value?.toAccountSummaries().orEmpty(),
|
||||
),
|
||||
) {
|
||||
|
@ -67,7 +67,7 @@ class LandingViewModel @Inject constructor(
|
|||
is LandingAction.SwitchAccountClick -> handleSwitchAccountClicked(action)
|
||||
is LandingAction.ContinueButtonClick -> handleContinueButtonClicked()
|
||||
LandingAction.CreateAccountClick -> handleCreateAccountClicked()
|
||||
is LandingAction.ErrorDialogDismiss -> handleErrorDialogDismiss()
|
||||
is LandingAction.DialogDismiss -> handleDialogDismiss()
|
||||
is LandingAction.RememberMeToggle -> handleRememberMeToggled(action)
|
||||
is LandingAction.EmailInputChanged -> handleEmailInputUpdated(action)
|
||||
is LandingAction.EnvironmentTypeSelect -> handleEnvironmentTypeSelect(action)
|
||||
|
@ -95,8 +95,7 @@ class LandingViewModel @Inject constructor(
|
|||
if (!mutableStateFlow.value.emailInput.isValidEmail()) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
errorDialogState = BasicDialogState.Shown(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
dialog = LandingState.DialogState.Error(
|
||||
message = R.string.invalid_email.asText(),
|
||||
),
|
||||
)
|
||||
|
@ -117,9 +116,9 @@ class LandingViewModel @Inject constructor(
|
|||
sendEvent(LandingEvent.NavigateToCreateAccount)
|
||||
}
|
||||
|
||||
private fun handleErrorDialogDismiss() {
|
||||
private fun handleDialogDismiss() {
|
||||
mutableStateFlow.update {
|
||||
it.copy(errorDialogState = BasicDialogState.Hidden)
|
||||
it.copy(dialog = null)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,9 +162,23 @@ data class LandingState(
|
|||
val isContinueButtonEnabled: Boolean,
|
||||
val isRememberMeEnabled: Boolean,
|
||||
val selectedEnvironmentType: Environment.Type,
|
||||
val errorDialogState: BasicDialogState,
|
||||
val dialog: DialogState?,
|
||||
val accountSummaries: List<AccountSummary>,
|
||||
) : Parcelable
|
||||
) : Parcelable {
|
||||
/**
|
||||
* Represents the current state of any dialogs on screen.
|
||||
*/
|
||||
sealed class DialogState : Parcelable {
|
||||
|
||||
/**
|
||||
* Represents an error dialog with the given [message].
|
||||
*/
|
||||
@Parcelize
|
||||
data class Error(
|
||||
val message: Text,
|
||||
) : DialogState()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Models events for the landing screen.
|
||||
|
@ -211,9 +224,9 @@ sealed class LandingAction {
|
|||
data object CreateAccountClick : LandingAction()
|
||||
|
||||
/**
|
||||
* Indicates that an error dialog is attempting to be dismissed.
|
||||
* Indicates that a dialog is attempting to be dismissed.
|
||||
*/
|
||||
data object ErrorDialogDismiss : LandingAction()
|
||||
data object DialogDismiss : LandingAction()
|
||||
|
||||
/**
|
||||
* Indicates that the Remember Me switch has been toggled.
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.test.core.app.ApplicationProvider
|
|||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
@ -236,8 +235,7 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
errorDialogState = BasicDialogState.Shown(
|
||||
title = "Error dialog title".asText(),
|
||||
dialog = LandingState.DialogState.Error(
|
||||
message = "Error dialog message".asText(),
|
||||
),
|
||||
)
|
||||
|
@ -246,7 +244,7 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
composeTestRule.onNode(isDialog()).assertIsDisplayed()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Error dialog title")
|
||||
.onNodeWithText("An error has occurred.")
|
||||
.assert(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
composeTestRule
|
||||
|
@ -260,11 +258,10 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `error dialog OK click should send ErrorDialogDismiss action`() {
|
||||
fun `error dialog OK click should send DialogDismiss action`() {
|
||||
mutableStateFlow.update {
|
||||
DEFAULT_STATE.copy(
|
||||
errorDialogState = BasicDialogState.Shown(
|
||||
title = "title".asText(),
|
||||
dialog = LandingState.DialogState.Error(
|
||||
message = "message".asText(),
|
||||
),
|
||||
)
|
||||
|
@ -274,7 +271,7 @@ class LandingScreenTest : BaseComposeTest() {
|
|||
.onAllNodesWithText("Ok")
|
||||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
verify { viewModel.trySendAction(LandingAction.ErrorDialogDismiss) }
|
||||
verify { viewModel.trySendAction(LandingAction.DialogDismiss) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,6 +288,6 @@ private val DEFAULT_STATE = LandingState(
|
|||
isContinueButtonEnabled = true,
|
||||
isRememberMeEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
dialog = null,
|
||||
accountSummaries = emptyList(),
|
||||
)
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
|||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toAccountSummaries
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
@ -112,8 +111,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
viewModel.actionChannel.trySend(LandingAction.ContinueButtonClick)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
errorDialogState = BasicDialogState.Shown(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
dialog = LandingState.DialogState.Error(
|
||||
message = R.string.invalid_email.asText(),
|
||||
),
|
||||
),
|
||||
|
@ -134,6 +132,27 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DialogDismiss should clear the active dialog`() {
|
||||
val initialState = DEFAULT_STATE.copy(
|
||||
dialog = LandingState.DialogState.Error(
|
||||
message = "Error".asText(),
|
||||
),
|
||||
)
|
||||
val viewModel = createViewModel(initialState = initialState)
|
||||
assertEquals(
|
||||
initialState,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
|
||||
viewModel.trySendAction(LandingAction.DialogDismiss)
|
||||
|
||||
assertEquals(
|
||||
initialState.copy(dialog = null),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RememberMeToggle should update value of isRememberMeToggled`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
@ -206,9 +225,12 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
//region Helper methods
|
||||
|
||||
private fun createViewModel(
|
||||
initialState: LandingState? = null,
|
||||
rememberedEmail: String? = null,
|
||||
userState: UserState? = null,
|
||||
savedStateHandle: SavedStateHandle = SavedStateHandle(),
|
||||
savedStateHandle: SavedStateHandle = SavedStateHandle(
|
||||
initialState = mapOf("state" to initialState),
|
||||
),
|
||||
): LandingViewModel = LandingViewModel(
|
||||
authRepository = mockk(relaxed = true) {
|
||||
every { rememberedEmailAddress } returns rememberedEmail
|
||||
|
@ -226,7 +248,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
|||
isContinueButtonEnabled = false,
|
||||
isRememberMeEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
dialog = null,
|
||||
accountSummaries = emptyList(),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue