Add optional "hint" to BitwardenTextField and BitwardenPasswordField (#202)

This commit is contained in:
Brian Yencho 2023-11-03 09:35:15 -05:00 committed by Álison Fernandes
parent 49d71627c7
commit d10e678bb3
4 changed files with 108 additions and 80 deletions

View file

@ -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),

View file

@ -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),
)
}
}
}

View file

@ -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",
)
}

View file

@ -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",
)
}