BIT-1496: Generator Prompt Overwrite Confirmation (#755)

This commit is contained in:
Joshua Queen 2024-01-24 18:14:33 -05:00 committed by Álison Fernandes
parent 4fcbf4704d
commit 65e85b02f8
2 changed files with 145 additions and 49 deletions

View file

@ -9,6 +9,11 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -25,6 +30,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitchWithActions
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextFieldWithActions
import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditCommonHandlers
import com.x8bit.bitwarden.ui.vault.feature.addedit.handlers.VaultAddEditLoginTypeHandlers
@ -58,58 +64,18 @@ fun LazyListScope.vaultAddEditLoginItems(
item {
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextFieldWithActions(
label = stringResource(id = R.string.username),
value = loginState.username,
onValueChange = loginItemTypeHandlers.onUsernameTextChange,
actions = {
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_generator),
contentDescription = stringResource(id = R.string.generate_username),
),
onClick = loginItemTypeHandlers.onOpenUsernameGeneratorClick,
)
},
modifier = Modifier.padding(horizontal = 16.dp),
UsernameRow(
loginState = loginState,
loginItemTypeHandlers = loginItemTypeHandlers,
)
}
item {
Spacer(modifier = Modifier.height(8.dp))
if (loginState.canViewPassword) {
BitwardenPasswordFieldWithActions(
label = stringResource(id = R.string.password),
value = loginState.password,
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
) {
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_check_mark),
contentDescription = stringResource(id = R.string.check_password),
),
onClick = loginItemTypeHandlers.onPasswordCheckerClick,
)
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_generator),
contentDescription = stringResource(id = R.string.generate_password),
),
onClick = loginItemTypeHandlers.onOpenPasswordGeneratorClick,
)
}
} else {
BitwardenHiddenPasswordField(
label = stringResource(id = R.string.password),
value = loginState.password,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
PasswordRow(
loginState = loginState,
loginItemTypeHandlers = loginItemTypeHandlers,
)
}
item {
@ -362,3 +328,113 @@ fun LazyListScope.vaultAddEditLoginItems(
Spacer(modifier = Modifier.height(24.dp))
}
}
@Composable
private fun UsernameRow(
loginState: VaultAddEditState.ViewState.Content.ItemType.Login,
loginItemTypeHandlers: VaultAddEditLoginTypeHandlers,
) {
var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
BitwardenTextFieldWithActions(
label = stringResource(id = R.string.username),
value = loginState.username,
onValueChange = loginItemTypeHandlers.onUsernameTextChange,
actions = {
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_generator),
contentDescription = stringResource(id = R.string.generate_username),
),
onClick = { shouldShowDialog = true },
)
},
modifier = Modifier.padding(horizontal = 16.dp),
)
if (shouldShowDialog) {
BitwardenTwoButtonDialog(
title = stringResource(id = R.string.username),
message = stringResource(
id =
R.string.are_you_sure_you_want_to_overwrite_the_current_username,
),
confirmButtonText = stringResource(id = R.string.yes),
dismissButtonText = stringResource(id = R.string.no),
onConfirmClick = {
shouldShowDialog = false
loginItemTypeHandlers.onOpenUsernameGeneratorClick()
},
onDismissClick = {
shouldShowDialog = false
},
onDismissRequest = {
shouldShowDialog = false
},
)
}
}
@Composable
private fun PasswordRow(
loginState: VaultAddEditState.ViewState.Content.ItemType.Login,
loginItemTypeHandlers: VaultAddEditLoginTypeHandlers,
) {
var shouldShowDialog by rememberSaveable { mutableStateOf(false) }
if (loginState.canViewPassword) {
BitwardenPasswordFieldWithActions(
label = stringResource(id = R.string.password),
value = loginState.password,
onValueChange = loginItemTypeHandlers.onPasswordTextChange,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
) {
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_check_mark),
contentDescription = stringResource(id = R.string.check_password),
),
onClick = loginItemTypeHandlers.onPasswordCheckerClick,
)
BitwardenIconButtonWithResource(
iconRes = IconResource(
iconPainter = painterResource(id = R.drawable.ic_generator),
contentDescription = stringResource(id = R.string.generate_password),
),
onClick = { shouldShowDialog = true },
)
if (shouldShowDialog) {
BitwardenTwoButtonDialog(
title = stringResource(id = R.string.password),
message = stringResource(
id =
R.string.password_override_alert,
),
confirmButtonText = stringResource(id = R.string.yes),
dismissButtonText = stringResource(id = R.string.no),
onConfirmClick = {
shouldShowDialog = false
loginItemTypeHandlers.onOpenPasswordGeneratorClick()
},
onDismissClick = {
shouldShowDialog = false
},
onDismissRequest = {
shouldShowDialog = false
},
)
}
}
} else {
BitwardenHiddenPasswordField(
label = stringResource(id = R.string.password),
value = loginState.password,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
}

View file

@ -1,6 +1,7 @@
package com.x8bit.bitwarden.ui.vault.feature.addedit
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotDisplayed
@ -34,6 +35,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
import com.x8bit.bitwarden.ui.platform.base.util.asText
import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
import com.x8bit.bitwarden.ui.util.isProgressBar
import com.x8bit.bitwarden.ui.util.onAllNodesWithContentDescriptionAfterScroll
import com.x8bit.bitwarden.ui.util.onAllNodesWithTextAfterScroll
@ -406,11 +408,20 @@ class VaultAddEditScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state clicking Username generator action should trigger OpenUsernameGeneratorClick`() {
fun `in ItemType_Login state clicking Username generator action should open dialog that triggers OpenUsernameGeneratorClick`() {
composeTestRule.assertNoDialogExists()
composeTestRule
.onNodeWithContentDescriptionAfterScroll(label = "Generate username")
.performClick()
composeTestRule
.onNodeWithText("Yes")
.assert(hasAnyAncestor(isDialog()))
.performClick()
composeTestRule.assertNoDialogExists()
verify {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.OpenUsernameGeneratorClick,
@ -434,13 +445,22 @@ class VaultAddEditScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength")
@Test
fun `in ItemType_Login state click Password text field generator action should trigger OpenPasswordGeneratorClick`() {
fun `in ItemType_Login state click Password text field generator action should open dialog that triggers OpenPasswordGeneratorClick`() {
composeTestRule.assertNoDialogExists()
composeTestRule
.onNodeWithTextAfterScroll(text = "Password")
.onSiblings()
.onLast()
.performClick()
composeTestRule
.onNodeWithText("Yes")
.assert(hasAnyAncestor(isDialog()))
.performClick()
composeTestRule.assertNoDialogExists()
verify {
viewModel.trySendAction(
VaultAddEditAction.ItemType.LoginType.OpenPasswordGeneratorClick,