android: polish fullscreen chats search interactions
This commit is contained in:
@@ -592,3 +592,10 @@
|
|||||||
### Step 92 - Search filter leak fix on exit
|
### Step 92 - Search filter leak fix on exit
|
||||||
- Fixed chats search state leak: leaving fullscreen search now resets local/global query.
|
- 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.
|
- 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.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ru.daemonlord.messenger.ui.chats
|
package ru.daemonlord.messenger.ui.chats
|
||||||
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -45,8 +46,8 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.snapshotFlow
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -176,6 +177,12 @@ fun ChatListScreen(
|
|||||||
var manageRoleText by remember { mutableStateOf("member") }
|
var manageRoleText by remember { mutableStateOf("member") }
|
||||||
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
val isTabletLayout = LocalConfiguration.current.screenWidthDp >= 840
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
BackHandler(enabled = isSearchMode) {
|
||||||
|
isSearchMode = false
|
||||||
|
localSearchQuery = ""
|
||||||
|
onSearchChanged("")
|
||||||
|
onGlobalSearchChanged("")
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
onMainBarVisibilityChanged(true)
|
onMainBarVisibilityChanged(true)
|
||||||
@@ -712,6 +719,12 @@ private fun ChatSearchFullscreen(
|
|||||||
onOpenChat: (Long) -> Unit,
|
onOpenChat: (Long) -> Unit,
|
||||||
) {
|
) {
|
||||||
val trimmedQuery = searchQuery.trim()
|
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) {
|
val sectionChats = remember(state.chats, searchSection) {
|
||||||
when (searchSection) {
|
when (searchSection) {
|
||||||
SearchSection.Chats -> state.chats
|
SearchSection.Chats -> state.chats
|
||||||
@@ -864,11 +877,13 @@ private fun ChatSearchFullscreen(
|
|||||||
item(key = "global_header") {
|
item(key = "global_header") {
|
||||||
SectionHeader(
|
SectionHeader(
|
||||||
title = "Глобальный поиск",
|
title = "Глобальный поиск",
|
||||||
action = "Показать больше",
|
action = if (showMoreGlobalUsers) "Свернуть" else "Показать больше",
|
||||||
|
onActionClick = { showMoreGlobalUsers = !showMoreGlobalUsers },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (state.globalUsers.isNotEmpty()) {
|
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(
|
SearchUserRow(
|
||||||
title = user.name,
|
title = user.name,
|
||||||
subtitle = buildString {
|
subtitle = buildString {
|
||||||
@@ -890,10 +905,12 @@ private fun ChatSearchFullscreen(
|
|||||||
item(key = "messages_header") {
|
item(key = "messages_header") {
|
||||||
SectionHeader(
|
SectionHeader(
|
||||||
title = "Сообщения",
|
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(
|
SearchMessageRow(
|
||||||
state = state,
|
state = state,
|
||||||
messageText = message.text?.take(70).orEmpty().ifBlank { "[${message.type}]" },
|
messageText = message.text?.take(70).orEmpty().ifBlank { "[${message.type}]" },
|
||||||
@@ -905,6 +922,16 @@ private fun ChatSearchFullscreen(
|
|||||||
chatId = message.chatId,
|
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(
|
private fun SectionHeader(
|
||||||
title: String,
|
title: String,
|
||||||
action: String,
|
action: String,
|
||||||
|
onActionClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -931,6 +959,7 @@ private fun SectionHeader(
|
|||||||
text = action,
|
text = action,
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = if (onActionClick != null) Modifier.clickable(onClick = onActionClick) else Modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user