android: refine multi-select ui to telegram-like layout
Some checks failed
Android CI / android (push) Failing after 5m11s
Android Release / release (push) Has started running
CI / test (push) Has been cancelled

This commit is contained in:
Codex
2026-03-10 20:21:10 +03:00
parent fbe4db02ca
commit 63c0cd098e
2 changed files with 60 additions and 4 deletions

View File

@@ -1015,3 +1015,11 @@
- Message actions are now driven by Telegram-like context UI:
- tap -> context sheet actions,
- long-press -> selection mode flow.
### Step 138 - Multi-select UX closer to Telegram
- Refined selection top bar:
- removed extra overflow/load action from selection mode,
- kept focused actions only: close, selected count, forward, delete.
- In `MULTI` selection mode, composer is now replaced with a compact bottom action row:
- `Reply` (enabled for single selected message),
- `Forward`.

View File

@@ -419,9 +419,6 @@ fun ChatScreen(
) {
Icon(imageVector = Icons.Filled.DeleteOutline, contentDescription = "Delete selected")
}
IconButton(onClick = onLoadMore, enabled = !state.isLoadingMore) {
Icon(imageVector = Icons.Filled.MoreVert, contentDescription = "Selection menu")
}
}
} else {
Row(
@@ -1045,7 +1042,14 @@ fun ChatScreen(
}
}
if (isChannelChat && !state.canSendMessages) {
if (state.actionState.mode == MessageSelectionMode.MULTI && state.actionState.hasSelection) {
MultiSelectActionBar(
selectedCount = state.actionState.selectedCount,
canReply = state.actionState.selectedCount == 1 && state.selectedMessage != null,
onReply = { state.selectedMessage?.let(onReplySelected) },
onForward = onForwardSelected,
)
} else if (isChannelChat && !state.canSendMessages) {
ChannelReadOnlyBar(
modifier = Modifier
.fillMaxWidth()
@@ -2161,6 +2165,50 @@ private fun ChannelReadOnlyBar(
}
}
@Composable
private fun MultiSelectActionBar(
selectedCount: Int,
canReply: Boolean,
onReply: () -> Unit,
onForward: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.navigationBarsPadding()
.padding(horizontal = 10.dp, vertical = 6.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Surface(
shape = RoundedCornerShape(999.dp),
color = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f),
modifier = Modifier.weight(1f),
) {
TextButton(
onClick = onReply,
enabled = canReply,
modifier = Modifier.fillMaxWidth(),
) {
Text("Reply")
}
}
Surface(
shape = RoundedCornerShape(999.dp),
color = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f),
modifier = Modifier.weight(1f),
) {
TextButton(
onClick = onForward,
enabled = selectedCount > 0,
modifier = Modifier.fillMaxWidth(),
) {
Text("Forward")
}
}
}
}
private fun parseMessageLocalDate(createdAt: String): LocalDate? {
return runCatching {
Instant.parse(createdAt).atZone(ZoneId.systemDefault()).toLocalDate()