From cbeb58f00e831e44bde3d99d1f0eec54fa34148d Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Tue, 21 Oct 2025 11:25:46 +0200 Subject: [PATCH] Keep the cursor position in room list search when going back (#5570) Also, make sure disposing a `MessagesView` doesn't accidentally hide the keyboard once the transition animation is done --- .../home/impl/search/RoomListSearchView.kt | 20 ++++++++++++------- .../features/messages/impl/MessagesView.kt | 3 --- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt index 2302b3325f..05ee11997d 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/search/RoomListSearchView.kt @@ -24,6 +24,7 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -33,6 +34,8 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.compound.tokens.generated.CompoundIcons @@ -41,7 +44,6 @@ import io.element.android.features.home.impl.contentType import io.element.android.features.home.impl.model.RoomListRoomSummary import io.element.android.features.home.impl.roomlist.RoomListEvents import io.element.android.libraries.designsystem.components.button.BackButton -import io.element.android.libraries.designsystem.components.form.textFieldState import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.FilledTextField @@ -111,18 +113,18 @@ private fun RoomListSearchContent( }, navigationIcon = { BackButton(onClick = ::onBackButtonClick) }, title = { - var filter by textFieldState(state.query) + var value by remember { mutableStateOf(TextFieldValue(state.query)) } val focusRequester = remember { FocusRequester() } FilledTextField( modifier = Modifier .fillMaxWidth() .focusRequester(focusRequester), - value = filter, + value = value, singleLine = true, onValueChange = { - filter = it - state.eventSink(RoomListSearchEvents.QueryChanged(it)) + value = it + state.eventSink(RoomListSearchEvents.QueryChanged(it.text)) }, colors = TextFieldDefaults.colors( focusedContainerColor = Color.Transparent, @@ -134,7 +136,7 @@ private fun RoomListSearchContent( errorIndicatorColor = Color.Transparent, ), trailingIcon = { - if (filter.isNotEmpty()) { + if (value.text.isNotEmpty()) { IconButton(onClick = { state.eventSink(RoomListSearchEvents.ClearQuery) }) { @@ -148,7 +150,11 @@ private fun RoomListSearchContent( ) LaunchedEffect(Unit) { - focusRequester.requestFocus() + value = value.copy(selection = TextRange(value.text.length)) + if (!focusRequester.restoreFocusedChild()) { + focusRequester.requestFocus() + } + focusRequester.saveFocusedChild() } }, windowInsets = TopAppBarDefaults.windowInsets.copy(top = 0) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt index 07fc178721..6e9e5cf55d 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt @@ -84,7 +84,6 @@ import io.element.android.libraries.designsystem.text.toAnnotatedString import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed import io.element.android.libraries.designsystem.utils.KeepScreenOn import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost @@ -124,8 +123,6 @@ fun MessagesView( KeepScreenOn(state.voiceMessageComposerState.keepScreenOn) - HideKeyboardWhenDisposed() - val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) // This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose