From 5a0bb9ff087b4c9d0ca8d0f2c725bbde0faf21e2 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 10 Mar 2026 01:38:46 +0300 Subject: [PATCH] android: fix inline search close and polish message action sheet --- android/CHANGELOG.md | 7 + .../messenger/ui/chat/ChatScreen.kt | 149 ++++++++++++++---- 2 files changed, 124 insertions(+), 32 deletions(-) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 41265d5..bc7be0a 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -884,3 +884,10 @@ - `Files / Links / Voice` use denser card rows with icon+meta layout. - `Voice` rows now show a dedicated play affordance. - Refined menu order in chat `3-dot` popup and kept actions consistent with current no-calls scope. + +### Step 124 - Inline search close fix + message menu visual pass +- Fixed inline chat search UX: + - added explicit close button in the search row, + - closing search now also clears active query/filter without re-entering chat. +- Added automatic inline-search collapse when entering multi-select mode. +- Reworked message tap action sheet to Telegram-like list actions with icons and clearer destructive `Delete` row styling. diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt index b0f9548..3f460f2 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chat/ChatScreen.kt @@ -110,6 +110,8 @@ import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.automirrored.filled.Reply import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import coil.compose.AsyncImage import kotlinx.coroutines.flow.collectLatest @@ -302,6 +304,12 @@ fun ChatScreen( listState.animateScrollToItem(index = index) } } + LaunchedEffect(state.actionState.mode) { + if (state.actionState.mode == MessageSelectionMode.MULTI && showInlineSearch) { + showInlineSearch = false + onInlineSearchChanged("") + } + } LaunchedEffect(listState, state.messages) { snapshotFlow { listState.layoutInfo.visibleItemsInfo @@ -493,6 +501,12 @@ fun ChatScreen( onClick = { onJumpInlineSearch(true) }, enabled = state.inlineSearchMatches.isNotEmpty(), ) { Icon(imageVector = Icons.Filled.ArrowDownward, contentDescription = "Next match") } + IconButton( + onClick = { + showInlineSearch = false + onInlineSearchChanged("") + }, + ) { Icon(imageVector = Icons.Filled.Close, contentDescription = "Close search") } } } if (showInlineSearch && state.inlineSearchMatches.isNotEmpty()) { @@ -611,38 +625,109 @@ fun ChatScreen( } } } - Button( - onClick = { - onReplySelected(selected) - actionMenuMessage = null - }, - modifier = Modifier.fillMaxWidth(), - ) { Text("Reply") } - Button( - onClick = { - onEditSelected(selected) - actionMenuMessage = null - }, - enabled = state.selectedCanEdit, - modifier = Modifier.fillMaxWidth(), - ) { Text("Edit") } - Button( - onClick = { - onSelectMessage(selected) - onForwardSelected() - actionMenuMessage = null - }, - modifier = Modifier.fillMaxWidth(), - ) { Text("Forward") } - Button( - onClick = { - onSelectMessage(selected) - pendingDeleteForAll = false - showDeleteDialog = true - actionMenuMessage = null - }, - modifier = Modifier.fillMaxWidth(), - ) { Text("Delete") } + Surface( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .clickable { + onReplySelected(selected) + actionMenuMessage = null + }, + color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Icon(imageVector = Icons.AutoMirrored.Filled.Reply, contentDescription = null) + Text("Reply", style = MaterialTheme.typography.bodyLarge) + } + } + Surface( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .clickable(enabled = state.selectedCanEdit) { + onEditSelected(selected) + actionMenuMessage = null + }, + color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Icon(imageVector = Icons.Filled.Edit, contentDescription = null) + Text( + "Edit", + style = MaterialTheme.typography.bodyLarge, + color = if (state.selectedCanEdit) { + MaterialTheme.colorScheme.onSurface + } else { + MaterialTheme.colorScheme.onSurfaceVariant + }, + ) + } + } + Surface( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .clickable { + onSelectMessage(selected) + onForwardSelected() + actionMenuMessage = null + }, + color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Icon(imageVector = Icons.AutoMirrored.Filled.Forward, contentDescription = null) + Text("Forward", style = MaterialTheme.typography.bodyLarge) + } + } + Surface( + modifier = Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) + .clickable { + onSelectMessage(selected) + pendingDeleteForAll = false + showDeleteDialog = true + actionMenuMessage = null + }, + color = MaterialTheme.colorScheme.errorContainer.copy(alpha = 0.45f), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp, vertical = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + Icon( + imageVector = Icons.Filled.DeleteOutline, + contentDescription = null, + tint = MaterialTheme.colorScheme.error, + ) + Text( + "Delete", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.error, + ) + } + } TextButton( onClick = { actionMenuMessage = null