@@ -66,6 +66,7 @@ import androidx.compose.runtime.getValue
6666import androidx.compose.runtime.mutableStateOf
6767import androidx.compose.runtime.remember
6868import androidx.compose.runtime.rememberCoroutineScope
69+ import androidx.compose.runtime.saveable.rememberSaveable
6970import androidx.compose.runtime.setValue
7071import androidx.compose.ui.Alignment
7172import androidx.compose.ui.Modifier
@@ -83,8 +84,11 @@ import androidx.compose.ui.platform.LocalUriHandler
8384import androidx.compose.ui.platform.testTag
8485import androidx.compose.ui.res.painterResource
8586import androidx.compose.ui.res.stringResource
87+ import androidx.compose.ui.semantics.Role
8688import androidx.compose.ui.semantics.semantics
89+ import androidx.compose.ui.text.style.TextDecoration
8790import androidx.compose.ui.tooling.preview.Preview
91+ import androidx.compose.ui.text.style.TextOverflow
8892import androidx.compose.ui.unit.dp
8993import com.example.compose.jetchat.FunctionalityNotAvailablePopup
9094import com.example.compose.jetchat.R
@@ -440,6 +444,7 @@ private fun AuthorNameTimestamp(msg: Message) {
440444}
441445
442446private val ChatBubbleShape = RoundedCornerShape (4 .dp, 20 .dp, 20 .dp, 20 .dp)
447+ private const val MessageCollapsedMaxLines = 8
443448
444449@Composable
445450fun 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
0 commit comments