feat: Add SFPP confirmed status to Messages and Reactions (#4139)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
Co-authored-by: Mac DeCourcy <github.znq26@slmail.me>
This commit is contained in:
James Rich 2026-01-08 07:21:21 -06:00 committed by GitHub
parent 78bd1ad6dd
commit 782c068ead
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 2699 additions and 61 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Meshtastic LLC
* Copyright (c) 2025-2026 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
@ -14,7 +14,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.feature.messaging
import android.os.RemoteException
@ -172,7 +171,10 @@ constructor(
}
}
}
val p = DataPacket(dest, channel ?: 0, str, replyId)
val p =
DataPacket(dest, channel ?: 0, str, replyId).apply {
from = ourNodeInfo.value?.user?.id ?: DataPacket.ID_LOCAL
}
sendDataPacket(p)
}

View file

@ -23,11 +23,13 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Reply
import androidx.compose.material.icons.filled.EmojiEmotions
import androidx.compose.material.icons.twotone.AddLink
import androidx.compose.material.icons.twotone.Cloud
import androidx.compose.material.icons.twotone.CloudDone
import androidx.compose.material.icons.twotone.CloudOff
import androidx.compose.material.icons.twotone.CloudUpload
import androidx.compose.material.icons.twotone.HowToReg
import androidx.compose.material.icons.twotone.Link
import androidx.compose.material.icons.twotone.Warning
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
@ -82,6 +84,8 @@ internal fun MessageStatusButton(onStatusClick: () -> Unit = {}, status: Message
MessageStatus.RECEIVED -> Icons.TwoTone.HowToReg
MessageStatus.QUEUED -> Icons.TwoTone.CloudUpload
MessageStatus.DELIVERED -> Icons.TwoTone.CloudDone
MessageStatus.SFPP_ROUTING -> Icons.TwoTone.AddLink
MessageStatus.SFPP_CONFIRMED -> Icons.TwoTone.Link
MessageStatus.ENROUTE -> Icons.TwoTone.Cloud
MessageStatus.ERROR -> Icons.TwoTone.CloudOff
else -> Icons.TwoTone.Warning

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Meshtastic LLC
* Copyright (c) 2025-2026 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
@ -14,7 +14,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.feature.messaging.component
import androidx.compose.foundation.background
@ -204,6 +203,7 @@ internal fun MessageItem(
ReactionRow(
modifier = Modifier.fillMaxWidth(),
reactions = emojis,
myId = ourNode.user.id,
onSendReaction = sendReaction,
onShowReactions = onShowReactions,
)

View file

@ -114,6 +114,7 @@ private fun ReactionItem(
internal fun ReactionRow(
modifier: Modifier = Modifier,
reactions: List<Reaction> = emptyList(),
myId: String? = null,
onSendReaction: (String) -> Unit = {},
onShowReactions: () -> Unit = {},
) {
@ -126,7 +127,7 @@ internal fun ReactionRow(
verticalAlignment = Alignment.CenterVertically,
) {
items(emojiGroups.entries.toList()) { (emoji, reactions) ->
val localReaction = reactions.find { it.user.id == DataPacket.ID_LOCAL }
val localReaction = reactions.find { it.user.id == DataPacket.ID_LOCAL || it.user.id == myId }
ReactionItem(
emoji = emoji,
emojiCount = reactions.size,
@ -187,7 +188,7 @@ internal fun ReactionDialog(
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
items(groupedEmojis.entries.toList()) { (emoji, reactions) ->
val localReaction = reactions.find { it.user.id == DataPacket.ID_LOCAL }
val localReaction = reactions.find { it.user.id == DataPacket.ID_LOCAL || it.user.id == myId }
val isSending =
localReaction?.status == MessageStatus.QUEUED || localReaction?.status == MessageStatus.ENROUTE
Text(