Moving chatroomlist to an additive filter

This commit is contained in:
Vitor Pamplona 2023-05-29 14:25:34 -04:00
parent 02ad85a740
commit a5a3c62edd
3 changed files with 129 additions and 8 deletions

View File

@ -1,9 +1,16 @@
package com.vitorpamplona.amethyst.ui.dal
import android.util.Log
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
import com.vitorpamplona.amethyst.ui.actions.updated
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue
object ChatroomListKnownFeedFilter : FeedFilter<Note>() {
object ChatroomListKnownFeedFilter : AdditiveFeedFilter<Note>() {
lateinit var account: Account
// returns the last Note of each user.
@ -35,4 +42,120 @@ object ChatroomListKnownFeedFilter : FeedFilter<Note>() {
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
.reversed()
}
@OptIn(ExperimentalTime::class)
override fun updateListWith(oldList: List<Note>, newItems: Set<Note>): List<Note> {
val (feed, elapsed) = measureTimedValue {
val me = account.userProfile()
// Gets the latest message by channel from the new items.
val newRelevantPublicMessages = filterRelevantPublicMessages(newItems, account)
// Gets the latest message by room from the new items.
val newRelevantPrivateMessages = filterRelevantPrivateMessages(newItems, account)
if (newRelevantPrivateMessages.isEmpty() && newRelevantPublicMessages.isEmpty()) {
return oldList
}
var myNewList = oldList
newRelevantPublicMessages.forEach { newNotePair ->
oldList.forEach { oldNote ->
if (
(newNotePair.key == oldNote.channelHex()) && (newNotePair.value.createdAt() ?: 0) > (oldNote.createdAt() ?: 0)
) {
myNewList = myNewList.updated(oldNote, newNotePair.value)
}
}
}
newRelevantPrivateMessages.forEach { newNotePair ->
oldList.forEach { oldNote ->
val oldAuthor = oldNote.author?.pubkeyHex
val oldRecipient = (oldNote.event as? PrivateDmEvent)?.verifiedRecipientPubKey()
val oldRoom = if (oldAuthor == me.pubkeyHex) oldRecipient else oldAuthor
if (
(newNotePair.key == oldRoom) && (newNotePair.value.createdAt() ?: 0) > (oldNote.createdAt() ?: 0)
) {
myNewList = myNewList.updated(oldNote, newNotePair.value)
}
}
}
myNewList
}
Log.d("Time", "${this.javaClass.simpleName} Modified Additive Feed in $elapsed with ${feed.size} objects")
return feed
}
override fun applyFilter(newItems: Set<Note>): Set<Note> {
// Gets the latest message by channel from the new items.
val newRelevantPublicMessages = filterRelevantPublicMessages(newItems, account)
// Gets the latest message by room from the new items.
val newRelevantPrivateMessages = filterRelevantPrivateMessages(newItems, account)
return if (newRelevantPrivateMessages.isEmpty() && newRelevantPublicMessages.isEmpty()) {
emptySet()
} else {
(newRelevantPrivateMessages.values + newRelevantPublicMessages.values).toSet()
}
}
private fun filterRelevantPublicMessages(newItems: Set<Note>, account: Account): MutableMap<String, Note> {
val followingChannels = account.followingChannels
val newRelevantPublicMessages = mutableMapOf<String, Note>()
newItems.filter { it.event is ChannelMessageEvent }.forEach { newNote ->
newNote.channelHex()?.let { channelHex ->
if (channelHex in followingChannels && account.isAcceptable(newNote)) {
val lastNote = newRelevantPublicMessages.get(channelHex)
if (lastNote != null) {
if ((newNote.createdAt() ?: 0) > (lastNote.createdAt() ?: 0)) {
newRelevantPublicMessages.put(channelHex, newNote)
}
} else {
newRelevantPublicMessages.put(channelHex, newNote)
}
}
}
}
return newRelevantPublicMessages
}
private fun filterRelevantPrivateMessages(newItems: Set<Note>, account: Account): MutableMap<String, Note> {
val me = account.userProfile()
val followingKeySet = account.followingKeySet()
val newRelevantPrivateMessages = mutableMapOf<String, Note>()
newItems.filter { it.event is PrivateDmEvent }.forEach { newNote ->
val newAuthor = newNote.author?.pubkeyHex
val newRecipient = (newNote.event as? PrivateDmEvent)?.verifiedRecipientPubKey()
val roomUserHex = if (newAuthor == me.pubkeyHex) newRecipient else newAuthor
val roomUser = roomUserHex?.let { LocalCache.users[it] }
if (roomUserHex != null && (newAuthor == me.pubkeyHex || roomUserHex in followingKeySet || me.hasSentMessagesTo(roomUser)) && !account.isHidden(roomUserHex) ) {
val lastNote = newRelevantPrivateMessages.get(roomUserHex)
if (lastNote != null) {
if ((newNote.createdAt() ?: 0) > (lastNote.createdAt() ?: 0)) {
newRelevantPrivateMessages.put(roomUserHex, newNote)
}
} else {
newRelevantPrivateMessages.put(roomUserHex, newNote)
}
}
}
return newRelevantPrivateMessages
}
override fun sort(collection: Set<Note>): List<Note> {
return collection
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
.reversed()
}
}

View File

@ -23,7 +23,7 @@ abstract class AdditiveFeedFilter<T> : FeedFilter<T>() {
abstract fun sort(collection: Set<T>): List<T>
@OptIn(ExperimentalTime::class)
fun updateListWith(oldList: List<T>, newItems: Set<T>): List<T> {
open fun updateListWith(oldList: List<T>, newItems: Set<T>): List<T> {
val (feed, elapsed) = measureTimedValue {
val newItemsToBeAdded = applyFilter(newItems)
if (newItemsToBeAdded.isNotEmpty()) {

View File

@ -170,7 +170,7 @@ object NotificationLatestItem : LatestItem() {
}
}
object MessagesLatestItem {
object MessagesLatestItem : LatestItem() {
fun hasNewItems(
account: Account,
cache: NotificationCache,
@ -178,13 +178,11 @@ object MessagesLatestItem {
): Boolean {
ChatroomListKnownFeedFilter.account = account
val note = ChatroomListKnownFeedFilter.loadTop().firstOrNull {
it.createdAt() != null && it.channel() == null && it.author != account.userProfile()
} ?: return false
val newestItem = updateNewestItem(newNotes, account, ChatroomListKnownFeedFilter)
val lastTime = cache.load("Room/${note.author?.pubkeyHex}")
val lastTime = cache.load("Room/${newestItem?.author?.pubkeyHex}")
return (note.createdAt() ?: 0) > lastTime
return (newestItem?.createdAt() ?: 0) > lastTime
}
}