From d10e678bb376817236347c3e95c8921eb46aa4c6 Mon Sep 17 00:00:00 2001 From: Brian Yencho Date: Fri, 3 Nov 2023 09:35:15 -0500 Subject: [PATCH] Add optional "hint" to BitwardenTextField and BitwardenPasswordField (#202) --- .../createaccount/CreateAccountScreen.kt | 17 +--- .../feature/environment/EnvironmentScreen.kt | 25 +---- .../components/BitwardenPasswordField.kt | 95 +++++++++++++------ .../platform/components/BitwardenTextField.kt | 51 +++++++--- 4 files changed, 108 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt index de4e2d1d8..9c66ef05e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/createaccount/CreateAccountScreen.kt @@ -212,6 +212,7 @@ fun CreateAccountScreen( showPassword = showPassword, showPasswordChange = { showPassword = it }, value = state.passwordInput, + hint = state.passwordLengthLabel(), onValueChange = remember(viewModel) { { viewModel.trySendAction(PasswordInputChange(it)) } }, @@ -219,13 +220,6 @@ fun CreateAccountScreen( .fillMaxWidth() .padding(horizontal = 16.dp), ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = state.passwordLengthLabel(), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(horizontal = 32.dp), - ) Spacer(modifier = Modifier.height(8.dp)) PasswordStrengthIndicator( modifier = Modifier.padding(horizontal = 16.dp), @@ -251,18 +245,11 @@ fun CreateAccountScreen( onValueChange = remember(viewModel) { { viewModel.trySendAction(PasswordHintChange(it)) } }, + hint = stringResource(id = R.string.master_password_hint_description), modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = stringResource(id = R.string.master_password_hint_description), - color = MaterialTheme.colorScheme.onSurfaceVariant, - style = MaterialTheme.typography.bodySmall, - modifier = Modifier - .padding(horizontal = 32.dp), - ) Spacer(modifier = Modifier.height(24.dp)) BitwardenSwitch( label = stringResource(id = R.string.check_known_data_breaches_for_this_password), diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt index e9d407fae..46952b4b9 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/auth/feature/environment/EnvironmentScreen.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable @@ -101,6 +100,7 @@ fun EnvironmentScreen( label = stringResource(id = R.string.server_url), value = state.serverUrl, placeholder = "ex. https://bitwarden.company.com", + hint = stringResource(id = R.string.self_hosted_environment_footer), onValueChange = remember(viewModel) { { viewModel.trySendAction(EnvironmentAction.ServerUrlChange(it)) } }, @@ -110,17 +110,6 @@ fun EnvironmentScreen( .padding(horizontal = 16.dp), ) - Spacer(modifier = Modifier.height(4.dp)) - - Text( - text = stringResource(id = R.string.self_hosted_environment_footer), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp), - ) - Spacer(modifier = Modifier.height(24.dp)) BitwardenListHeaderText( @@ -180,22 +169,12 @@ fun EnvironmentScreen( onValueChange = remember(viewModel) { { viewModel.trySendAction(EnvironmentAction.IconsServerUrlChange(it)) } }, + hint = stringResource(id = R.string.custom_environment_footer), keyboardType = KeyboardType.Uri, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), ) - - Spacer(modifier = Modifier.height(4.dp)) - - Text( - text = stringResource(id = R.string.custom_environment_footer), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp), - ) } } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt index 0d171f773..d3cf75f50 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenPasswordField.kt @@ -1,5 +1,10 @@ package com.x8bit.bitwarden.ui.platform.components +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -18,6 +23,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.x8bit.bitwarden.R /** @@ -31,6 +37,7 @@ import com.x8bit.bitwarden.R * @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. + * @param hint optional hint text that will appear below the text input. */ @Composable fun BitwardenPasswordField( @@ -40,40 +47,59 @@ fun BitwardenPasswordField( showPasswordChange: (Boolean) -> Unit, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, + hint: String? = null, ) { - OutlinedTextField( + Column( 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, - ) + ) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + 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, + ) + } } - } - }, - ) + }, + ) + + hint?.let { + Spacer( + modifier = Modifier.height(4.dp), + ) + Text( + text = hint, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + } + } } /** @@ -84,6 +110,7 @@ fun BitwardenPasswordField( * @param value Current next on the text field. * @param onValueChange Callback that is triggered when the password changes. * @param modifier Modifier for the composable. + * @param hint optional hint text that will appear below the text input. * @param initialShowPassword The initial state of the show/hide password control. A value of * `false` (the default) indicates that that password should begin in the hidden state. */ @@ -93,6 +120,7 @@ fun BitwardenPasswordField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, + hint: String? = null, initialShowPassword: Boolean = false, ) { var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) } @@ -103,6 +131,7 @@ fun BitwardenPasswordField( showPassword = showPassword, showPasswordChange = { showPassword = !showPassword }, onValueChange = onValueChange, + hint = hint, ) } @@ -114,6 +143,7 @@ private fun BitwardenPasswordField_preview_withInput_hidePassword() { value = "Password", onValueChange = {}, initialShowPassword = false, + hint = "Hint", ) } @@ -125,6 +155,7 @@ private fun BitwardenPasswordField_preview_withInput_showPassword() { value = "Password", onValueChange = {}, initialShowPassword = true, + hint = "Hint", ) } @@ -136,6 +167,7 @@ private fun BitwardenPasswordField_preview_withoutInput_hidePassword() { value = "", onValueChange = {}, initialShowPassword = false, + hint = "Hint", ) } @@ -147,5 +179,6 @@ private fun BitwardenPasswordField_preview_withoutInput_showPassword() { value = "", onValueChange = {}, initialShowPassword = true, + hint = "Hint", ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenTextField.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenTextField.kt index d8bf900e8..cb82b7527 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenTextField.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/components/BitwardenTextField.kt @@ -1,12 +1,19 @@ package com.x8bit.bitwarden.ui.platform.components +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp /** * Component that allows the user to input text. This composable will manage the state of @@ -17,6 +24,7 @@ import androidx.compose.ui.tooling.preview.Preview * @param onValueChange callback that is triggered when the input of the text field changes. * @param placeholder the optional placeholder to be displayed when the text field is in focus and * the [value] is empty. + * @param hint optional hint text that will appear below the text input. * @param readOnly `true` if the input should be read-only and not accept user interactions. * @param keyboardType the preferred type of keyboard input. */ @@ -27,21 +35,40 @@ fun BitwardenTextField( onValueChange: (String) -> Unit, modifier: Modifier = Modifier, placeholder: String? = null, + hint: String? = null, readOnly: Boolean = false, keyboardType: KeyboardType = KeyboardType.Text, ) { - OutlinedTextField( + Column( modifier = modifier, - label = { Text(text = label) }, - value = value, - placeholder = placeholder?.let { - { Text(text = it) } - }, - onValueChange = onValueChange, - singleLine = true, - readOnly = readOnly, - keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType), - ) + ) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + label = { Text(text = label) }, + value = value, + placeholder = placeholder?.let { + { Text(text = it) } + }, + onValueChange = onValueChange, + singleLine = true, + readOnly = readOnly, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType), + ) + + hint?.let { + Spacer( + modifier = Modifier.height(4.dp), + ) + Text( + text = hint, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + } + } } @Preview @@ -51,6 +78,7 @@ private fun BitwardenTextField_preview_withInput() { label = "Label", value = "Input", onValueChange = {}, + hint = "Hint", ) } @@ -61,5 +89,6 @@ private fun BitwardenTextField_preview_withoutInput() { label = "Label", value = "", onValueChange = {}, + hint = "Hint", ) }