From 1d165a5dc32a2361402c4a65bdc0c1b754f2e4fc Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sun, 22 Jun 2025 19:26:36 +0000 Subject: [PATCH] Refactor: Improve UI consistency and animations (#2226) --- .../mesh/ui/common/components/AutoLinkText.kt | 4 +- .../geeksville/mesh/ui/message/MessageList.kt | 1 + .../mesh/ui/message/components/MessageItem.kt | 37 +++++++++++-------- .../com/geeksville/mesh/ui/node/NodeScreen.kt | 3 +- .../mesh/ui/node/components/NodeItem.kt | 16 ++++++++ 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/components/AutoLinkText.kt b/app/src/main/java/com/geeksville/mesh/ui/common/components/AutoLinkText.kt index 70e6317ee..9276bc277 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/components/AutoLinkText.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/common/components/AutoLinkText.kt @@ -25,6 +25,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.LinkAnnotation import androidx.compose.ui.text.SpanStyle @@ -50,6 +51,7 @@ fun AutoLinkText( modifier: Modifier = Modifier, style: TextStyle = TextStyle.Default, linkStyles: TextLinkStyles = DefaultTextLinkStyles, + color: Color = Color.Unspecified, ) { val spannable = remember(text) { linkify(text) @@ -57,7 +59,7 @@ fun AutoLinkText( Text( text = spannable.toAnnotatedString(linkStyles), modifier = modifier, - style = style, + style = style.copy(color = color), ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt b/app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt index 1406c1f0c..9fbaeee57 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/message/MessageList.kt @@ -172,6 +172,7 @@ internal fun MessageList( mutableStateOf(nodes.find { it.num == msg.node.num } ?: msg.node) } MessageItem( + modifier = Modifier.animateItem(), node = node, ourNode = ourNode!!, message = msg, diff --git a/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt b/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt index bf2ca1c58..7a4352c4f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/message/components/MessageItem.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FormatQuote import androidx.compose.material3.Card +import androidx.compose.material3.CardColors import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon @@ -89,11 +90,17 @@ internal fun MessageItem( .background(color = if (selected) Color.Gray else MaterialTheme.colorScheme.background), ) { val fromLocal = node.user.id == DataPacket.ID_LOCAL - val messageColor = if (fromLocal) { - Color(ourNode.colors.second).copy(alpha = 0.25f) - } else { - Color(node.colors.second).copy(alpha = 0.25f) - } + val containerColor = Color( + if (fromLocal) { + ourNode.colors.second + } else { + node.colors.second + } + ).copy(alpha = 0.2f) + val cardColors = CardDefaults.cardColors().copy( + containerColor = containerColor, + contentColor = contentColorFor(containerColor) + ) val messageModifier = Modifier.padding(start = 8.dp, top = 8.dp, end = 8.dp) Box { Card( @@ -109,17 +116,18 @@ internal fun MessageItem( onLongClick = onLongClick, ) .then(messageModifier), - colors = CardDefaults.cardColors( - containerColor = messageColor, - contentColor = contentColorFor(messageColor), - ), + colors = cardColors, ) { Column( modifier = Modifier .fillMaxWidth(), ) { - ReplyingTo(message, ourNode, onNavigateToOriginalMessage) - + ReplyingTo( + message = message, + ourNode = ourNode, + cardColors = cardColors, + onNavigateToOriginalMessage = onNavigateToOriginalMessage + ) Row( modifier = Modifier .fillMaxWidth() @@ -154,6 +162,7 @@ internal fun MessageItem( .padding(horizontal = 8.dp), text = message.text, style = MaterialTheme.typography.bodyMedium, + color = cardColors.contentColor ) Row( modifier = Modifier @@ -208,6 +217,7 @@ internal fun MessageItem( private fun ReplyingTo( message: Message, ourNode: Node, + cardColors: CardColors = CardDefaults.cardColors(), onNavigateToOriginalMessage: (Int) -> Unit ) { message.originalMessage?.let { originalMessage -> @@ -219,10 +229,7 @@ private fun ReplyingTo( modifier = Modifier .fillMaxWidth() .clickable { onNavigateToOriginalMessage(originalMessage.packetId) }, - colors = CardDefaults.cardColors( - containerColor = Color(originalMessageNode.colors.second).copy(alpha = 0.5f), - contentColor = Color(originalMessageNode.colors.first), - ), + colors = cardColors, ) { Row( modifier = Modifier.padding(horizontal = 4.dp), diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt index 9034bdb6e..aaf4b2265 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/node/NodeScreen.kt @@ -18,7 +18,6 @@ package com.geeksville.mesh.ui.node import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -115,7 +114,7 @@ fun NodeScreen( items(nodes, key = { it.num }) { node -> NodeItem( - modifier = Modifier.animateContentSize(), + modifier = Modifier.animateItem(), thisNode = ourNode, thatNode = node, gpsFormat = state.gpsFormat, diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt b/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt index a590cf068..0cc2873b5 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/node/components/NodeItem.kt @@ -29,15 +29,18 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign @@ -96,6 +99,18 @@ fun NodeItem( LocalTextStyle.current } + val cardColors = if (isThisNode) { + thisNode?.colors?.second + } else { + thatNode.colors.second + }?.let { + val containerColor = Color(it).copy(alpha = 0.2f) + CardDefaults.cardColors().copy( + containerColor = containerColor, + contentColor = contentColorFor(containerColor) + ) + } ?: (CardDefaults.cardColors()) + val (detailsShown, showDetails) = remember { mutableStateOf(expanded) } val unmessageable = remember(thatNode) { when { @@ -110,6 +125,7 @@ fun NodeItem( .padding(horizontal = 8.dp, vertical = 4.dp) .defaultMinSize(minHeight = 80.dp), onClick = { showDetails(!detailsShown) }, + colors = cardColors ) { Column( modifier = Modifier