update reaction design

This commit is contained in:
2026-09-07 18:40:14 +07:00
parent c4d3870a02
commit 91817d7061
@@ -5,10 +5,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
@@ -27,7 +26,6 @@ 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.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.boundsInWindow
@@ -188,42 +186,53 @@ fun ChatMessage(
horizontalAlignment = if (model.isMine) Alignment.End else Alignment.Start, horizontalAlignment = if (model.isMine) Alignment.End else Alignment.Start,
verticalArrangement = Arrangement.spacedBy(4.dp) verticalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
if (model.annotatedContent.isNotBlank()) { Box(contentAlignment = Alignment.BottomEnd) {
Surface( Column(
modifier = Modifier.widthIn(max = 280.dp), modifier = Modifier.padding(
color = containerColor, bottom = if (model.reactions.isNotEmpty()) 4.dp else 0.dp,
contentColor = contentColor, end = if (model.reactions.isNotEmpty() && !model.isMine) 8.dp else 0.dp
shape = bubbleShape, ),
horizontalAlignment = if (model.isMine) Alignment.End else Alignment.Start,
verticalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
Text( if (model.annotatedContent.isNotBlank()) {
text = model.annotatedContent, Surface(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), modifier = Modifier.widthIn(max = 280.dp),
style = MaterialTheme.typography.bodyLarge color = containerColor,
) contentColor = contentColor,
shape = bubbleShape,
) {
Text(
text = model.annotatedContent,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
style = MaterialTheme.typography.bodyLarge
)
}
}
model.images.forEach { imageUrl ->
Surface(
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier.widthIn(max = 280.dp)
) {
AsyncImage(
model = imageUrl,
contentDescription = "Image from chat",
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp)),
contentScale = ContentScale.FillWidth
)
}
}
} }
}
model.images.forEach { imageUrl ->
Surface(
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier.widthIn(max = 280.dp)
) {
AsyncImage(
model = imageUrl,
contentDescription = "Image from chat",
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp)),
contentScale = ContentScale.FillWidth
)
}
}
if (model.reactions.isNotEmpty()) { if (model.reactions.isNotEmpty()) {
ReactionsRow( MessageReactions(
reactions = model.reactions, reactions = model.reactions,
modifier = Modifier.padding(top = 2.dp) modifier = Modifier.offset(y = 12.dp)
) )
}
} }
if (isMessageClicked) { if (isMessageClicked) {
@@ -231,64 +240,53 @@ fun ChatMessage(
text = model.timestamp, text = model.timestamp,
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.outline, color = MaterialTheme.colorScheme.outline,
modifier = Modifier.align( modifier = Modifier.padding(top = if (model.reactions.isNotEmpty()) 8.dp else 0.dp)
if (model.isMine) Alignment.End else Alignment.Start
)
) )
} }
} }
} }
} }
@OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
private fun ReactionsRow( private fun MessageReactions(
reactions: List<ReactionGroup>, reactions: List<ReactionGroup>,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
FlowRow( val totalCount = reactions.sumOf { it.authors.size }
val displayEmojis = reactions.take(3).map { it.emoji }
Row(
modifier = modifier, modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically,
verticalArrangement = Arrangement.spacedBy(4.dp) horizontalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
reactions.forEach { group -> displayEmojis.forEach { emoji ->
ReactionChip(group) Surface(
modifier = Modifier.size(24.dp),
color = MaterialTheme.colorScheme.surface,
shape = CircleShape,
) {
Box(contentAlignment = Alignment.Center) {
Text(
text = emoji,
fontSize = 12.sp,
)
}
}
} }
} if (totalCount > 2) {
} Surface(
modifier = Modifier.size(24.dp),
@Composable color = MaterialTheme.colorScheme.surface,
private fun ReactionChip(group: ReactionGroup) { shape = CircleShape,
val backgroundColor = if (group.containsMe) { ) {
MaterialTheme.colorScheme.secondaryContainer Box(contentAlignment = Alignment.Center) {
} else { Text(
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f) text = totalCount.toString(),
} style = MaterialTheme.typography.labelSmall,
fontSize = 10.sp,
val contentColor = if (group.containsMe) { )
MaterialTheme.colorScheme.onSecondaryContainer }
} else {
MaterialTheme.colorScheme.onSurfaceVariant
}
Surface(
color = backgroundColor,
contentColor = contentColor,
shape = CircleShape,
modifier = Modifier.padding(vertical = 2.dp)
) {
Row(
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Text(text = group.emoji, fontSize = 14.sp)
if (group.authors.size > 1) {
Text(
text = group.authors.size.toString(),
style = MaterialTheme.typography.labelSmall,
fontWeight = FontWeight.Bold
)
} }
} }
} }