Refactor: Improve reply component layout and styling

This commit refactors the `Reply` composable for better layout consistency and simplifies its implementation.

The `Reply` component no longer uses a fixed height, allowing it to dynamically resize based on its content. The layout has been updated from a `Box` to a `Row` to properly align the side indicator bar with the height of the text content. Padding and corner rounding logic has been simplified and centralized within the `Reply` composable itself, removing redundant parameters from the `MessageBubble`.

Key changes:
- `Reply` composable now uses `Row` for its root layout instead of `Box`.
- Removed the fixed `48.dp` height to allow dynamic content sizing.
- The side indicator bar's height now matches the text content's height.
- Simplified padding and shape logic in `MessageBubble` by removing conditional parameters passed to `Reply`.
- Adjusted padding inside `MessageBubble` to accommodate the new `Reply` layout.
This commit is contained in:
2026-02-06 22:58:03 +03:00
parent 96b4fc8539
commit ce375c902c
2 changed files with 41 additions and 53 deletions
@@ -118,15 +118,10 @@ fun MessageBubble(
) { ) {
if (replyTitle != null) { if (replyTitle != null) {
Reply( Reply(
modifier = Modifier modifier = Modifier.width(with(density) { containerWidth.toDp() }),
.padding(if (attachments == null || text != null) 0.dp else 0.dp)
.width(with(density) { containerWidth.toDp() }),
bottomPadding = if (attachments == null || text != null) 0.dp else 4.dp,
shape = RoundedCornerShape( shape = RoundedCornerShape(
topStart = 16.dp, topStart = 16.dp,
topEnd = 16.dp, topEnd = 16.dp,
bottomStart = if (attachments == null || text != null) 0.dp else 0.dp,
bottomEnd = if (attachments == null || text != null) 0.dp else 0.dp
), ),
onClick = onReplyClick, onClick = onReplyClick,
title = replyTitle, title = replyTitle,
@@ -160,7 +155,7 @@ fun MessageBubble(
.padding( .padding(
start = 8.dp, start = 8.dp,
end = 8.dp, end = 8.dp,
top = if (replyTitle != null) 4.dp else 6.dp, top = if (replyTitle != null) 0.dp else 6.dp,
bottom = if (replyTitle != null) 4.dp else 6.dp bottom = if (replyTitle != null) 4.dp else 6.dp
) )
.then(if (theme.enableAnimations) Modifier.animateContentSize() else Modifier), .then(if (theme.enableAnimations) Modifier.animateContentSize() else Modifier),
@@ -8,9 +8,6 @@ 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.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
@@ -19,16 +16,21 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.conena.nanokt.android.content.pxToDp
import dev.meloda.fast.domain.util.annotated import dev.meloda.fast.domain.util.annotated
import dev.meloda.fast.domain.util.orEmpty import dev.meloda.fast.domain.util.orEmpty
import dev.meloda.fast.ui.common.FastPreview import dev.meloda.fast.ui.common.FastPreview
@@ -37,7 +39,6 @@ import dev.meloda.fast.ui.theme.AppTheme
@Composable @Composable
fun Reply( fun Reply(
onClick: () -> Unit, onClick: () -> Unit,
bottomPadding: Dp,
shape: Shape, shape: Shape,
backgroundColor: Color, backgroundColor: Color,
innerBackgroundColor: Color, innerBackgroundColor: Color,
@@ -47,60 +48,54 @@ fun Reply(
summary: AnnotatedString?, summary: AnnotatedString?,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
Box( var innerContainerHeight by remember {
mutableIntStateOf(0)
}
Row(
modifier = modifier modifier = modifier
.background( .background(
color = backgroundColor, color = backgroundColor,
shape = shape shape = shape
) )
.height(48.dp) .padding(4.dp)
.padding( .clip(RoundedCornerShape(12.dp))
top = 4.dp, .clickable(onClick = onClick)
start = 4.dp, .background(innerBackgroundColor),
end = 4.dp, horizontalArrangement = Arrangement.spacedBy(6.dp)
bottom = bottomPadding
)
) { ) {
Row( Box(
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(12.dp)) .width(3.dp)
.clickable(onClick = onClick) .height(innerContainerHeight.dp + 12.dp)
.fillMaxSize() .background(MaterialTheme.colorScheme.primary)
.background(innerBackgroundColor) )
Column(
modifier = Modifier
.padding(vertical = 6.dp)
.padding(end = 9.dp)
.onGloballyPositioned { innerContainerHeight = it.size.height.pxToDp() }
) { ) {
Box( Text(
modifier = Modifier text = title,
.width(3.dp) style = MaterialTheme.typography.labelLarge,
.fillMaxHeight() maxLines = 1,
.background(MaterialTheme.colorScheme.primary) overflow = TextOverflow.Ellipsis,
lineHeight = 16.sp,
color = titleColor
) )
Spacer(modifier = Modifier.width(6.dp)) AnimatedVisibility(summary != null) {
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.Center
) {
Text( Text(
text = title, text = summary.orEmpty(),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelMedium,
fontWeight = FontWeight.Normal,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
lineHeight = 16.sp, lineHeight = 16.sp,
color = titleColor color = textColor
) )
AnimatedVisibility(summary != null) {
Text(
text = summary.orEmpty(),
style = MaterialTheme.typography.labelMedium,
fontWeight = FontWeight.Normal,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
lineHeight = 20.sp,
color = textColor
)
}
} }
} }
} }
@@ -114,7 +109,6 @@ private fun ReplyBasePreview(
textColor: Color textColor: Color
) { ) {
Reply( Reply(
modifier = Modifier.width(120.dp),
shape = RoundedCornerShape( shape = RoundedCornerShape(
topStart = 12.dp, topStart = 12.dp,
topEnd = 12.dp topEnd = 12.dp
@@ -126,7 +120,6 @@ private fun ReplyBasePreview(
innerBackgroundColor = innerBackgroundColor, innerBackgroundColor = innerBackgroundColor,
titleColor = titleColor, titleColor = titleColor,
textColor = textColor, textColor = textColor,
bottomPadding = 0.dp,
) )
} }