BIT-868 Keep password fields on create account in sync (#125)

This commit is contained in:
Andrew Haisting
2023-10-18 13:29:48 -05:00
committed by Álison Fernandes
parent 9483d58d81
commit 77f693e159
3 changed files with 105 additions and 29 deletions

View File

@@ -23,7 +23,10 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
@@ -124,8 +127,11 @@ fun CreateAccountScreen(
.padding(horizontal = 16.dp),
)
Spacer(modifier = Modifier.height(16.dp))
var showPassword by rememberSaveable { mutableStateOf(false) }
BitwardenPasswordField(
label = stringResource(id = R.string.master_password),
showPassword = showPassword,
showPasswordChange = { showPassword = it },
value = state.passwordInput,
onValueChange = remember(viewModel) {
{ viewModel.trySendAction(PasswordInputChange(it)) }
@@ -138,6 +144,8 @@ fun CreateAccountScreen(
BitwardenPasswordField(
label = stringResource(id = R.string.retype_master_password),
value = state.confirmPasswordInput,
showPassword = showPassword,
showPasswordChange = { showPassword = it },
onValueChange = remember(viewModel) {
{ viewModel.trySendAction(ConfirmPasswordInputChange(it)) }
},

View File

@@ -20,6 +20,62 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import com.x8bit.bitwarden.R
/**
* Represents a Bitwarden-styled password field that hoists show/hide password state to the caller.
*
* See overloaded [BitwardenPasswordField] for self managed show/hide state.
*
* @param label Label for the text field.
* @param value Current next on the text field.
* @param showPassword Whether or not password should be shown.
* @param showPasswordChange Lambda that is called when user request show/hide be toggled.
* @param onValueChange Callback that is triggered when the password changes.
* @param modifier Modifier for the composable.
*/
@Composable
fun BitwardenPasswordField(
label: String,
value: String,
showPassword: Boolean,
showPasswordChange: (Boolean) -> Unit,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
) {
OutlinedTextField(
modifier = modifier,
textStyle = MaterialTheme.typography.bodyLarge,
label = { Text(text = label) },
value = value,
onValueChange = onValueChange,
visualTransformation = if (showPassword) {
VisualTransformation.None
} else {
PasswordVisualTransformation()
},
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
IconButton(
onClick = { showPasswordChange.invoke(!showPassword) },
) {
if (showPassword) {
Icon(
painter = painterResource(id = R.drawable.ic_visibility_off),
contentDescription = stringResource(id = R.string.hide),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
} else {
Icon(
painter = painterResource(id = R.drawable.ic_visibility),
contentDescription = stringResource(id = R.string.show),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
},
)
}
/**
* Represents a Bitwarden-styled password field that manages the state of a show/hide indicator
* internally.
@@ -40,38 +96,13 @@ fun BitwardenPasswordField(
initialShowPassword: Boolean = false,
) {
var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) }
OutlinedTextField(
BitwardenPasswordField(
modifier = modifier,
textStyle = MaterialTheme.typography.bodyLarge,
label = { Text(text = label) },
label = label,
value = value,
showPassword = showPassword,
showPasswordChange = { showPassword = !showPassword },
onValueChange = onValueChange,
visualTransformation = if (showPassword) {
VisualTransformation.None
} else {
PasswordVisualTransformation()
},
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
IconButton(
onClick = { showPassword = !showPassword },
) {
if (showPassword) {
Icon(
painter = painterResource(id = R.drawable.ic_visibility_off),
contentDescription = stringResource(id = R.string.hide),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
} else {
Icon(
painter = painterResource(id = R.drawable.ic_visibility),
contentDescription = stringResource(id = R.string.show),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
},
)
}