From 4f53e3ef995ca93f3bb5ebffd88e2bd0a81146e7 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 9 Mar 2026 22:12:51 +0300 Subject: [PATCH] android: polish fullscreen chats search interactions --- android/CHANGELOG.md | 7 ++++ .../messenger/ui/chats/ChatListScreen.kt | 39 ++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 810fd0d..8cdeb38 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -592,3 +592,10 @@ ### Step 92 - Search filter leak fix on exit - Fixed chats search state leak: leaving fullscreen search now resets local/global query. - Main chats list no longer stays filtered by previous search input after returning from search mode. + +### Step 93 - Fullscreen search UX polish +- Added system back-handler for search mode with safe query reset. +- Improved fullscreen search result sections: + - `Показать больше / Свернуть` toggle for global users, + - `Показать больше / Свернуть` toggle for message results. +- Added explicit empty-state text when local/global/message search sections all have no results. diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt index 24dc604..44be038 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt @@ -1,6 +1,7 @@ package ru.daemonlord.messenger.ui.chats import android.widget.Toast +import androidx.activity.compose.BackHandler import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.background @@ -45,8 +46,8 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -176,6 +177,12 @@ fun ChatListScreen( var manageRoleText by remember { mutableStateOf("member") } val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840 val listState = rememberLazyListState() + BackHandler(enabled = isSearchMode) { + isSearchMode = false + localSearchQuery = "" + onSearchChanged("") + onGlobalSearchChanged("") + } LaunchedEffect(Unit) { onMainBarVisibilityChanged(true) @@ -712,6 +719,12 @@ private fun ChatSearchFullscreen( onOpenChat: (Long) -> Unit, ) { val trimmedQuery = searchQuery.trim() + var showMoreGlobalUsers by remember { mutableStateOf(false) } + var showMoreMessages by remember { mutableStateOf(false) } + LaunchedEffect(trimmedQuery) { + showMoreGlobalUsers = false + showMoreMessages = false + } val sectionChats = remember(state.chats, searchSection) { when (searchSection) { SearchSection.Chats -> state.chats @@ -864,11 +877,13 @@ private fun ChatSearchFullscreen( item(key = "global_header") { SectionHeader( title = "Глобальный поиск", - action = "Показать больше", + action = if (showMoreGlobalUsers) "Свернуть" else "Показать больше", + onActionClick = { showMoreGlobalUsers = !showMoreGlobalUsers }, ) } if (state.globalUsers.isNotEmpty()) { - items(state.globalUsers.take(8), key = { "user_${it.id}" }) { user -> + val users = if (showMoreGlobalUsers) state.globalUsers else state.globalUsers.take(5) + items(users, key = { "user_${it.id}" }) { user -> SearchUserRow( title = user.name, subtitle = buildString { @@ -890,10 +905,12 @@ private fun ChatSearchFullscreen( item(key = "messages_header") { SectionHeader( title = "Сообщения", - action = "Из всех чатов", + action = if (showMoreMessages) "Свернуть" else "Показать больше", + onActionClick = { showMoreMessages = !showMoreMessages }, ) } - items(state.globalMessages.take(12), key = { "msg_${it.id}" }) { message -> + val messages = if (showMoreMessages) state.globalMessages else state.globalMessages.take(8) + items(messages, key = { "msg_${it.id}" }) { message -> SearchMessageRow( state = state, messageText = message.text?.take(70).orEmpty().ifBlank { "[${message.type}]" }, @@ -905,6 +922,16 @@ private fun ChatSearchFullscreen( chatId = message.chatId, ) } + if (localQueryResults.isEmpty() && state.globalUsers.isEmpty() && state.globalMessages.isEmpty()) { + item(key = "all_empty") { + Text( + text = "Ничего не найдено", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 12.dp), + ) + } + } } } } @@ -914,6 +941,7 @@ private fun ChatSearchFullscreen( private fun SectionHeader( title: String, action: String, + onActionClick: (() -> Unit)? = null, ) { Row( modifier = Modifier @@ -931,6 +959,7 @@ private fun SectionHeader( text = action, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = if (onActionClick != null) Modifier.clickable(onClick = onActionClick) else Modifier, ) } }