Skip to content

Commit 853c3bd

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

3 files changed

Lines changed: 66 additions & 16 deletions

File tree

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

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import androidx.compose.runtime.getValue
6666
import androidx.compose.runtime.mutableStateOf
6767
import androidx.compose.runtime.remember
6868
import androidx.compose.runtime.rememberCoroutineScope
69+
import androidx.compose.runtime.saveable.rememberSaveable
6970
import androidx.compose.runtime.setValue
7071
import androidx.compose.ui.Alignment
7172
import androidx.compose.ui.Modifier
@@ -83,8 +84,11 @@ import androidx.compose.ui.platform.LocalUriHandler
8384
import androidx.compose.ui.platform.testTag
8485
import androidx.compose.ui.res.painterResource
8586
import androidx.compose.ui.res.stringResource
87+
import androidx.compose.ui.semantics.Role
8688
import androidx.compose.ui.semantics.semantics
89+
import androidx.compose.ui.text.style.TextDecoration
8790
import androidx.compose.ui.tooling.preview.Preview
91+
import androidx.compose.ui.text.style.TextOverflow
8892
import androidx.compose.ui.unit.dp
8993
import com.example.compose.jetchat.FunctionalityNotAvailablePopup
9094
import com.example.compose.jetchat.R
@@ -440,6 +444,7 @@ private fun AuthorNameTimestamp(msg: Message) {
440444
}
441445

442446
private val ChatBubbleShape = RoundedCornerShape(4.dp, 20.dp, 20.dp, 20.dp)
447+
private const val MessageCollapsedMaxLines = 8
443448

444449
@Composable
445450
fun DayHeader(dayString: String) {
@@ -516,23 +521,51 @@ fun ClickableMessage(message: Message, isUserMe: Boolean, authorClicked: (String
516521
primary = isUserMe,
517522
)
518523

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
524+
var isExpanded by rememberSaveable { mutableStateOf(false) }
525+
var isOverflowing by remember { mutableStateOf(false) }
526+
527+
Column {
528+
ClickableText(
529+
text = styledMessage,
530+
style = MaterialTheme.typography.bodyLarge.copy(color = LocalContentColor.current),
531+
modifier = Modifier.padding(
532+
start = 16.dp,
533+
end = 16.dp,
534+
top = 16.dp,
535+
bottom = if (isOverflowing && !isExpanded) 4.dp else 16.dp,
536+
),
537+
maxLines = if (isExpanded) Int.MAX_VALUE else MessageCollapsedMaxLines,
538+
overflow = TextOverflow.Ellipsis,
539+
onTextLayout = { isOverflowing = it.hasVisualOverflow },
540+
onClick = {
541+
styledMessage
542+
.getStringAnnotations(start = it, end = it)
543+
.firstOrNull()
544+
?.let { annotation ->
545+
when (annotation.tag) {
546+
SymbolAnnotationType.LINK.name -> uriHandler.openUri(annotation.item)
547+
SymbolAnnotationType.PERSON.name -> authorClicked(annotation.item)
548+
else -> Unit
549+
}
532550
}
533-
}
534-
},
535-
)
551+
},
552+
)
553+
if (isOverflowing && !isExpanded) {
554+
Text(
555+
text = stringResource(id = R.string.show_more),
556+
style = MaterialTheme.typography.bodyMedium,
557+
color = if (isUserMe) {
558+
MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f)
559+
} else {
560+
MaterialTheme.colorScheme.primary
561+
},
562+
modifier = Modifier
563+
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
564+
.clickable(role = Role.Button) { isExpanded = true },
565+
textDecoration = TextDecoration.Underline
566+
)
567+
}
568+
}
536569
}
537570

538571
@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!",

Jetchat/app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<string name="swipe_to_cancel_recording">&#x25C0; Swipe to cancel</string>
3939
<string name="emojis_label">Emojis</string>
4040
<string name="stickers_label">Stickers</string>
41+
<string name="show_more">Show more</string>
4142

4243
<string name="message">Message</string>
4344
<string name="edit_profile">Edit Profile</string>

0 commit comments

Comments
 (0)