mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 20:07:59 -06:00
PM-16058 - Add default environments via autocomplete dropdown (#4473)
This commit is contained in:
parent
ae20e55b1a
commit
e37cefeb1d
@ -26,6 +26,7 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||
@ -35,6 +36,7 @@ import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
|
||||
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Displays the about self-hosted/custom environment screen.
|
||||
@ -115,6 +117,15 @@ fun EnvironmentScreen(
|
||||
onValueChange = remember(viewModel) {
|
||||
{ viewModel.trySendAction(EnvironmentAction.ServerUrlChange(it)) }
|
||||
},
|
||||
autoCompleteOptions = if (BuildConfig.BUILD_TYPE != "release") {
|
||||
persistentListOf(
|
||||
"https://vault.qa.bitwarden.pw",
|
||||
"https://qa-team.sh.bitwarden.pw",
|
||||
"https://vault.usdev.bitwarden.pw",
|
||||
)
|
||||
} else {
|
||||
persistentListOf()
|
||||
},
|
||||
keyboardType = KeyboardType.Uri,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components.field
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
@ -16,6 +20,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalTextToolbar
|
||||
@ -26,14 +31,19 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.PopupProperties
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toPx
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.withLineBreaksAtWidth
|
||||
import com.x8bit.bitwarden.ui.platform.components.appbar.color.bitwardenMenuItemColors
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.color.bitwardenTextFieldColors
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.toolbar.BitwardenCutCopyTextToolbar
|
||||
import com.x8bit.bitwarden.ui.platform.components.field.toolbar.BitwardenEmptyTextToolbar
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconResource
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.TextToolbarType
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* Component that allows the user to input text. This composable will manage the state of
|
||||
@ -79,6 +89,7 @@ fun BitwardenTextField(
|
||||
autoFocus: Boolean = false,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
textToolbarType: TextToolbarType = TextToolbarType.DEFAULT,
|
||||
autoCompleteOptions: ImmutableList<String> = persistentListOf<String>(),
|
||||
) {
|
||||
var widthPx by remember { mutableIntStateOf(0) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
@ -112,54 +123,80 @@ fun BitwardenTextField(
|
||||
}
|
||||
var lastTextValue by remember(value) { mutableStateOf(value = value) }
|
||||
CompositionLocalProvider(value = LocalTextToolbar provides textToolbar) {
|
||||
OutlinedTextField(
|
||||
colors = bitwardenTextFieldColors(),
|
||||
modifier = modifier
|
||||
.onGloballyPositioned { widthPx = it.size.width }
|
||||
.focusRequester(focusRequester),
|
||||
enabled = enabled,
|
||||
label = { Text(text = label) },
|
||||
value = textFieldValue,
|
||||
leadingIcon = leadingIconResource?.let { iconResource ->
|
||||
{
|
||||
Icon(
|
||||
painter = iconResource.iconPainter,
|
||||
contentDescription = iconResource.contentDescription,
|
||||
var hasFocused by remember { mutableStateOf(value = false) }
|
||||
Box(modifier = modifier) {
|
||||
OutlinedTextField(
|
||||
colors = bitwardenTextFieldColors(),
|
||||
modifier = Modifier
|
||||
.onGloballyPositioned { widthPx = it.size.width }
|
||||
.onFocusEvent { focusState -> hasFocused = focusState.hasFocus }
|
||||
.focusRequester(focusRequester)
|
||||
.fillMaxWidth(),
|
||||
enabled = enabled,
|
||||
label = { Text(text = label) },
|
||||
value = textFieldValue,
|
||||
leadingIcon = leadingIconResource?.let { iconResource ->
|
||||
{
|
||||
Icon(
|
||||
painter = iconResource.iconPainter,
|
||||
contentDescription = iconResource.contentDescription,
|
||||
)
|
||||
}
|
||||
},
|
||||
trailingIcon = trailingIconContent,
|
||||
placeholder = placeholder?.let {
|
||||
{
|
||||
Text(
|
||||
text = it,
|
||||
style = textStyle,
|
||||
)
|
||||
}
|
||||
},
|
||||
supportingText = hint?.let {
|
||||
{
|
||||
Text(
|
||||
text = hint,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
},
|
||||
onValueChange = {
|
||||
hasFocused = true
|
||||
textFieldValueState = it
|
||||
val stringChangedSinceLastInvocation = lastTextValue != it.text
|
||||
lastTextValue = it.text
|
||||
if (stringChangedSinceLastInvocation) {
|
||||
onValueChange(it.text)
|
||||
}
|
||||
},
|
||||
singleLine = singleLine,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType),
|
||||
isError = isError,
|
||||
visualTransformation = visualTransformation,
|
||||
)
|
||||
val filteredAutoCompleteList = autoCompleteOptions
|
||||
.filter { option ->
|
||||
option.startsWith(textFieldValue.text) && option != textFieldValue.text
|
||||
}
|
||||
.toImmutableList()
|
||||
DropdownMenu(
|
||||
expanded = filteredAutoCompleteList.isNotEmpty() && hasFocused,
|
||||
shape = BitwardenTheme.shapes.menu,
|
||||
containerColor = BitwardenTheme.colorScheme.background.primary,
|
||||
properties = PopupProperties(),
|
||||
onDismissRequest = { hasFocused = false },
|
||||
) {
|
||||
filteredAutoCompleteList.forEach {
|
||||
DropdownMenuItem(
|
||||
colors = bitwardenMenuItemColors(),
|
||||
text = { Text(text = it, style = textStyle) },
|
||||
onClick = { onValueChange(it) },
|
||||
)
|
||||
}
|
||||
},
|
||||
trailingIcon = trailingIconContent,
|
||||
placeholder = placeholder?.let {
|
||||
{
|
||||
Text(
|
||||
text = it,
|
||||
style = textStyle,
|
||||
)
|
||||
}
|
||||
},
|
||||
supportingText = hint?.let {
|
||||
{
|
||||
Text(
|
||||
text = hint,
|
||||
style = BitwardenTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
},
|
||||
onValueChange = {
|
||||
textFieldValueState = it
|
||||
val stringChangedSinceLastInvocation = lastTextValue != it.text
|
||||
lastTextValue = it.text
|
||||
if (stringChangedSinceLastInvocation) {
|
||||
onValueChange(it.text)
|
||||
}
|
||||
},
|
||||
singleLine = singleLine,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = keyboardType),
|
||||
isError = isError,
|
||||
visualTransformation = visualTransformation,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (autoFocus) {
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user