mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
Improve reply/edit UI
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package ru.fromchat.ui.chat
|
package ru.fromchat.ui.chat
|
||||||
|
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@@ -7,90 +8,23 @@ import kotlin.math.abs
|
|||||||
/**
|
/**
|
||||||
* Get gradient brush for own messages
|
* Get gradient brush for own messages
|
||||||
*/
|
*/
|
||||||
fun getMessageGradient(isDark: Boolean): Brush {
|
fun getMessageGradient(isDark: Boolean) = Brush.linearGradient(
|
||||||
return if (isDark) {
|
colors = if (isDark) {
|
||||||
Brush.linearGradient(
|
listOf(
|
||||||
colors = listOf(
|
|
||||||
Color(0xFF9333EA),
|
Color(0xFF9333EA),
|
||||||
Color(0xFF6366F1),
|
Color(0xFF6366F1),
|
||||||
Color(0xFF2F68C5)
|
Color(0xFF2F68C5)
|
||||||
),
|
|
||||||
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
|
||||||
end = androidx.compose.ui.geometry.Offset(1000f, 1000f)
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Brush.linearGradient(
|
listOf(
|
||||||
colors = listOf(
|
|
||||||
Color(0xFFB794F6),
|
Color(0xFFB794F6),
|
||||||
Color(0xFF818CF8),
|
Color(0xFF818CF8),
|
||||||
Color(0xFF60A5FA)
|
Color(0xFF60A5FA)
|
||||||
),
|
|
||||||
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
|
||||||
end = androidx.compose.ui.geometry.Offset(1000f, 1000f)
|
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}
|
start = Offset(0f, 0f),
|
||||||
|
end = Offset(1000f, 1000f)
|
||||||
/**
|
|
||||||
* Get background gradient brushes for chat background
|
|
||||||
*/
|
|
||||||
fun getBackgroundGradients(isDark: Boolean): List<Brush> {
|
|
||||||
return if (isDark) {
|
|
||||||
listOf(
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x26DBA1F9),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.2f, 0.8f),
|
|
||||||
radius = 500f
|
|
||||||
),
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x26F3B7BE),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.8f, 0.2f),
|
|
||||||
radius = 500f
|
|
||||||
),
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x1AD0C1DA),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.4f, 0.4f),
|
|
||||||
radius = 500f
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
listOf(
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x15B794F6),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.2f, 0.8f),
|
|
||||||
radius = 500f
|
|
||||||
),
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x15F3B7BE),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.8f, 0.2f),
|
|
||||||
radius = 500f
|
|
||||||
),
|
|
||||||
Brush.radialGradient(
|
|
||||||
colors = listOf(
|
|
||||||
Color(0x0DD0C1DA),
|
|
||||||
Color.Transparent
|
|
||||||
),
|
|
||||||
center = androidx.compose.ui.geometry.Offset(0.4f, 0.4f),
|
|
||||||
radius = 500f
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a consistent gradient from a name for avatar fallback
|
* Generate a consistent gradient from a name for avatar fallback
|
||||||
@@ -102,21 +36,21 @@ fun generateGradientFromName(name: String): Brush {
|
|||||||
val b = abs((hash / 65536) % 256)
|
val b = abs((hash / 65536) % 256)
|
||||||
|
|
||||||
// Create two colors based on hash for gradient
|
// Create two colors based on hash for gradient
|
||||||
val color1 = Color(
|
return Brush.linearGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color(
|
||||||
red = (r + 100).coerceIn(0, 255) / 255f,
|
red = (r + 100).coerceIn(0, 255) / 255f,
|
||||||
green = (g + 100).coerceIn(0, 255) / 255f,
|
green = (g + 100).coerceIn(0, 255) / 255f,
|
||||||
blue = (b + 100).coerceIn(0, 255) / 255f
|
blue = (b + 100).coerceIn(0, 255) / 255f
|
||||||
)
|
),
|
||||||
val color2 = Color(
|
Color(
|
||||||
red = (r + 50).coerceIn(0, 255) / 255f,
|
red = (r + 50).coerceIn(0, 255) / 255f,
|
||||||
green = (g + 50).coerceIn(0, 255) / 255f,
|
green = (g + 50).coerceIn(0, 255) / 255f,
|
||||||
blue = (b + 50).coerceIn(0, 255) / 255f
|
blue = (b + 50).coerceIn(0, 255) / 255f
|
||||||
)
|
)
|
||||||
|
),
|
||||||
return Brush.linearGradient(
|
start = Offset(0f, 0f),
|
||||||
colors = listOf(color1, color2),
|
end = Offset(100f, 100f)
|
||||||
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
|
||||||
end = androidx.compose.ui.geometry.Offset(100f, 100f)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package ru.fromchat.ui.chat
|
package ru.fromchat.ui.chat
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.expandVertically
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.animation.slideInHorizontally
|
import androidx.compose.animation.slideInHorizontally
|
||||||
import androidx.compose.animation.slideOutHorizontally
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -20,15 +25,16 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.Reply
|
||||||
import androidx.compose.material.icons.automirrored.filled.Send
|
import androidx.compose.material.icons.automirrored.filled.Send
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.FilledIconButton
|
import androidx.compose.material3.FilledIconButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -41,6 +47,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
@@ -56,6 +63,78 @@ import ru.fromchat.Res
|
|||||||
import ru.fromchat.api.Message
|
import ru.fromchat.api.Message
|
||||||
import ru.fromchat.message_placeholder
|
import ru.fromchat.message_placeholder
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun <T> AnimatedPreviewBar(
|
||||||
|
state: T?,
|
||||||
|
content: @Composable (T) -> Unit
|
||||||
|
) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = state != null,
|
||||||
|
enter = fadeIn() + expandVertically(),
|
||||||
|
exit = fadeOut() + shrinkVertically()
|
||||||
|
) {
|
||||||
|
var lastState by remember { mutableStateOf(state) }
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
if (state != null) {
|
||||||
|
lastState = state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != null || lastState != null) {
|
||||||
|
content(state ?: lastState!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PreviewBar(
|
||||||
|
icon: ImageVector,
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
onClose: () -> Unit
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 12.dp, end = 12.dp, top = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(2.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = subtitle,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = onClose) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = "Close",
|
||||||
|
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalHazeMaterialsApi::class)
|
@OptIn(ExperimentalHazeMaterialsApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ChatInput(
|
fun ChatInput(
|
||||||
@@ -77,6 +156,7 @@ fun ChatInput(
|
|||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
typingJob?.cancel()
|
typingJob?.cancel()
|
||||||
typingHandler.sendTyping()
|
typingHandler.sendTyping()
|
||||||
|
@Suppress("AssignedValueIsNeverRead")
|
||||||
typingJob = scope.launch {
|
typingJob = scope.launch {
|
||||||
delay(3000) // 3 seconds
|
delay(3000) // 3 seconds
|
||||||
typingHandler.stopTyping()
|
typingHandler.stopTyping()
|
||||||
@@ -90,49 +170,18 @@ fun ChatInput(
|
|||||||
Column(
|
Column(
|
||||||
Modifier.windowInsetsPadding(WindowInsets.navigationBars)
|
Modifier.windowInsetsPadding(WindowInsets.navigationBars)
|
||||||
) {
|
) {
|
||||||
// Reply preview
|
|
||||||
replyTo?.let { reply ->
|
|
||||||
ReplyPreviewBar(
|
|
||||||
replyTo = reply,
|
|
||||||
onClose = onClearReply,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 8.dp, vertical = 4.dp)
|
|
||||||
.hazeEffect(hazeState, style = HazeMaterials.thick())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Edit preview
|
|
||||||
editingMessage?.let { edit ->
|
|
||||||
EditPreviewBar(
|
|
||||||
message = edit,
|
|
||||||
onClose = onClearEdit,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 8.dp, vertical = 4.dp)
|
|
||||||
.hazeEffect(hazeState, style = HazeMaterials.thick())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input field with blur
|
// Input field with blur
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(Color.Transparent)
|
.background(Color.Transparent)
|
||||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
) {
|
||||||
val shape = RoundedCornerShape(24.dp)
|
val shape = RoundedCornerShape(24.dp)
|
||||||
|
|
||||||
OutlinedTextField(
|
Column(
|
||||||
value = text,
|
|
||||||
onValueChange = onTextChange,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.fillMaxWidth()
|
||||||
.border(
|
.border(
|
||||||
Dp.Hairline,
|
Dp.Hairline,
|
||||||
MaterialTheme.colorScheme.outline.copy(alpha = 0.5f),
|
MaterialTheme.colorScheme.outline.copy(alpha = 0.5f),
|
||||||
@@ -142,7 +191,32 @@ fun ChatInput(
|
|||||||
.hazeEffect(
|
.hazeEffect(
|
||||||
state = hazeState,
|
state = hazeState,
|
||||||
style = HazeMaterials.thin()
|
style = HazeMaterials.thin()
|
||||||
),
|
)
|
||||||
|
) {
|
||||||
|
AnimatedPreviewBar(replyTo) { replyTo ->
|
||||||
|
PreviewBar(
|
||||||
|
icon = Icons.AutoMirrored.Filled.Reply,
|
||||||
|
title = "Replying to ${replyTo.username}",
|
||||||
|
subtitle = replyTo.content.take(50) + if (replyTo.content.length > 50) "..." else "",
|
||||||
|
onClose = { onClearReply() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedPreviewBar(editingMessage) { message ->
|
||||||
|
PreviewBar(
|
||||||
|
icon = Icons.Filled.Edit,
|
||||||
|
title = "Editing message",
|
||||||
|
subtitle = message.content.take(50) + if (message.content.length > 50) "..." else "",
|
||||||
|
onClose = { onClearEdit() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = text,
|
||||||
|
onValueChange = onTextChange,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.animateContentSize(),
|
||||||
placeholder = {
|
placeholder = {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(Res.string.message_placeholder),
|
text = stringResource(Res.string.message_placeholder),
|
||||||
@@ -200,91 +274,3 @@ fun ChatInput(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ReplyPreviewBar(
|
|
||||||
replyTo: Message,
|
|
||||||
onClose: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Surface(
|
|
||||||
modifier = modifier, // hazeEffect moved to ChatInput where it's called
|
|
||||||
shape = RoundedCornerShape(8.dp),
|
|
||||||
color = Color.Transparent
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
|
||||||
Text(
|
|
||||||
text = "Replying to ${replyTo.username}",
|
|
||||||
style = MaterialTheme.typography.labelSmall,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
color = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(2.dp))
|
|
||||||
Text(
|
|
||||||
text = replyTo.content.take(50) + if (replyTo.content.length > 50) "..." else "",
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
IconButton(onClick = onClose) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Close,
|
|
||||||
contentDescription = "Close",
|
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun EditPreviewBar(
|
|
||||||
message: Message,
|
|
||||||
onClose: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Surface(
|
|
||||||
modifier = modifier, // hazeEffect moved to ChatInput where it's called
|
|
||||||
shape = RoundedCornerShape(8.dp),
|
|
||||||
color = Color.Transparent
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
|
||||||
Text(
|
|
||||||
text = "Editing message",
|
|
||||||
style = MaterialTheme.typography.labelSmall,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
color = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(2.dp))
|
|
||||||
Text(
|
|
||||||
text = message.content.take(50) + if (message.content.length > 50) "..." else "",
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
IconButton(onClick = onClose) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Close,
|
|
||||||
contentDescription = "Close",
|
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -279,7 +279,10 @@ fun ChatScreen(
|
|||||||
replyTo = replyTo,
|
replyTo = replyTo,
|
||||||
editingMessage = editingMessage,
|
editingMessage = editingMessage,
|
||||||
onClearReply = { replyTo = null },
|
onClearReply = { replyTo = null },
|
||||||
onClearEdit = { editingMessage = null },
|
onClearEdit = {
|
||||||
|
editingMessage = null
|
||||||
|
inputText = ""
|
||||||
|
},
|
||||||
hazeState = hazeState
|
hazeState = hazeState
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -355,13 +358,17 @@ fun ChatScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Context menu
|
// Context menu
|
||||||
|
@Suppress("AssignedValueIsNeverRead")
|
||||||
MessageContextMenu(
|
MessageContextMenu(
|
||||||
state = contextMenuState,
|
state = contextMenuState,
|
||||||
isAuthor = contextMenuState.message?.user_id == currentUserId,
|
isAuthor = contextMenuState.message?.user_id == currentUserId,
|
||||||
onDismiss = { contextMenuState = contextMenuState.copy(isOpen = false) },
|
onDismiss = { contextMenuState = contextMenuState.copy(isOpen = false) },
|
||||||
onReply = { message ->
|
onReply = { message ->
|
||||||
replyTo = message
|
replyTo = message
|
||||||
|
if (editingMessage != null) {
|
||||||
editingMessage = null
|
editingMessage = null
|
||||||
|
inputText = ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onEdit = { message ->
|
onEdit = { message ->
|
||||||
editingMessage = message
|
editingMessage = message
|
||||||
|
|||||||
Reference in New Issue
Block a user