diff --git a/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt b/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt new file mode 100644 index 000000000..a87243500 --- /dev/null +++ b/app/src/androidTest/java/com/geeksville/mesh/compose/MessageItemTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.compose + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.geeksville.mesh.MessageStatus +import com.geeksville.mesh.R +import com.geeksville.mesh.model.Message +import com.geeksville.mesh.model.Node +import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider +import com.geeksville.mesh.ui.message.components.MessageItem +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MessageItemTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun mqttIconIsDisplayedWhenViaMqttIsTrue() { + val testNode = NodePreviewParameterProvider().minnieMouse + val messageWithMqtt = Message( + text = "Test message via MQTT", + time = "10:00", + fromLocal = false, + status = MessageStatus.RECEIVED, + snr = 2.5f, + rssi = 90, + hopsAway = 0, + uuid = 1L, + receivedTime = System.currentTimeMillis(), + node = testNode, + read = false, + routingError = 0, + packetId = 1234, + emojis = listOf(), + replyId = null, + viaMqtt = true + ) + + composeTestRule.setContent { + MessageItem( + message = messageWithMqtt, + node = testNode, + selected = false, + onClick = {}, + onLongClick = {}, + onStatusClick = {}, + isConnected = true, + ourNode = testNode, + ) + } + + // Check that the MQTT icon is displayed + composeTestRule.onNodeWithContentDescription("via MQTT").assertIsDisplayed() + } + + @Test + fun mqttIconIsNotDisplayedWhenViaMqttIsFalse() { + val testNode = NodePreviewParameterProvider().minnieMouse + val messageWithoutMqtt = Message( + text = "Test message not via MQTT", + time = "10:00", + fromLocal = false, + status = MessageStatus.RECEIVED, + snr = 2.5f, + rssi = 90, + hopsAway = 0, + uuid = 1L, + receivedTime = System.currentTimeMillis(), + node = testNode, + read = false, + routingError = 0, + packetId = 1234, + emojis = listOf(), + replyId = null, + viaMqtt = false + ) + + composeTestRule.setContent { + MessageItem( + message = messageWithoutMqtt, + node = testNode, + selected = false, + onClick = {}, + onLongClick = {}, + onStatusClick = {}, + isConnected = true, + ourNode = testNode, + ) + } + + // Check that the MQTT icon is not displayed + composeTestRule.onNodeWithContentDescription("via MQTT").assertDoesNotExist() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt b/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt index 1a9d67254..d1a9e0589 100644 --- a/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt +++ b/app/src/main/java/com/geeksville/mesh/database/entity/Packet.kt @@ -51,7 +51,8 @@ data class PacketEntity( routingError = routingError, packetId = packetId, emojis = reactions.toReaction(getNode), - replyId = data.replyId + replyId = data.replyId, + viaMqtt = node.viaMqtt ) } } diff --git a/app/src/main/java/com/geeksville/mesh/model/Message.kt b/app/src/main/java/com/geeksville/mesh/model/Message.kt index 983215f82..c3a16178a 100644 --- a/app/src/main/java/com/geeksville/mesh/model/Message.kt +++ b/app/src/main/java/com/geeksville/mesh/model/Message.kt @@ -62,6 +62,7 @@ data class Message( val hopsAway: Int, val replyId: Int?, val originalMessage: Message? = null, + val viaMqtt: Boolean = false, ) { fun getStatusStringRes(): Pair { val title = if (routingError > 0) R.string.error else R.string.message_delivery_status 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 7363210a6..d97091473 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 @@ -27,7 +27,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Cloud import androidx.compose.material.icons.filled.FormatQuote import androidx.compose.material3.Card import androidx.compose.material3.CardColors @@ -140,6 +142,13 @@ internal fun MessageItem( style = MaterialTheme.typography.labelMedium, modifier = Modifier.weight(1f, fill = true) ) + if (message.viaMqtt) { + Icon( + Icons.Default.Cloud, + contentDescription = stringResource(R.string.via_mqtt), + modifier = Modifier.size(16.dp) + ) + } MessageActions( isLocal = message.fromLocal, status = message.status, @@ -275,6 +284,7 @@ private fun MessageItemPreview() { packetId = 4545, emojis = listOf(), replyId = null, + viaMqtt = false, ) val received = Message( text = "This is a received message", @@ -292,6 +302,7 @@ private fun MessageItemPreview() { packetId = 4545, emojis = listOf(), replyId = null, + viaMqtt = false, ) val receivedWithOriginalMessage = Message( text = "This is a received message w/ original, this is a longer message to test next-lining.", @@ -310,6 +321,7 @@ private fun MessageItemPreview() { emojis = listOf(), replyId = null, originalMessage = received, + viaMqtt = true, ) AppTheme { Column( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e0ac6796f..3f1d403b6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ Hops away Last heard via MQTT + via MQTT via Favorite Unrecognized