diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt index 6ee8f6e75694fc0d61575961b3ab4593d68b4c3c..c1b08e1b5ac1fa230ab54fa37dd7e7d493d147e3 100644 --- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt +++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/ui/SearchTextField.kt @@ -19,6 +19,7 @@ package org.briarproject.briar.desktop.ui import androidx.compose.animation.Crossfade +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -37,20 +38,35 @@ import androidx.compose.material.TextField import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Cancel +import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Search import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.pointer.PointerIconDefaults import androidx.compose.ui.input.pointer.pointerHoverIcon +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.unit.dp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.job +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.runInterruptible import org.briarproject.briar.desktop.theme.surfaceVariant import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n @@ -138,6 +154,13 @@ fun SearchInput( onBack: () -> Unit, ) { val focusRequester = remember { FocusRequester() } + val focusManager = LocalFocusManager.current + + fun endSearch() { + onValueChange("") + focusManager.clearFocus(true) + onBack() + } TextField( value = searchValue, onValueChange = onValueChange, @@ -150,19 +173,33 @@ fun SearchInput( colors = TextFieldDefaults.textFieldColors(backgroundColor = MaterialTheme.colors.surfaceVariant), leadingIcon = { IconButton( - { - focusRequester.freeFocus() - onValueChange("") - onBack() - }, + { endSearch() }, Modifier.padding(start = 20.dp, end = 16.dp).size(24.dp).pointerHoverIcon(PointerIconDefaults.Default) ) { Icon(Icons.Filled.ArrowBack, i18n("access.contacts.search")) } }, - modifier = Modifier.fillMaxSize().focusRequester(focusRequester) + trailingIcon = { + if (searchValue.isNotEmpty()) { + IconButton( + { + onValueChange("") + focusRequester.requestFocus() + }, + Modifier.size(24.dp).pointerHoverIcon(PointerIconDefaults.Default) + ) { + Icon(Icons.Filled.Close, "clear search text") + } + } + }, + modifier = Modifier.fillMaxSize().focusRequester(focusRequester).onKeyEvent { + if (it.key == Key.Escape) { endSearch() } + true + } ) LaunchedEffect(Unit) { - focusRequester.requestFocus() + this.coroutineContext.job.invokeOnCompletion { + focusRequester.requestFocus() + } } }