android: fix inline search close and polish message action sheet
This commit is contained in:
@@ -884,3 +884,10 @@
|
|||||||
- `Files / Links / Voice` use denser card rows with icon+meta layout.
|
- `Files / Links / Voice` use denser card rows with icon+meta layout.
|
||||||
- `Voice` rows now show a dedicated play affordance.
|
- `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.
|
- 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.
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ import androidx.compose.material.icons.filled.Info
|
|||||||
import androidx.compose.material.icons.filled.Image
|
import androidx.compose.material.icons.filled.Image
|
||||||
import androidx.compose.material.icons.filled.Link
|
import androidx.compose.material.icons.filled.Link
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
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 androidx.compose.material.icons.automirrored.filled.InsertDriveFile
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
@@ -302,6 +304,12 @@ fun ChatScreen(
|
|||||||
listState.animateScrollToItem(index = index)
|
listState.animateScrollToItem(index = index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LaunchedEffect(state.actionState.mode) {
|
||||||
|
if (state.actionState.mode == MessageSelectionMode.MULTI && showInlineSearch) {
|
||||||
|
showInlineSearch = false
|
||||||
|
onInlineSearchChanged("")
|
||||||
|
}
|
||||||
|
}
|
||||||
LaunchedEffect(listState, state.messages) {
|
LaunchedEffect(listState, state.messages) {
|
||||||
snapshotFlow {
|
snapshotFlow {
|
||||||
listState.layoutInfo.visibleItemsInfo
|
listState.layoutInfo.visibleItemsInfo
|
||||||
@@ -493,6 +501,12 @@ fun ChatScreen(
|
|||||||
onClick = { onJumpInlineSearch(true) },
|
onClick = { onJumpInlineSearch(true) },
|
||||||
enabled = state.inlineSearchMatches.isNotEmpty(),
|
enabled = state.inlineSearchMatches.isNotEmpty(),
|
||||||
) { Icon(imageVector = Icons.Filled.ArrowDownward, contentDescription = "Next match") }
|
) { 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()) {
|
if (showInlineSearch && state.inlineSearchMatches.isNotEmpty()) {
|
||||||
@@ -611,38 +625,109 @@ fun ChatScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button(
|
Surface(
|
||||||
onClick = {
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
.clickable {
|
||||||
onReplySelected(selected)
|
onReplySelected(selected)
|
||||||
actionMenuMessage = null
|
actionMenuMessage = null
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f),
|
||||||
) { Text("Reply") }
|
) {
|
||||||
Button(
|
Row(
|
||||||
onClick = {
|
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)
|
onEditSelected(selected)
|
||||||
actionMenuMessage = null
|
actionMenuMessage = null
|
||||||
},
|
},
|
||||||
enabled = state.selectedCanEdit,
|
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f),
|
||||||
modifier = Modifier.fillMaxWidth(),
|
) {
|
||||||
) { Text("Edit") }
|
Row(
|
||||||
Button(
|
modifier = Modifier
|
||||||
onClick = {
|
.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)
|
onSelectMessage(selected)
|
||||||
onForwardSelected()
|
onForwardSelected()
|
||||||
actionMenuMessage = null
|
actionMenuMessage = null
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f),
|
||||||
) { Text("Forward") }
|
) {
|
||||||
Button(
|
Row(
|
||||||
onClick = {
|
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)
|
onSelectMessage(selected)
|
||||||
pendingDeleteForAll = false
|
pendingDeleteForAll = false
|
||||||
showDeleteDialog = true
|
showDeleteDialog = true
|
||||||
actionMenuMessage = null
|
actionMenuMessage = null
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
color = MaterialTheme.colorScheme.errorContainer.copy(alpha = 0.45f),
|
||||||
) { Text("Delete") }
|
) {
|
||||||
|
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(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
actionMenuMessage = null
|
actionMenuMessage = null
|
||||||
|
|||||||
Reference in New Issue
Block a user