Migrates Desktop App to the new metadata cache.

This commit is contained in:
Vitor Pamplona
2026-02-04 15:38:16 -05:00
parent d2f77ed521
commit e6f7a543cd
6 changed files with 37 additions and 27 deletions
@@ -54,7 +54,7 @@ class ThreadAssembler(
// Check to see if there is an error in the tag and the root has replies
val rootNote = cache.getNoteIfExists(markedAsRoot) as? Note
if (rootNote?.replyTo?.isEmpty() == true) {
return cache.checkGetOrCreateNote(markedAsRoot) as? Note
return cache.checkGetOrCreateNote(markedAsRoot)
}
}
@@ -88,7 +88,7 @@ class ThreadAssembler(
)
fun findRoot(noteId: String): Note? {
val note = cache.checkGetOrCreateNote(noteId) as? Note ?: return null
val note = cache.checkGetOrCreateNote(noteId) ?: return null
return if (note.event != null) {
val thread = OnlyLatestVersionSet()
@@ -102,7 +102,7 @@ class ThreadAssembler(
fun findThreadFor(noteId: String): ThreadInfo? {
checkNotInMainThread()
val note = cache.checkGetOrCreateNote(noteId) as? Note ?: return null
val note = cache.checkGetOrCreateNote(noteId) ?: return null
return if (note.event != null) {
val thread = OnlyLatestVersionSet()
@@ -41,7 +41,11 @@ class MetadataPreloader(
*/
fun preloadForUsers(users: Collection<User>) {
users.forEach { user ->
val metadata = user.info
val metadata =
user
.metadata()
.flow.value
?.info
if (metadata != null) {
// Already have metadata, prefetch avatar
metadata.picture?.let { avatarUrl ->
@@ -58,7 +62,11 @@ class MetadataPreloader(
* Queue a single user for metadata preloading.
*/
fun preloadForUser(user: User) {
val metadata = user.info
val metadata =
user
.metadata()
.flow.value
?.info
if (metadata != null) {
metadata.picture?.let { avatarUrl ->
imagePrefetcher?.prefetch(avatarUrl)
@@ -73,7 +81,7 @@ class MetadataPreloader(
* Triggers avatar image prefetch.
*/
fun onMetadataReceived(user: User) {
user.info?.picture?.let { avatarUrl ->
user.metadata().flow.value?.info?.picture?.let { avatarUrl ->
imagePrefetcher?.prefetch(avatarUrl)
}
}
@@ -83,7 +91,7 @@ class MetadataPreloader(
*/
fun prefetchAvatars(users: Collection<User>) {
users.forEach { user ->
user.info?.picture?.let { avatarUrl ->
user.metadata().flow.value?.info?.picture?.let { avatarUrl ->
imagePrefetcher?.prefetch(avatarUrl)
}
}
@@ -107,11 +107,11 @@ class DesktopLocalCache : ICacheProvider {
fun consumeMetadata(event: MetadataEvent) {
val user = getOrCreateUser(event.pubKey)
// Only update if newer
val currentMetadata = user.latestMetadata
if (currentMetadata == null || event.createdAt > currentMetadata.createdAt) {
user.latestMetadata = event
user.info = event.contactMetaData()
if (user.metadata().shouldUpdateWith(event)) {
val newUserMetadata = event.contactMetaData()
if (newUserMetadata != null) {
user.updateUserInfo(newUserMetadata, event, null)
}
}
}
@@ -333,7 +333,11 @@ fun FeedScreen(
// Only fetch metadata for users we don't have yet
val missingPubkeys =
zapSenderPubkeys.filter { pubkey ->
localCache.getUserIfExists(pubkey)?.info == null
localCache
.getUserIfExists(pubkey)
?.metadataOrNull()
?.flow
?.value == null
}
if (missingPubkeys.isEmpty()) {
return@rememberSubscription null
@@ -449,7 +453,11 @@ fun FeedScreen(
// Only fetch metadata for users we don't have yet
val missingPubkeys =
authorPubkeys.filter { pubkey ->
localCache.getUserIfExists(pubkey)?.info == null
localCache
.getUserIfExists(pubkey)
?.metadataOrNull()
?.flow
?.value == null
}
if (missingPubkeys.isEmpty()) {
return@rememberSubscription null
@@ -70,14 +70,12 @@ import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
import com.vitorpamplona.amethyst.desktop.nwc.NwcPaymentHandler
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArrayOrNull
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.IRequestListener
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
import com.vitorpamplona.quartz.nip19Bech32.entities.NNote
import com.vitorpamplona.quartz.nip19Bech32.toNpub
import com.vitorpamplona.quartz.nip47WalletConnect.Nip47WalletConnect
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
@@ -149,12 +147,8 @@ fun getDisplayName(
pubKey: String,
localCache: DesktopLocalCache,
): String {
val user = localCache.getUserIfExists(pubKey)
return user?.info?.bestName()
?: pubKey.hexToByteArrayOrNull()?.toNpub()?.let { npub ->
npub.take(12) + "..." + npub.takeLast(6)
}
?: pubKey.take(12) + "..."
val user = localCache.getUserIfExists(pubKey) ?: return pubKey.take(12)
return user.toBestDisplayName()
}
/**
@@ -308,7 +302,7 @@ fun ZapReceiptsDialog(
.distinct()
.filter { pubKey ->
val user = localCache.getUserIfExists(pubKey)
user?.info == null
user?.metadataOrNull()?.flow?.value == null
}
if (pubKeysNeedingMetadata.isNotEmpty()) {
@@ -925,7 +919,7 @@ private suspend fun zapNote(
withContext(Dispatchers.IO) {
// Get author's lightning address from cache
var user = localCache.getUserIfExists(event.pubKey)
var lnAddress = user?.info?.lud16 ?: user?.info?.lud06
var lnAddress = user?.lnAddress()
// TODO: Use UserFinderFilterAssemblerSubscription pattern from Amethyst
// to proactively load metadata when zap button is displayed.
@@ -1068,7 +1062,7 @@ private suspend fun fetchUserLightningAddress(
if (event is MetadataEvent && !resumed) {
localCache.consumeMetadata(event)
val user = localCache.getUserIfExists(pubKey)
val lnAddress = user?.info?.lud16 ?: user?.info?.lud06
val lnAddress = user?.lnAddress()
if (lnAddress != null && !resumed) {
resumed = true
timeoutJob.cancel()
@@ -84,8 +84,8 @@ fun LongFormCard(
onAuthorClick: (String) -> Unit = {},
onClick: () -> Unit = {},
) {
val author = localCache.getUserIfExists(event.pubKey)
val authorName = author?.info?.bestName() ?: event.pubKey.take(8)
val author = localCache.getOrCreateUser(event.pubKey)
val authorName = author.toBestDisplayName()
val publishedAt = event.publishedAt() ?: event.createdAt
Card(