mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
Add optional "hint" to BitwardenTextField and BitwardenPasswordField (#202)
This commit is contained in:
parent
49d71627c7
commit
d10e678bb3
4 changed files with 108 additions and 80 deletions
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue