Fixes missing cache after AI PR for the desktop app

Removes dependency on the Cache from User.
Updates interface methods to match.
This commit is contained in:
Vitor Pamplona
2026-01-13 11:27:45 -05:00
parent 2fe0157b2e
commit 5241a6dfa7
5 changed files with 18 additions and 30 deletions
@@ -324,7 +324,7 @@ object LocalCache : ILocalCache, ICacheProvider {
return users.get(key) return users.get(key)
} }
override fun countUsers(predicate: (String, Any) -> Boolean): Int { override fun countUsers(predicate: (String, User) -> Boolean): Int {
var count = 0 var count = 0
users.forEach { key, user -> users.forEach { key, user ->
if (predicate(key, user)) count++ if (predicate(key, user)) count++
@@ -531,9 +531,13 @@ object LocalCache : ILocalCache, ICacheProvider {
// avoids processing empty contact lists. // avoids processing empty contact lists.
if (event.createdAt > (user.latestContactList?.createdAt ?: 0) && !event.tags.isEmpty() && (wasVerified || justVerify(event))) { if (event.createdAt > (user.latestContactList?.createdAt ?: 0) && !event.tags.isEmpty() && (wasVerified || justVerify(event))) {
user.updateContactList(event) val needsToUpdateFollowers = user.updateContactList(event)
// Log.d("CL", "Consumed contact list ${user.toNostrUri()} ${event.relays()?.size}") // Log.d("CL", "Consumed contact list ${user.toNostrUri()} ${event.relays()?.size}")
needsToUpdateFollowers.forEach {
getUserIfExists(it)?.flowSet?.followers?.invalidateData()
}
updateObservables(event) updateObservables(event)
return true return true
@@ -21,9 +21,6 @@
package com.vitorpamplona.amethyst.model package com.vitorpamplona.amethyst.model
// Re-export from commons for backwards compatibility // Re-export from commons for backwards compatibility
typealias UserDependencies = com.vitorpamplona.amethyst.commons.model.UserDependencies
typealias User = com.vitorpamplona.amethyst.commons.model.User typealias User = com.vitorpamplona.amethyst.commons.model.User
typealias UserFlowSet = com.vitorpamplona.amethyst.commons.model.UserFlowSet
typealias RelayInfo = com.vitorpamplona.amethyst.commons.model.RelayInfo typealias RelayInfo = com.vitorpamplona.amethyst.commons.model.RelayInfo
typealias UserBundledRefresherFlow = com.vitorpamplona.amethyst.commons.model.UserBundledRefresherFlow
typealias UserState = com.vitorpamplona.amethyst.commons.model.UserState typealias UserState = com.vitorpamplona.amethyst.commons.model.UserState
@@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.model.nip28PublicChats.PublicChatChannel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.tags.people.isTaggedUser
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.hashtagList.HashtagListEvent import com.vitorpamplona.quartz.nip51Lists.hashtagList.HashtagListEvent
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
@@ -392,7 +393,9 @@ fun observeUserFollowerCount(
.followers.stateFlow .followers.stateFlow
.sample(200) .sample(200)
.mapLatest { userState -> .mapLatest { userState ->
userState.user.transientFollowerCount() LocalCache.countUsers { _, user ->
user.latestContactList?.isTaggedUser(user.pubkeyHex) ?: false
}
}.distinctUntilChanged() }.distinctUntilChanged()
.flowOn(Dispatchers.IO) .flowOn(Dispatchers.IO)
} }
@@ -22,11 +22,11 @@ package com.vitorpamplona.amethyst.commons.model
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.model.cache.ICacheProvider
import com.vitorpamplona.amethyst.commons.model.nip56Reports.UserReportCache import com.vitorpamplona.amethyst.commons.model.nip56Reports.UserReportCache
import com.vitorpamplona.amethyst.commons.model.trustedAssertions.UserCardsCache import com.vitorpamplona.amethyst.commons.model.trustedAssertions.UserCardsCache
import com.vitorpamplona.amethyst.commons.util.toShortDisplay import com.vitorpamplona.amethyst.commons.util.toShortDisplay
import com.vitorpamplona.quartz.lightning.Lud06 import com.vitorpamplona.quartz.lightning.Lud06
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists import com.vitorpamplona.quartz.nip01Core.core.toImmutableListOfLists
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata
@@ -51,7 +51,6 @@ class User(
val pubkeyHex: String, val pubkeyHex: String,
val nip65RelayListNote: Note, val nip65RelayListNote: Note,
val dmRelayListNote: Note, val dmRelayListNote: Note,
private val cacheProvider: ICacheProvider? = null,
) { ) {
private var reports: UserReportCache? = null private var reports: UserReportCache? = null
private var cards: UserCardsCache? = null private var cards: UserCardsCache? = null
@@ -120,8 +119,8 @@ class User(
fun profilePicture(): String? = info?.picture fun profilePicture(): String? = info?.picture
fun updateContactList(event: ContactListEvent) { fun updateContactList(event: ContactListEvent): Set<HexKey> {
if (event.id == latestContactList?.id) return if (event.id == latestContactList?.id) return emptySet()
val oldContactListEvent = latestContactList val oldContactListEvent = latestContactList
latestContactList = event latestContactList = event
@@ -129,20 +128,9 @@ class User(
// Update following of the current user // Update following of the current user
flowSet?.follows?.invalidateData() flowSet?.follows?.invalidateData()
// Update Followers of the past user list val affectedUsers = event.verifiedFollowKeySet() + (oldContactListEvent?.verifiedFollowKeySet() ?: emptySet())
// Update Followers of the new contact list
(oldContactListEvent)?.unverifiedFollowKeySet()?.forEach { return affectedUsers
(cacheProvider?.getUserIfExists(it) as? User)
?.flowSet
?.followers
?.invalidateData()
}
(latestContactList)?.unverifiedFollowKeySet()?.forEach {
(cacheProvider?.getUserIfExists(it) as? User)
?.flowSet
?.followers
?.invalidateData()
}
} }
fun addZap( fun addZap(
@@ -217,11 +205,6 @@ class User(
fun transientFollowCount(): Int? = latestContactList?.unverifiedFollowKeySet()?.size fun transientFollowCount(): Int? = latestContactList?.unverifiedFollowKeySet()?.size
fun transientFollowerCount(): Int =
cacheProvider?.countUsers { _, it ->
(it as? User)?.latestContactList?.isTaggedUser(pubkeyHex) ?: false
} ?: 0
fun reportsOrNull(): UserReportCache? = reports fun reportsOrNull(): UserReportCache? = reports
fun reports(): UserReportCache = reports ?: UserReportCache().also { reports = it } fun reports(): UserReportCache = reports ?: UserReportCache().also { reports = it }
@@ -20,6 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.commons.model.cache package com.vitorpamplona.amethyst.commons.model.cache
import com.vitorpamplona.amethyst.commons.model.User
import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.HexKey
/** /**
@@ -60,7 +61,7 @@ interface ICacheProvider {
* @param predicate Filter function for counting users * @param predicate Filter function for counting users
* @return Count of users matching the predicate * @return Count of users matching the predicate
*/ */
fun countUsers(predicate: (String, Any) -> Boolean): Int fun countUsers(predicate: (String, User) -> Boolean): Int
/** /**
* Gets a Note if it exists in cache. * Gets a Note if it exists in cache.