PM-16058 - Add default environments via autocomplete dropdown (#4473)

This commit is contained in:
David Perez 2024-12-13 17:04:02 -06:00 committed by GitHub
parent ae20e55b1a
commit e37cefeb1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 46 deletions

View File

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

View File

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