mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-16 03:49:33 -04:00
ui update/cleanup: Message padding updates (#2289)
This commit is contained in:
@@ -35,10 +35,12 @@ data class PacketEntity(
|
||||
val reactions: List<ReactionEntity> = emptyList(),
|
||||
) {
|
||||
suspend fun toMessage(getNode: suspend (userId: String?) -> Node) = with(packet) {
|
||||
val node = getNode(data.from)
|
||||
Message(
|
||||
uuid = uuid,
|
||||
receivedTime = received_time,
|
||||
node = getNode(data.from),
|
||||
node = node,
|
||||
fromLocal = node.user.id == DataPacket.ID_LOCAL,
|
||||
text = data.text.orEmpty(),
|
||||
time = getShortDateTime(data.time),
|
||||
snr = snr,
|
||||
|
||||
@@ -50,6 +50,7 @@ data class Message(
|
||||
val receivedTime: Long,
|
||||
val node: Node,
|
||||
val text: String,
|
||||
val fromLocal: Boolean,
|
||||
val time: String,
|
||||
val read: Boolean,
|
||||
val status: MessageStatus?,
|
||||
|
||||
@@ -61,7 +61,7 @@ class NodePreviewParameterProvider : PreviewParameterProvider<Node> {
|
||||
hopsAway = 0
|
||||
)
|
||||
|
||||
private val minnieMouse = mickeyMouse.copy(
|
||||
val minnieMouse = mickeyMouse.copy(
|
||||
num = Random.nextInt(),
|
||||
user = user {
|
||||
longName = "Minnie Mouse"
|
||||
|
||||
@@ -166,9 +166,10 @@ internal fun MessageList(
|
||||
items(messages, key = { it.uuid }) { msg ->
|
||||
if (ourNode != null) {
|
||||
val selected by remember { derivedStateOf { selectedIds.value.contains(msg.uuid) } }
|
||||
var node by remember {
|
||||
mutableStateOf(nodes.find { it.num == msg.node.num } ?: msg.node)
|
||||
val node by remember {
|
||||
derivedStateOf { nodes.find { it.num == msg.node.num } ?: msg.node }
|
||||
}
|
||||
|
||||
MessageItem(
|
||||
modifier = Modifier.animateItem(),
|
||||
node = node,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package com.geeksville.mesh.ui.message.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
@@ -33,7 +32,6 @@ 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
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
@@ -48,7 +46,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.geeksville.mesh.DataPacket
|
||||
import com.geeksville.mesh.MessageStatus
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.database.entity.Reaction
|
||||
@@ -61,10 +58,8 @@ import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider
|
||||
import com.geeksville.mesh.ui.common.theme.AppTheme
|
||||
import com.geeksville.mesh.ui.node.components.NodeChip
|
||||
import com.geeksville.mesh.ui.node.components.NodeMenuAction
|
||||
import kotlin.uuid.ExperimentalUuidApi
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
internal fun MessageItem(
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -87,9 +82,8 @@ internal fun MessageItem(
|
||||
.fillMaxWidth()
|
||||
.background(color = if (selected) Color.Gray else MaterialTheme.colorScheme.background),
|
||||
) {
|
||||
val fromLocal = node.user.id == DataPacket.ID_LOCAL
|
||||
val containerColor = Color(
|
||||
if (fromLocal) {
|
||||
if (message.fromLocal) {
|
||||
ourNode.colors.second
|
||||
} else {
|
||||
node.colors.second
|
||||
@@ -103,11 +97,11 @@ internal fun MessageItem(
|
||||
Box {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.align(if (fromLocal) Alignment.BottomEnd else Alignment.BottomStart)
|
||||
.align(if (message.fromLocal) Alignment.BottomEnd else Alignment.BottomStart)
|
||||
.padding(
|
||||
top = 4.dp,
|
||||
start = if (!fromLocal) 0.dp else 16.dp,
|
||||
end = if (fromLocal) 0.dp else 16.dp,
|
||||
start = if (!message.fromLocal) 0.dp else 16.dp,
|
||||
end = if (message.fromLocal) 0.dp else 16.dp,
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
@@ -134,70 +128,76 @@ internal fun MessageItem(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
NodeChip(
|
||||
node = if (fromLocal) ourNode else node,
|
||||
node = if (message.fromLocal) ourNode else node,
|
||||
onAction = onAction,
|
||||
isConnected = isConnected,
|
||||
isThisNode = fromLocal,
|
||||
isThisNode = message.fromLocal,
|
||||
)
|
||||
Text(
|
||||
text = with(if (fromLocal) ourNode.user else node.user) { "$longName ($id)" },
|
||||
text = with(if (message.fromLocal) ourNode.user else node.user) { "$longName ($id)" },
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
modifier = Modifier.weight(1f, fill = true)
|
||||
)
|
||||
MessageActions(
|
||||
isLocal = fromLocal,
|
||||
isLocal = message.fromLocal,
|
||||
status = message.status,
|
||||
onSendReaction = sendReaction,
|
||||
onSendReply = onReply,
|
||||
onStatusClick = onStatusClick,
|
||||
)
|
||||
}
|
||||
AutoLinkText(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
text = message.text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = cardColors.contentColor
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
) {
|
||||
if (!fromLocal) {
|
||||
if (message.hopsAway == 0) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Snr(
|
||||
message.snr,
|
||||
fontSize = MaterialTheme.typography.labelSmall.fontSize
|
||||
)
|
||||
Rssi(
|
||||
message.rssi,
|
||||
fontSize = MaterialTheme.typography.labelSmall.fontSize
|
||||
AutoLinkText(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
text = message.text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = cardColors.contentColor
|
||||
)
|
||||
|
||||
val topPadding = if (!message.fromLocal) 2.dp else 0.dp
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = topPadding, bottom = 4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (!message.fromLocal) {
|
||||
if (message.hopsAway == 0) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Snr(
|
||||
message.snr,
|
||||
fontSize = MaterialTheme.typography.labelSmall.fontSize
|
||||
)
|
||||
Rssi(
|
||||
message.rssi,
|
||||
fontSize = MaterialTheme.typography.labelSmall.fontSize
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = stringResource(
|
||||
R.string.hops_away_template,
|
||||
message.hopsAway
|
||||
),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = stringResource(
|
||||
R.string.hops_away_template,
|
||||
message.hopsAway
|
||||
),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = message.time,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Text(
|
||||
text = message.time,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,13 +219,12 @@ private fun OriginalMessageSnippet(
|
||||
onNavigateToOriginalMessage: (Int) -> Unit
|
||||
) {
|
||||
message.originalMessage?.let { originalMessage ->
|
||||
val originalMessageIsFromLocal =
|
||||
originalMessage.node.user.id == DataPacket.ID_LOCAL
|
||||
val originalMessageNode =
|
||||
if (originalMessageIsFromLocal) ourNode else originalMessage.node
|
||||
if (originalMessage.fromLocal) ourNode else originalMessage.node
|
||||
OutlinedCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(4.dp)
|
||||
.clickable { onNavigateToOriginalMessage(originalMessage.packetId) },
|
||||
colors = cardColors,
|
||||
) {
|
||||
@@ -239,7 +238,7 @@ private fun OriginalMessageSnippet(
|
||||
contentDescription = stringResource(R.string.reply), // Add to strings.xml
|
||||
)
|
||||
Text(
|
||||
text = "${originalMessageNode.user.shortName}",
|
||||
text = originalMessageNode.user.shortName,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
@@ -257,56 +256,98 @@ private fun OriginalMessageSnippet(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalUuidApi::class)
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun MessageItemPreview() {
|
||||
val message = Message(
|
||||
val sent = Message(
|
||||
text = stringResource(R.string.sample_message),
|
||||
time = "10:00",
|
||||
fromLocal = true,
|
||||
status = MessageStatus.DELIVERED,
|
||||
snr = 20.5f,
|
||||
rssi = 90,
|
||||
hopsAway = 0,
|
||||
uuid = 1L,
|
||||
receivedTime = System.currentTimeMillis(),
|
||||
node = NodePreviewParameterProvider().values.first(),
|
||||
node = NodePreviewParameterProvider().mickeyMouse,
|
||||
read = false,
|
||||
routingError = 0,
|
||||
packetId = 4545,
|
||||
emojis = listOf(),
|
||||
replyId = null,
|
||||
)
|
||||
val received = Message(
|
||||
text = "This is a received message",
|
||||
time = "10:10",
|
||||
fromLocal = false,
|
||||
status = MessageStatus.RECEIVED,
|
||||
snr = 2.5f,
|
||||
rssi = 90,
|
||||
hopsAway = 0,
|
||||
uuid = 2L,
|
||||
receivedTime = System.currentTimeMillis(),
|
||||
node = NodePreviewParameterProvider().minnieMouse,
|
||||
read = false,
|
||||
routingError = 0,
|
||||
packetId = 4545,
|
||||
emojis = listOf(),
|
||||
replyId = null,
|
||||
)
|
||||
val receivedWithOriginalMessage = Message(
|
||||
text = "This is a received message w/ original, this is a longer message to test next-lining.",
|
||||
time = "10:20",
|
||||
fromLocal = false,
|
||||
status = MessageStatus.RECEIVED,
|
||||
snr = 2.5f,
|
||||
rssi = 90,
|
||||
hopsAway = 2,
|
||||
uuid = 2L,
|
||||
receivedTime = System.currentTimeMillis(),
|
||||
node = NodePreviewParameterProvider().minnieMouse,
|
||||
read = false,
|
||||
routingError = 0,
|
||||
packetId = 4545,
|
||||
emojis = listOf(),
|
||||
replyId = null,
|
||||
originalMessage = received,
|
||||
)
|
||||
AppTheme {
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(vertical = 16.dp),
|
||||
) {
|
||||
MessageItem(
|
||||
message = message,
|
||||
node = message.node,
|
||||
message = sent,
|
||||
node = sent.node,
|
||||
selected = false,
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
onStatusClick = {},
|
||||
isConnected = true,
|
||||
ourNode = message.node,
|
||||
ourNode = sent.node,
|
||||
)
|
||||
|
||||
MessageItem(
|
||||
message = message.let { message ->
|
||||
val originalMessage = message.copy(
|
||||
replyId = message.packetId,
|
||||
node = NodePreviewParameterProvider().values.last(),
|
||||
text = "This is a reply to the original message."
|
||||
)
|
||||
message.copy(originalMessage = originalMessage)
|
||||
},
|
||||
node = message.node,
|
||||
message = received,
|
||||
node = received.node,
|
||||
selected = false,
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
onStatusClick = {},
|
||||
isConnected = true,
|
||||
ourNode = message.node,
|
||||
onNavigateToOriginalMessage = {}
|
||||
ourNode = sent.node,
|
||||
)
|
||||
|
||||
MessageItem(
|
||||
message = receivedWithOriginalMessage,
|
||||
node = receivedWithOriginalMessage.node,
|
||||
selected = false,
|
||||
onClick = {},
|
||||
onLongClick = {},
|
||||
onStatusClick = {},
|
||||
isConnected = true,
|
||||
ourNode = sent.node,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ complexity:
|
||||
LongMethod:
|
||||
active: true
|
||||
threshold: 60
|
||||
ignoreAnnotated: [ 'Preview', 'PreviewLightDark', 'PreviewScreenSizes' ]
|
||||
LongParameterList:
|
||||
active: true
|
||||
functionThreshold: 12
|
||||
|
||||
Reference in New Issue
Block a user