android: refine multi-select ui to telegram-like layout
This commit is contained in:
@@ -1015,3 +1015,11 @@
|
|||||||
- Message actions are now driven by Telegram-like context UI:
|
- Message actions are now driven by Telegram-like context UI:
|
||||||
- tap -> context sheet actions,
|
- tap -> context sheet actions,
|
||||||
- long-press -> selection mode flow.
|
- 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`.
|
||||||
|
|||||||
@@ -419,9 +419,6 @@ fun ChatScreen(
|
|||||||
) {
|
) {
|
||||||
Icon(imageVector = Icons.Filled.DeleteOutline, contentDescription = "Delete selected")
|
Icon(imageVector = Icons.Filled.DeleteOutline, contentDescription = "Delete selected")
|
||||||
}
|
}
|
||||||
IconButton(onClick = onLoadMore, enabled = !state.isLoadingMore) {
|
|
||||||
Icon(imageVector = Icons.Filled.MoreVert, contentDescription = "Selection menu")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Row(
|
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(
|
ChannelReadOnlyBar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.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? {
|
private fun parseMessageLocalDate(createdAt: String): LocalDate? {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
Instant.parse(createdAt).atZone(ZoneId.systemDefault()).toLocalDate()
|
Instant.parse(createdAt).atZone(ZoneId.systemDefault()).toLocalDate()
|
||||||
|
|||||||
Reference in New Issue
Block a user