fix(messaging): use stored contact_key to avoid duplicate LazyColumn key crash (#6131) (#6142)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
James Rich
2026-07-07 19:42:22 -05:00
committed by GitHub
parent 492d4dc08c
commit 93b24572c8
3 changed files with 8 additions and 12 deletions

View File

@@ -61,7 +61,7 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
.flatMapLatest { db -> db.packetDao().getContactKeys() }
.map { map -> map.mapValues { it.value.data } }
override fun getContactsPaged(): Flow<PagingData<DataPacket>> = Pager(
override fun getContactsPaged(): Flow<PagingData<Pair<String, DataPacket>>> = Pager(
config =
PagingConfig(
pageSize = CONTACTS_PAGE_SIZE,
@@ -71,7 +71,7 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
pagingSourceFactory = { dbManager.currentDb.value.packetDao().getContactKeysPaged() },
)
.flow
.map { pagingData -> pagingData.map { it.data } }
.map { pagingData -> pagingData.map { it.contact_key to it.data } }
override suspend fun getMessageCount(contact: String): Int =
withContext(dispatchers.io) { dbManager.currentDb.value.packetDao().getMessageCount(contact) }

View File

@@ -40,8 +40,8 @@ interface PacketRepository {
/** Reactive flow of all conversation contacts, keyed by their contact identifier. */
fun getContacts(): Flow<Map<String, DataPacket>>
/** Reactive paged flow of conversation contacts. */
fun getContactsPaged(): Flow<PagingData<DataPacket>>
/** Reactive paged flow of conversation contacts, each paired with its stored contact key. */
fun getContactsPaged(): Flow<PagingData<Pair<String, DataPacket>>>
/** Returns the total number of messages in a conversation. */
suspend fun getMessageCount(contact: String): Int

View File

@@ -142,17 +142,13 @@ class ContactsViewModel(
val myNodeNum = params.myNodeNum
packetRepository.getContactsPaged().map { pagingData ->
pagingData.map { packetData: DataPacket ->
// Determine if this is my message (originated on this device)
pagingData.map { (contactKey, packetData) ->
// Use the stored contact_key as the identity. Recomputing it here from a
// possibly-null myNodeNum collapses distinct conversations onto one key and
// crashes the LazyColumn with a duplicate-key error (#6131).
val fromLocal = packetData.isFromLocal(myNodeNum)
val toBroadcast = packetData.isBroadcast
// Reconstruct contactKey exactly as rememberDataPacket() computes it:
// For outgoing or broadcast: use the "to" field (recipient / ^all)
// For incoming DMs: use the "from" field (the other party)
val contactId = if (fromLocal || toBroadcast) packetData.to else packetData.from
val contactKey = "${packetData.channel}$contactId"
// grab usernames from NodeInfo
val userId = if (fromLocal) packetData.to else packetData.from
val user = nodeRepository.getUser(userId ?: NodeAddress.ID_BROADCAST)