Skip to content

Commit 708fe48

Browse files
committed
Add "show more" to truncate long chat messages at 8 lines
1 parent d3ff757 commit 708fe48

2 files changed

Lines changed: 63 additions & 16 deletions

File tree

Jetchat/app/src/main/java/com/example/compose/jetchat/conversation/Conversation.kt

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ import androidx.compose.ui.platform.testTag
8484
import androidx.compose.ui.res.painterResource
8585
import androidx.compose.ui.res.stringResource
8686
import androidx.compose.ui.semantics.semantics
87+
import androidx.compose.ui.text.style.TextDecoration
8788
import androidx.compose.ui.tooling.preview.Preview
89+
import androidx.compose.ui.text.style.TextOverflow
8890
import androidx.compose.ui.unit.dp
8991
import com.example.compose.jetchat.FunctionalityNotAvailablePopup
9092
import com.example.compose.jetchat.R
@@ -440,6 +442,7 @@ private fun AuthorNameTimestamp(msg: Message) {
440442
}
441443

442444
private val ChatBubbleShape = RoundedCornerShape(4.dp, 20.dp, 20.dp, 20.dp)
445+
private const val MessageCollapsedMaxLines = 8
443446

444447
@Composable
445448
fun DayHeader(dayString: String) {
@@ -516,23 +519,51 @@ fun ClickableMessage(message: Message, isUserMe: Boolean, authorClicked: (String
516519
primary = isUserMe,
517520
)
518521

519-
ClickableText(
520-
text = styledMessage,
521-
style = MaterialTheme.typography.bodyLarge.copy(color = LocalContentColor.current),
522-
modifier = Modifier.padding(16.dp),
523-
onClick = {
524-
styledMessage
525-
.getStringAnnotations(start = it, end = it)
526-
.firstOrNull()
527-
?.let { annotation ->
528-
when (annotation.tag) {
529-
SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item)
530-
SymbolAnnotationType.PERSON.name -> authorClicked(annotation.item)
531-
else -> Unit
522+
var isExpanded by remember { mutableStateOf(false) }
523+
var isOverflowing by remember { mutableStateOf(false) }
524+
525+
Column {
526+
ClickableText(
527+
text = styledMessage,
528+
style = MaterialTheme.typography.bodyLarge.copy(color = LocalContentColor.current),
529+
modifier = Modifier.padding(
530+
start = 16.dp,
531+
end = 16.dp,
532+
top = 16.dp,
533+
bottom = if (isOverflowing && !isExpanded) 4.dp else 16.dp,
534+
),
535+
maxLines = if (isExpanded) Int.MAX_VALUE else MessageCollapsedMaxLines,
536+
overflow = TextOverflow.Ellipsis,
537+
onTextLayout = { isOverflowing = it.hasVisualOverflow },
538+
onClick = {
539+
styledMessage
540+
.getStringAnnotations(start = it, end = it)
541+
.firstOrNull()
542+
?.let { annotation ->
543+
when (annotation.tag) {
544+
SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item)
545+
SymbolAnnotationType.PERSON.name -> authorClicked(annotation.item)
546+
else -> Unit
547+
}
532548
}
533-
}
534-
},
535-
)
549+
},
550+
)
551+
if (isOverflowing && !isExpanded) {
552+
Text(
553+
text = "Show more",
554+
style = MaterialTheme.typography.bodyMedium,
555+
color = if (isUserMe) {
556+
MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f)
557+
} else {
558+
MaterialTheme.colorScheme.primary
559+
},
560+
modifier = Modifier
561+
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
562+
.clickable { isExpanded = true },
563+
textDecoration = TextDecoration.Underline
564+
)
565+
}
566+
}
536567
}
537568

538569
@Preview

Jetchat/app/src/main/java/com/example/compose/jetchat/data/FakeData.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ import com.example.compose.jetchat.data.EMOJIS.EMOJI_POINTS
2727
import com.example.compose.jetchat.profile.ProfileScreenState
2828

2929
val initialMessages = listOf(
30+
Message(
31+
author = "me",
32+
content = "One thing I keep coming back to with Compose is how much easier state management " +
33+
"has become. In the old View world you'd have to manually sync your UI to the model " +
34+
"(call setText, setVisibility, notifyDataSetChanged) and it was really easy to miss a " +
35+
"spot and end up with stale UI. With Compose, you just describe what the UI should " +
36+
"look like for a given state and the framework takes care of the rest.\n" +
37+
"The mental shift to thinking in terms of unidirectional data flow took a bit of " +
38+
"getting used to, but once it clicked everything felt a lot more predictable. " +
39+
"ViewModel + StateFlow + collectAsStateWithLifecycle is my go-to pattern now. " +
40+
"Recomposition is still something I have to reason about carefully — especially " +
41+
"around derived state and lambdas capturing stale values — but the tooling keeps " +
42+
"getting better. Layout Inspector showing recomposition counts has been a huge help " +
43+
"for spotting unnecessary work.",
44+
timestamp = "8:15 PM"
45+
),
3046
Message(
3147
"me",
3248
"Check it out!",

0 commit comments

Comments
 (0)