fix: Fetch original message when displaying a reply (#2152)

This commit is contained in:
James Rich 2025-06-18 16:05:02 +00:00 committed by GitHub
parent 0799122c9e
commit 468c4ab6b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 40 additions and 12 deletions

View file

@ -24,8 +24,10 @@ import com.geeksville.mesh.database.dao.PacketDao
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.ReactionEntity
import com.geeksville.mesh.model.Node
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import javax.inject.Inject
@ -58,7 +60,19 @@ class PacketRepository @Inject constructor(private val packetDaoLazy: dagger.Laz
packetDao.insert(packet)
}
fun getMessagesFrom(contact: String) = packetDao.getMessagesFrom(contact)
suspend fun getMessagesFrom(contact: String, getNode: suspend (String?) -> Node) =
withContext(Dispatchers.IO) {
packetDao.getMessagesFrom(contact).mapLatest { packets ->
packets.map { packet ->
val message = packet.toMessage(getNode)
message.replyId.takeIf { it != null && it != 0 }
?.let { getPacketByPacketId(it) }
?.toMessage(getNode)
?.let { originalMessage -> message.copy(originalMessage = originalMessage) }
?: message
}
}
}
suspend fun updateMessageStatus(d: DataPacket, m: MessageStatus) = withContext(Dispatchers.IO) {
packetDao.updateMessageStatus(d, m)
@ -72,6 +86,10 @@ class PacketRepository @Inject constructor(private val packetDaoLazy: dagger.Laz
packetDao.getPacketById(requestId)
}
suspend fun getPacketByPacketId(packetId: Int) = withContext(Dispatchers.IO) {
packetDao.getPacketByPacketId(packetId)
}
suspend fun deleteMessages(uuidList: List<Long>) = withContext(Dispatchers.IO) {
for (chunk in uuidList.chunked(500)) { // limit number of UUIDs per query
packetDao.deleteMessages(chunk)

View file

@ -19,15 +19,15 @@ package com.geeksville.mesh.database.dao
import androidx.room.Dao
import androidx.room.MapColumn
import androidx.room.Update
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import androidx.room.Upsert
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MessageStatus
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.PacketEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.PacketEntity
import com.geeksville.mesh.database.entity.ReactionEntity
import kotlinx.coroutines.flow.Flow
@ -174,6 +174,9 @@ interface PacketDao {
)
suspend fun getPacketById(requestId: Int): Packet?
@Query("SELECT * FROM packet WHERE packet_id = :packetId LIMIT 1")
suspend fun getPacketByPacketId(packetId: Int): PacketEntity?
@Transaction
suspend fun getQueuedPackets(): List<DataPacket>? =
getDataPackets().filter { it.status == MessageStatus.QUEUED }

View file

@ -60,6 +60,7 @@ data class Message(
val rssi: Int,
val hopsAway: Int,
val replyId: Int?,
val originalMessage: Message? = null,
) {
fun getStatusStringRes(): Pair<Int, Int> {
val title = if (routingError > 0) R.string.error else R.string.message_delivery_status

View file

@ -517,8 +517,20 @@ class UIViewModel @Inject constructor(
initialValue = emptyList(),
)
fun getMessagesFrom(contactKey: String) = packetRepository.getMessagesFrom(contactKey)
.mapLatest { list -> list.map { it.toMessage(::getNode) } }
fun getMessagesFrom(contactKey: String): StateFlow<List<Message>> {
_contactKeyForMessages.value = contactKey
return messagesForContactKey
}
private val _contactKeyForMessages: MutableStateFlow<String?> = MutableStateFlow(null)
private val messagesForContactKey: StateFlow<List<Message>> =
_contactKeyForMessages.filterNotNull().flatMapLatest { contactKey ->
packetRepository.getMessagesFrom(contactKey, ::getNode)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)
val waypoints = packetRepository.getWaypoints().mapLatest { list ->
list.associateBy { packet -> packet.data.waypoint!!.id }

View file

@ -171,10 +171,6 @@ internal fun MessageList(
var node by remember {
mutableStateOf(nodes.find { it.num == msg.node.num } ?: msg.node)
}
val originalMessage = messages.find { it.packetId == msg.replyId }
LaunchedEffect(nodes, messages) {
node = nodes.find { it.num == msg.node.num } ?: msg.node
}
MessageItem(
node = node,
ourNode = ourNode!!,
@ -192,7 +188,6 @@ internal fun MessageList(
sendReaction = { onSendReaction(it, msg.packetId) },
onShowReactions = { showReactionDialog = msg.emojis },
isConnected = isConnected,
originalMessage = originalMessage,
onNavigateToOriginalMessage = {
coroutineScope.launch {
listState.animateScrollToItem(

View file

@ -89,7 +89,6 @@ internal fun MessageItem(
onAction: (NodeMenuAction) -> Unit = {},
onStatusClick: () -> Unit = {},
isConnected: Boolean,
originalMessage: Message? = null,
onNavigateToOriginalMessage: (Int) -> Unit = {},
) = Column(
modifier = modifier
@ -124,7 +123,7 @@ internal fun MessageItem(
modifier = Modifier
.fillMaxWidth(),
) {
if (originalMessage != null) {
message.originalMessage?.let { originalMessage ->
val originalMessageIsFromLocal = originalMessage.node.user.id == DataPacket.ID_LOCAL
val originalMessageNode =
if (originalMessageIsFromLocal) ourNode else originalMessage.node