Refactor: Encapsulate MessageBubble colors

This commit refactors the `MessageBubble` composable by extracting the color logic into a private `messageBubbleColors` function. This function returns an immutable `MessageBubbleColors` data class, which holds the container, content, and reply container colors.

This change cleans up the main composable, improves readability, and centralizes color definitions for both incoming and outgoing messages. Additionally, the background color logic for attachments has been simplified to make it transparent for media types like stickers and videos.
This commit is contained in:
2025-12-15 23:01:38 +03:00
parent 8839015249
commit 69a50f8fcd
@@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@@ -68,22 +69,7 @@ fun MessageBubble(
val currentOnLongClick by rememberUpdatedState(onLongClick) val currentOnLongClick by rememberUpdatedState(onLongClick)
val theme = LocalThemeConfig.current val theme = LocalThemeConfig.current
val backgroundColor = if (!isOut) { val colors = messageBubbleColors(isOut = isOut)
MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)
} else {
MaterialTheme.colorScheme.primaryContainer
}
val replyBackgroundColor = if (!isOut) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.inversePrimary
}
val contentColor = if (!isOut) {
MaterialTheme.colorScheme.onSurface
} else {
MaterialTheme.colorScheme.onPrimaryContainer
}
val shouldShowBubble = !text.isNullOrEmpty() val shouldShowBubble = !text.isNullOrEmpty()
@@ -117,7 +103,7 @@ fun MessageBubble(
label = "dateContainerWidth" label = "dateContainerWidth"
) )
CompositionLocalProvider(LocalContentColor provides contentColor) { CompositionLocalProvider(LocalContentColor provides colors.content) {
Column( Column(
modifier = modifier modifier = modifier
.wrapContentWidth() .wrapContentWidth()
@@ -140,8 +126,8 @@ fun MessageBubble(
onClick = onReplyClick, onClick = onReplyClick,
title = replyTitle, title = replyTitle,
summary = replySummary, summary = replySummary,
backgroundColor = backgroundColor, backgroundColor = colors.container,
innerBackgroundColor = replyBackgroundColor innerBackgroundColor = colors.replyContainer
) )
} }
@@ -163,7 +149,7 @@ fun MessageBubble(
bottomEnd = if (attachments != null) 0.dp else 24.dp bottomEnd = if (attachments != null) 0.dp else 24.dp
) )
) )
.background(backgroundColor) .background(colors.container)
.padding( .padding(
start = 8.dp, start = 8.dp,
end = 8.dp, end = 8.dp,
@@ -204,6 +190,15 @@ fun MessageBubble(
} }
if (attachments != null) { if (attachments != null) {
val firstAttachment = attachments.firstOrNull()
val isMediaAttachment = firstAttachment is VkStickerDomain ||
firstAttachment is VkVideoMessageDomain
val attachmentBackgroundColor = if (isMediaAttachment) {
Color.Transparent
} else {
colors.container
}
Box( Box(
modifier = Modifier modifier = Modifier
.onGloballyPositioned { .onGloballyPositioned {
@@ -218,18 +213,7 @@ fun MessageBubble(
topEnd = 0.dp topEnd = 0.dp
) )
) )
.background( .background(attachmentBackgroundColor)
backgroundColor.copy(
alpha = if ((attachments.firstOrNull()?.javaClass
?: Nothing::class.java)
in listOf(
VkStickerDomain::class.java,
VkVideoMessageDomain::class.java
)
) 0f
else 1f
)
)
) { ) {
Attachments( Attachments(
modifier = Modifier, modifier = Modifier,
@@ -241,7 +225,7 @@ fun MessageBubble(
val dateStatusBackground = if (theme.darkMode) Color.Black.copy(alpha = 0.5f) val dateStatusBackground = if (theme.darkMode) Color.Black.copy(alpha = 0.5f)
else Color.White.copy(alpha = 0.5f) else Color.White.copy(alpha = 0.5f)
CompositionLocalProvider(LocalContentColor provides contentColor) { CompositionLocalProvider(LocalContentColor provides colors.content) {
DateStatus( DateStatus(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomEnd) .align(Alignment.BottomEnd)
@@ -266,6 +250,30 @@ fun MessageBubble(
} }
} }
@Immutable
private data class MessageBubbleColors(
val container: Color,
val content: Color,
val replyContainer: Color,
)
@Composable
private fun messageBubbleColors(isOut: Boolean): MessageBubbleColors {
return if (isOut) {
MessageBubbleColors(
container = MaterialTheme.colorScheme.primaryContainer,
content = MaterialTheme.colorScheme.onPrimaryContainer,
replyContainer = MaterialTheme.colorScheme.inversePrimary
)
} else {
MessageBubbleColors(
container = MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp),
content = MaterialTheme.colorScheme.onSurface,
replyContainer = MaterialTheme.colorScheme.primaryContainer
)
}
}
@Preview @Preview
@Composable @Composable
private fun Bubble() { private fun Bubble() {