From e715a74bc429ef787f77d5d9e6bb4744719ff0af Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 1 Aug 2025 08:30:44 -0400 Subject: [PATCH] Better indexes notes in channels and chatrooms --- .../com/vitorpamplona/amethyst/model/Note.kt | 3 + .../amethyst/model/privateChats/Chatroom.kt | 11 +- .../loggedIn/DecryptAndIndexProcessor.kt | 100 ++++++------------ 3 files changed, 43 insertions(+), 71 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 90de133f3b..7e420a4e82 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.model.nip47WalletConnect.NwcSignerState import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState +import com.vitorpamplona.amethyst.model.privateChats.Chatroom import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.service.firstFullCharOrEmoji import com.vitorpamplona.amethyst.service.replace @@ -130,6 +131,8 @@ open class Note( var event: Event? = null var author: User? = null var replyTo: List? = null + var inChannel: Channel? = null + var inChatroom: Chatroom? = null // These fields are updated every time an event related to this note is received. var replies = listOf() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/Chatroom.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/Chatroom.kt index f7bfb7df22..d562e8ce7f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/Chatroom.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/privateChats/Chatroom.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.model.privateChats import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent @@ -41,7 +40,7 @@ class Chatroom { var lastMessage: Note? = null @Synchronized - fun addMessageSync(msg: Note) { + fun addMessageSync(msg: Note): Boolean { if (msg !in messages) { messages = messages + msg @@ -62,13 +61,13 @@ class Chatroom { subject.tryEmit(newSubject) subjectCreatedAt = msg.createdAt() } + return true } + return false } @Synchronized - fun removeMessageSync(msg: Note) { - checkNotInMainThread() - + fun removeMessageSync(msg: Note): Boolean { if (msg in messages) { messages = messages - msg @@ -80,7 +79,9 @@ class Chatroom { subject.tryEmit(it.event?.subject()) subjectCreatedAt = it.createdAt() } + return true } + return false } fun senderIntersects(keySet: Set): Boolean = activeSenders.any { it.pubkeyHex in keySet } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt index 13f513dd29..b12107f36c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt @@ -29,7 +29,6 @@ import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent -import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent import com.vitorpamplona.quartz.nip17Dm.messages.ChatMessageEvent import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent @@ -92,10 +91,9 @@ class DecryptAndIndexProcessor( // Avoid decrypting over and over again if the event already exist. if (event.pubKey == account.signer.pubKey) { if (!event.isDeleted()) { - if (account.draftsDecryptionCache.preCachedDraft(event) == null) { - account.draftsDecryptionCache.cachedDraft(event)?.let { rumor -> - indexDraftAsRealEvent(eventNote, rumor) - } + val rumor = account.draftsDecryptionCache.preCachedDraft(event) ?: account.draftsDecryptionCache.cachedDraft(event) + if (rumor != null) { + indexDraftAsRealEvent(eventNote, rumor) } } } @@ -200,14 +198,7 @@ class DecryptAndIndexProcessor( is DraftEvent -> { // Avoid decrypting over and over again if the event already exist. if (event.pubKey == account.signer.pubKey) { - if (!event.isDeleted()) { - if (account.draftsDecryptionCache.preCachedDraft(event) == null) { - account.draftsDecryptionCache.cachedDraft(event)?.let { - deindexDraftAsRealEvent(eventNote, it) - } - account.draftsDecryptionCache.delete(event) - } - } + deindexDraftAsRealEvent(eventNote) } } @@ -257,90 +248,67 @@ class DecryptAndIndexProcessor( draftEventWrap: Note, rumor: Event, ) { + draftEventWrap.replyTo = cache.computeReplyTo(rumor) + draftEventWrap.replyTo?.forEach { it.addReply(draftEventWrap) } + when (rumor) { is PrivateDmEvent -> { if (rumor.canDecrypt(account.signer)) { val talkingWith = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.addMessage(talkingWith, draftEventWrap) + val chatroom = account.chatroomList.getOrCreatePrivateChatroom(talkingWith) + if (chatroom.addMessageSync(draftEventWrap)) { + draftEventWrap.inChatroom = chatroom + } } } is ChatMessageEvent -> { if (rumor.isIncluded(account.signer.pubKey)) { val key = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.addMessage(key, draftEventWrap) + val chatroom = account.chatroomList.getOrCreatePrivateChatroom(key) + if (chatroom.addMessageSync(draftEventWrap)) { + draftEventWrap.inChatroom = chatroom + } } } is ChatMessageEncryptedFileHeaderEvent -> { if (rumor.isIncluded(account.signer.pubKey)) { val key = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.addMessage(key, draftEventWrap) + val chatroom = account.chatroomList.getOrCreatePrivateChatroom(key) + if (chatroom.addMessageSync(draftEventWrap)) { + draftEventWrap.inChatroom = chatroom + } } } is EphemeralChatEvent -> { rumor.roomId()?.let { - cache.getOrCreateEphemeralChannel(it).addNote(draftEventWrap, null) + val channel = cache.getOrCreateEphemeralChannel(it) + channel.addNote(draftEventWrap, null) + draftEventWrap.inChannel = channel } } is ChannelMessageEvent -> { rumor.channelId()?.let { channelId -> - cache.checkGetOrCreatePublicChatChannel(channelId)?.addNote(draftEventWrap, null) + val channel = cache.checkGetOrCreatePublicChatChannel(channelId) + channel?.addNote(draftEventWrap, null) + draftEventWrap.inChannel = channel } } is LiveActivitiesChatMessageEvent -> { rumor.activityAddress()?.let { channelId -> - cache.getOrCreateLiveChannel(channelId).addNote(draftEventWrap, null) + val channel = cache.getOrCreateLiveChannel(channelId) + channel.addNote(draftEventWrap, null) + draftEventWrap.inChannel = channel } } - is TextNoteEvent -> { - val replyTo = cache.computeReplyTo(rumor) - replyTo.forEach { it.addReply(draftEventWrap) } - } } } - fun deindexDraftAsRealEvent( - draftEventWrap: Note, - rumor: Event, - ) { - when (rumor) { - is PrivateDmEvent -> { - if (rumor.canDecrypt(account.signer.pubKey)) { - val talkingWith = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.addMessage(talkingWith, draftEventWrap) - } - } - is ChatMessageEvent -> { - if (rumor.isIncluded(account.signer.pubKey)) { - val key = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.removeMessage(key, draftEventWrap) - } - } - is ChatMessageEncryptedFileHeaderEvent -> { - if (rumor.isIncluded(account.signer.pubKey)) { - val key = rumor.chatroomKey(account.signer.pubKey) - account.chatroomList.removeMessage(key, draftEventWrap) - } - } - is ChannelMessageEvent -> { - rumor.channelId()?.let { channelId -> - cache.getPublicChatChannelIfExists(channelId)?.removeNote(draftEventWrap) - } - } - is EphemeralChatEvent -> { - rumor.roomId()?.let { - cache.getEphemeralChatChannelIfExists(it)?.removeNote(draftEventWrap) - } - } - is LiveActivitiesChatMessageEvent -> { - rumor.activityAddress()?.let { channelId -> - cache.getLiveActivityChannelIfExists(channelId)?.removeNote(draftEventWrap) - } - } - is TextNoteEvent -> { - val replyTo = cache.computeReplyTo(rumor) - replyTo.forEach { it.removeReply(draftEventWrap) } - } - } + fun deindexDraftAsRealEvent(draftEventWrap: Note) { + draftEventWrap.replyTo?.forEach { it.removeReply(draftEventWrap) } + draftEventWrap.replyTo = null + + draftEventWrap.inChatroom?.removeMessageSync(draftEventWrap) + draftEventWrap.inChannel?.removeNote(draftEventWrap) } suspend fun runNew(newNotes: Set) {