Меню для сообщений
This commit is contained in:
@@ -261,43 +261,62 @@ fun ChatDetailScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
AppAvatar(
|
||||
url = state.chatAvatar,
|
||||
name = state.chatName ?: chatName,
|
||||
size = 36.dp,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
Column {
|
||||
Text(state.chatName ?: chatName, style = MaterialTheme.typography.titleMedium)
|
||||
if (state.isTyping) {
|
||||
Text(
|
||||
stringResource(R.string.typing),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
if (state.selectedMessageIds.isNotEmpty()) {
|
||||
TopAppBar(
|
||||
title = { Text("${state.selectedMessageIds.size}") },
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { viewModel.clearSelection() }) {
|
||||
Icon(Icons.Default.Close, contentDescription = "Cancel")
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = { /* TODO: Forward */ }) {
|
||||
Icon(Icons.Default.Forward, contentDescription = "Forward")
|
||||
}
|
||||
IconButton(onClick = { /* TODO: Delete */ }) {
|
||||
Icon(Icons.Default.Delete, contentDescription = "Delete")
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
AppAvatar(
|
||||
url = state.chatAvatar,
|
||||
name = state.chatName ?: chatName,
|
||||
size = 36.dp,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
Column {
|
||||
Text(state.chatName ?: chatName, style = MaterialTheme.typography.titleMedium)
|
||||
if (state.isTyping) {
|
||||
Text(
|
||||
stringResource(R.string.typing),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.Default.ArrowBack, contentDescription = stringResource(R.string.back))
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (state.canCall) {
|
||||
IconButton(onClick = { /* Вызов (WebRTC) */ }) {
|
||||
Icon(Icons.Default.Call, contentDescription = stringResource(R.string.call))
|
||||
}
|
||||
IconButton(onClick = { /* Видеозвонок (WebRTC) */ }) {
|
||||
Icon(Icons.Default.VideoCall, contentDescription = stringResource(R.string.video_call))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.Default.ArrowBack, contentDescription = stringResource(R.string.back))
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (state.canCall) {
|
||||
IconButton(onClick = { /* Вызов (WebRTC) */ }) {
|
||||
Icon(Icons.Default.Call, contentDescription = stringResource(R.string.call))
|
||||
}
|
||||
IconButton(onClick = { /* Видеозвонок (WebRTC) */ }) {
|
||||
Icon(Icons.Default.VideoCall, contentDescription = stringResource(R.string.video_call))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
@@ -345,7 +364,6 @@ fun ChatDetailScreen(
|
||||
onVoiceFinished = { speed -> playNextVoiceMessage(item.message.id, speed) },
|
||||
onReactionClick = { emoji -> viewModel.addReaction(item.message.id, emoji) },
|
||||
onReplyClick = { reply ->
|
||||
// TODO: Scroll to reply
|
||||
val index = listItems.indexOfFirst {
|
||||
it is MessageListItem.MessageItem && it.message.id == reply.id
|
||||
}
|
||||
@@ -353,6 +371,9 @@ fun ChatDetailScreen(
|
||||
scope.launch { listState.animateScrollToItem(index) }
|
||||
}
|
||||
},
|
||||
onSelect = { viewModel.toggleSelection(it) },
|
||||
isSelected = state.selectedMessageIds.contains(item.message.id),
|
||||
isSelectionMode = state.selectedMessageIds.isNotEmpty(),
|
||||
onMediaClick = { clickedMedia ->
|
||||
val isMedia = clickedMedia.type.startsWith("image") ||
|
||||
clickedMedia.type.startsWith("video") ||
|
||||
@@ -491,11 +512,12 @@ fun ChatDetailScreen(
|
||||
}
|
||||
|
||||
// Панель ввода
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
|
||||
) {
|
||||
if (state.selectedMessageIds.isEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
|
||||
) {
|
||||
// Pending Attachments Bar
|
||||
if (state.pendingAttachments.isNotEmpty()) {
|
||||
Row(
|
||||
@@ -895,6 +917,7 @@ fun ChatDetailScreen(
|
||||
viewModel.loadGifCategories()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ data class ChatDetailState(
|
||||
val isUploading: Boolean = false,
|
||||
val isCompressionEnabled: Boolean = true,
|
||||
val inputText: String = "",
|
||||
val replyingMessage: Message? = null
|
||||
val replyingMessage: Message? = null,
|
||||
val selectedMessageIds: Set<String> = emptySet()
|
||||
)
|
||||
|
||||
@HiltViewModel
|
||||
@@ -312,6 +313,21 @@ class ChatDetailViewModel @Inject constructor(
|
||||
_state.update { it.copy(replyingMessage = message) }
|
||||
}
|
||||
|
||||
fun toggleSelection(messageId: String) {
|
||||
_state.update { s ->
|
||||
val newSelection = if (s.selectedMessageIds.contains(messageId)) {
|
||||
s.selectedMessageIds - messageId
|
||||
} else {
|
||||
s.selectedMessageIds + messageId
|
||||
}
|
||||
s.copy(selectedMessageIds = newSelection)
|
||||
}
|
||||
}
|
||||
|
||||
fun clearSelection() {
|
||||
_state.update { it.copy(selectedMessageIds = emptySet()) }
|
||||
}
|
||||
|
||||
fun cancelReply() {
|
||||
_state.update { it.copy(replyingMessage = null) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user