Add UI support for hiding all button on TrustedDeviceScreen (#1152)

This commit is contained in:
David Perez 2024-03-18 12:54:26 -05:00 committed by Álison Fernandes
parent f080b2cb8b
commit e012dbf45d
5 changed files with 161 additions and 31 deletions

View file

@ -110,35 +110,53 @@ private fun TrustedDeviceScaffold(
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
BitwardenFilledButton(
label = stringResource(id = R.string.approve_with_my_other_device),
onClick = handlers.onApproveWithDeviceClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
if (state.showContinueButton) {
BitwardenFilledButton(
label = stringResource(id = R.string.continue_text),
onClick = handlers.onContinueClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
}
if (state.showOtherDeviceButton) {
BitwardenFilledButton(
label = stringResource(id = R.string.approve_with_my_other_device),
onClick = handlers.onApproveWithDeviceClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
}
if (state.showRequestAdminButton) {
BitwardenOutlinedButton(
label = stringResource(id = R.string.request_admin_approval),
onClick = handlers.onApproveWithAdminClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
}
if (state.showMasterPasswordButton) {
BitwardenOutlinedButton(
label = stringResource(id = R.string.approve_with_master_password),
onClick = handlers.onApproveWithPasswordClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
}
Spacer(modifier = Modifier.height(12.dp))
BitwardenOutlinedButton(
label = stringResource(id = R.string.request_admin_approval),
onClick = handlers.onApproveWithAdminClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
BitwardenOutlinedButton(
label = stringResource(id = R.string.approve_with_master_password),
onClick = handlers.onApproveWithPasswordClick,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(
id = R.string.logging_in_as_x_on_y,
@ -174,10 +192,15 @@ private fun TrustedDeviceScaffold_preview() {
isRemembered = false,
emailAddress = "email@bitwarden.com",
environmentLabel = "vault.bitwarden.pw",
showContinueButton = false,
showOtherDeviceButton = true,
showRequestAdminButton = true,
showMasterPasswordButton = true,
),
handlers = TrustedDeviceHandlers(
onBackClick = {},
onRememberToggle = {},
onContinueClick = {},
onApproveWithAdminClick = {},
onApproveWithDeviceClick = {},
onApproveWithPasswordClick = {},

View file

@ -22,16 +22,23 @@ class TrustedDeviceViewModel @Inject constructor(
environmentRepository: EnvironmentRepository,
) : BaseViewModel<TrustedDeviceState, TrustedDeviceEvent, TrustedDeviceAction>(
initialState = savedStateHandle[KEY_STATE]
?: TrustedDeviceState(
emailAddress = TrustedDeviceArgs(savedStateHandle).emailAddress,
environmentLabel = environmentRepository.environment.label,
isRemembered = false,
),
?: run {
TrustedDeviceState(
emailAddress = TrustedDeviceArgs(savedStateHandle).emailAddress,
environmentLabel = environmentRepository.environment.label,
isRemembered = false,
showContinueButton = false,
showOtherDeviceButton = false,
showRequestAdminButton = false,
showMasterPasswordButton = false,
)
},
) {
override fun handleAction(action: TrustedDeviceAction) {
when (action) {
TrustedDeviceAction.BackClick -> handleBackClick()
is TrustedDeviceAction.RememberToggle -> handleRememberToggle(action)
TrustedDeviceAction.ContinueClick -> handleContinueClick()
TrustedDeviceAction.ApproveWithAdminClick -> handleApproveWithAdminClick()
TrustedDeviceAction.ApproveWithDeviceClick -> handleApproveWithDeviceClick()
TrustedDeviceAction.ApproveWithPasswordClick -> handleApproveWithPasswordClick()
@ -47,6 +54,10 @@ class TrustedDeviceViewModel @Inject constructor(
mutableStateFlow.update { it.copy(isRemembered = action.isRemembered) }
}
private fun handleContinueClick() {
sendEvent(TrustedDeviceEvent.ShowToast("Not yet implemented".asText()))
}
private fun handleApproveWithAdminClick() {
sendEvent(TrustedDeviceEvent.ShowToast("Not yet implemented".asText()))
}
@ -72,6 +83,10 @@ data class TrustedDeviceState(
val emailAddress: String,
val environmentLabel: String,
val isRemembered: Boolean,
val showContinueButton: Boolean,
val showOtherDeviceButton: Boolean,
val showRequestAdminButton: Boolean,
val showMasterPasswordButton: Boolean,
) : Parcelable
/**
@ -105,6 +120,11 @@ sealed class TrustedDeviceAction {
val isRemembered: Boolean,
) : TrustedDeviceAction()
/**
* User clicked the "Continue" button.
*/
data object ContinueClick : TrustedDeviceAction()
/**
* User clicked the "Approve with my other device" button.
*/

View file

@ -10,6 +10,7 @@ import com.x8bit.bitwarden.ui.auth.feature.trusteddevice.TrustedDeviceViewModel
data class TrustedDeviceHandlers(
val onBackClick: () -> Unit,
val onRememberToggle: (Boolean) -> Unit,
val onContinueClick: () -> Unit,
val onApproveWithDeviceClick: () -> Unit,
val onApproveWithAdminClick: () -> Unit,
val onApproveWithPasswordClick: () -> Unit,
@ -26,6 +27,7 @@ data class TrustedDeviceHandlers(
onRememberToggle = {
viewModel.trySendAction(TrustedDeviceAction.RememberToggle(it))
},
onContinueClick = { viewModel.trySendAction(TrustedDeviceAction.ContinueClick) },
onApproveWithDeviceClick = {
viewModel.trySendAction(TrustedDeviceAction.ApproveWithDeviceClick)
},

View file

@ -64,6 +64,45 @@ class TrustedDeviceScreenTest : BaseComposeTest() {
}
}
@Test
fun `continue button should be displayed according to state`() {
composeTestRule
.onNodeWithText("Continue")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update { it.copy(showContinueButton = false) }
composeTestRule
.onNodeWithText("Continue")
.assertDoesNotExist()
}
@Test
fun `on continue clicked should send ContinueClick`() {
composeTestRule
.onNodeWithText("Continue")
.performScrollTo()
.performClick()
verify(exactly = 1) {
viewModel.trySendAction(TrustedDeviceAction.ContinueClick)
}
}
@Test
fun `other device button should be displayed according to state`() {
composeTestRule
.onNodeWithText("Approve with my other device")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update { it.copy(showOtherDeviceButton = false) }
composeTestRule
.onNodeWithText("Approve with my other device")
.assertDoesNotExist()
}
@Test
fun `on approve with device clicked should send ApproveWithDeviceClick`() {
composeTestRule
@ -75,6 +114,20 @@ class TrustedDeviceScreenTest : BaseComposeTest() {
}
}
@Test
fun `admin approval button should be displayed according to state`() {
composeTestRule
.onNodeWithText("Request admin approval")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update { it.copy(showRequestAdminButton = false) }
composeTestRule
.onNodeWithText("Request admin approval")
.assertDoesNotExist()
}
@Test
fun `on approve with admin clicked should send ApproveWithAdminClick`() {
composeTestRule
@ -86,6 +139,20 @@ class TrustedDeviceScreenTest : BaseComposeTest() {
}
}
@Test
fun `master password button should be displayed according to state`() {
composeTestRule
.onNodeWithText("Approve with master password")
.performScrollTo()
.assertIsDisplayed()
mutableStateFlow.update { it.copy(showMasterPasswordButton = false) }
composeTestRule
.onNodeWithText("Approve with master password")
.assertDoesNotExist()
}
@Test
fun `on approve with master password clicked should send ApproveWithPasswordClick`() {
composeTestRule
@ -158,4 +225,8 @@ private val DEFAULT_STATE: TrustedDeviceState = TrustedDeviceState(
emailAddress = "email@bitwarden.com",
environmentLabel = "vault.bitwarden.pw",
isRemembered = false,
showContinueButton = true,
showOtherDeviceButton = true,
showRequestAdminButton = true,
showMasterPasswordButton = true,
)

View file

@ -37,6 +37,16 @@ class TrustedDeviceViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `on ContinueClick emits ShowToast`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(TrustedDeviceAction.ContinueClick)
assertEquals(TrustedDeviceEvent.ShowToast("Not yet implemented".asText()), awaitItem())
}
}
@Test
fun `on ApproveWithAdminClick emits ShowToast`() = runTest {
val viewModel = createViewModel()
@ -94,4 +104,8 @@ private val DEFAULT_STATE: TrustedDeviceState = TrustedDeviceState(
emailAddress = "email@bitwarden.com",
environmentLabel = "bitwarden.com",
isRemembered = false,
showContinueButton = false,
showOtherDeviceButton = false,
showRequestAdminButton = false,
showMasterPasswordButton = false,
)