mirror of
https://github.com/bitwarden/android.git
synced 2024-11-25 10:56:03 +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,
|
showPassword = showPassword,
|
||||||
showPasswordChange = { showPassword = it },
|
showPasswordChange = { showPassword = it },
|
||||||
value = state.passwordInput,
|
value = state.passwordInput,
|
||||||
|
hint = state.passwordLengthLabel(),
|
||||||
onValueChange = remember(viewModel) {
|
onValueChange = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(PasswordInputChange(it)) }
|
{ viewModel.trySendAction(PasswordInputChange(it)) }
|
||||||
},
|
},
|
||||||
|
@ -219,13 +220,6 @@ fun CreateAccountScreen(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.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))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
PasswordStrengthIndicator(
|
PasswordStrengthIndicator(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
@ -251,18 +245,11 @@ fun CreateAccountScreen(
|
||||||
onValueChange = remember(viewModel) {
|
onValueChange = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(PasswordHintChange(it)) }
|
{ viewModel.trySendAction(PasswordHintChange(it)) }
|
||||||
},
|
},
|
||||||
|
hint = stringResource(id = R.string.master_password_hint_description),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.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))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = stringResource(id = R.string.check_known_data_breaches_for_this_password),
|
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.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
@ -101,6 +100,7 @@ fun EnvironmentScreen(
|
||||||
label = stringResource(id = R.string.server_url),
|
label = stringResource(id = R.string.server_url),
|
||||||
value = state.serverUrl,
|
value = state.serverUrl,
|
||||||
placeholder = "ex. https://bitwarden.company.com",
|
placeholder = "ex. https://bitwarden.company.com",
|
||||||
|
hint = stringResource(id = R.string.self_hosted_environment_footer),
|
||||||
onValueChange = remember(viewModel) {
|
onValueChange = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(EnvironmentAction.ServerUrlChange(it)) }
|
{ viewModel.trySendAction(EnvironmentAction.ServerUrlChange(it)) }
|
||||||
},
|
},
|
||||||
|
@ -110,17 +110,6 @@ fun EnvironmentScreen(
|
||||||
.padding(horizontal = 16.dp),
|
.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))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
BitwardenListHeaderText(
|
BitwardenListHeaderText(
|
||||||
|
@ -180,22 +169,12 @@ fun EnvironmentScreen(
|
||||||
onValueChange = remember(viewModel) {
|
onValueChange = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(EnvironmentAction.IconsServerUrlChange(it)) }
|
{ viewModel.trySendAction(EnvironmentAction.IconsServerUrlChange(it)) }
|
||||||
},
|
},
|
||||||
|
hint = stringResource(id = R.string.custom_environment_footer),
|
||||||
keyboardType = KeyboardType.Uri,
|
keyboardType = KeyboardType.Uri,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.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
|
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.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
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.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.x8bit.bitwarden.R
|
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 showPasswordChange Lambda that is called when user request show/hide be toggled.
|
||||||
* @param onValueChange Callback that is triggered when the password changes.
|
* @param onValueChange Callback that is triggered when the password changes.
|
||||||
* @param modifier Modifier for the composable.
|
* @param modifier Modifier for the composable.
|
||||||
|
* @param hint optional hint text that will appear below the text input.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun BitwardenPasswordField(
|
fun BitwardenPasswordField(
|
||||||
|
@ -40,40 +47,59 @@ fun BitwardenPasswordField(
|
||||||
showPasswordChange: (Boolean) -> Unit,
|
showPasswordChange: (Boolean) -> Unit,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
hint: String? = null,
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
Column(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
textStyle = MaterialTheme.typography.bodyLarge,
|
) {
|
||||||
label = { Text(text = label) },
|
OutlinedTextField(
|
||||||
value = value,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onValueChange = onValueChange,
|
textStyle = MaterialTheme.typography.bodyLarge,
|
||||||
visualTransformation = if (showPassword) {
|
label = { Text(text = label) },
|
||||||
VisualTransformation.None
|
value = value,
|
||||||
} else {
|
onValueChange = onValueChange,
|
||||||
PasswordVisualTransformation()
|
visualTransformation = if (showPassword) {
|
||||||
},
|
VisualTransformation.None
|
||||||
singleLine = true,
|
} else {
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
PasswordVisualTransformation()
|
||||||
trailingIcon = {
|
},
|
||||||
IconButton(
|
singleLine = true,
|
||||||
onClick = { showPasswordChange.invoke(!showPassword) },
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||||
) {
|
trailingIcon = {
|
||||||
if (showPassword) {
|
IconButton(
|
||||||
Icon(
|
onClick = { showPasswordChange.invoke(!showPassword) },
|
||||||
painter = painterResource(id = R.drawable.ic_visibility_off),
|
) {
|
||||||
contentDescription = stringResource(id = R.string.hide),
|
if (showPassword) {
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
Icon(
|
||||||
)
|
painter = painterResource(id = R.drawable.ic_visibility_off),
|
||||||
} else {
|
contentDescription = stringResource(id = R.string.hide),
|
||||||
Icon(
|
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
painter = painterResource(id = R.drawable.ic_visibility),
|
)
|
||||||
contentDescription = stringResource(id = R.string.show),
|
} else {
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
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 value Current next on the text field.
|
||||||
* @param onValueChange Callback that is triggered when the password changes.
|
* @param onValueChange Callback that is triggered when the password changes.
|
||||||
* @param modifier Modifier for the composable.
|
* @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
|
* @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.
|
* `false` (the default) indicates that that password should begin in the hidden state.
|
||||||
*/
|
*/
|
||||||
|
@ -93,6 +120,7 @@ fun BitwardenPasswordField(
|
||||||
value: String,
|
value: String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
hint: String? = null,
|
||||||
initialShowPassword: Boolean = false,
|
initialShowPassword: Boolean = false,
|
||||||
) {
|
) {
|
||||||
var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) }
|
var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) }
|
||||||
|
@ -103,6 +131,7 @@ fun BitwardenPasswordField(
|
||||||
showPassword = showPassword,
|
showPassword = showPassword,
|
||||||
showPasswordChange = { showPassword = !showPassword },
|
showPasswordChange = { showPassword = !showPassword },
|
||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
|
hint = hint,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +143,7 @@ private fun BitwardenPasswordField_preview_withInput_hidePassword() {
|
||||||
value = "Password",
|
value = "Password",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
initialShowPassword = false,
|
initialShowPassword = false,
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +155,7 @@ private fun BitwardenPasswordField_preview_withInput_showPassword() {
|
||||||
value = "Password",
|
value = "Password",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
initialShowPassword = true,
|
initialShowPassword = true,
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +167,7 @@ private fun BitwardenPasswordField_preview_withoutInput_hidePassword() {
|
||||||
value = "",
|
value = "",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
initialShowPassword = false,
|
initialShowPassword = false,
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,5 +179,6 @@ private fun BitwardenPasswordField_preview_withoutInput_showPassword() {
|
||||||
value = "",
|
value = "",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
initialShowPassword = true,
|
initialShowPassword = true,
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.components
|
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.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
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
|
* 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 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
|
* @param placeholder the optional placeholder to be displayed when the text field is in focus and
|
||||||
* the [value] is empty.
|
* 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 readOnly `true` if the input should be read-only and not accept user interactions.
|
||||||
* @param keyboardType the preferred type of keyboard input.
|
* @param keyboardType the preferred type of keyboard input.
|
||||||
*/
|
*/
|
||||||
|
@ -27,21 +35,40 @@ fun BitwardenTextField(
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
placeholder: String? = null,
|
placeholder: String? = null,
|
||||||
|
hint: String? = null,
|
||||||
readOnly: Boolean = false,
|
readOnly: Boolean = false,
|
||||||
keyboardType: KeyboardType = KeyboardType.Text,
|
keyboardType: KeyboardType = KeyboardType.Text,
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
Column(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
label = { Text(text = label) },
|
) {
|
||||||
value = value,
|
OutlinedTextField(
|
||||||
placeholder = placeholder?.let {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
{ Text(text = it) }
|
label = { Text(text = label) },
|
||||||
},
|
value = value,
|
||||||
onValueChange = onValueChange,
|
placeholder = placeholder?.let {
|
||||||
singleLine = true,
|
{ Text(text = it) }
|
||||||
readOnly = readOnly,
|
},
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType),
|
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
|
@Preview
|
||||||
|
@ -51,6 +78,7 @@ private fun BitwardenTextField_preview_withInput() {
|
||||||
label = "Label",
|
label = "Label",
|
||||||
value = "Input",
|
value = "Input",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,5 +89,6 @@ private fun BitwardenTextField_preview_withoutInput() {
|
||||||
label = "Label",
|
label = "Label",
|
||||||
value = "",
|
value = "",
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
|
hint = "Hint",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue