From e80473a7d900d36979edacdc5b499b865857df97 Mon Sep 17 00:00:00 2001 From: nrobi144 Date: Thu, 19 Mar 2026 15:22:38 +0200 Subject: [PATCH] =?UTF-8?q?feat(cache):=20Phase=203=20=E2=80=94=20route=20?= =?UTF-8?q?all=20screen=20events=20through=20cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All screens now pipe relay events into DesktopLocalCache via coordinator.consumeEvent(). Existing per-screen EventCollectionState kept for rendering (incremental migration), but data also enters cache for persistence across navigation. - FeedScreen: route global + following feed events - ThreadScreen: route root note + reply events - UserProfileScreen: route posts + add cache hydration on mount (LaunchedEffect queries cache for existing posts → instant display) - BookmarksScreen: route public + private bookmark events - ReadsScreen: route long-form feed events (add coordinator param) - NotificationsScreen: route notification events Co-Authored-By: Claude Opus 4.6 (1M context) --- .../amethyst/desktop/ui/BookmarksScreen.kt | 6 ++++-- .../amethyst/desktop/ui/FeedScreen.kt | 3 ++- .../amethyst/desktop/ui/NotificationsScreen.kt | 3 ++- .../amethyst/desktop/ui/ReadsScreen.kt | 5 ++++- .../amethyst/desktop/ui/ThreadScreen.kt | 6 ++++-- .../amethyst/desktop/ui/UserProfileScreen.kt | 18 ++++++++++++++++-- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/BookmarksScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/BookmarksScreen.kt index f08682e56..ac56815dc 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/BookmarksScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/BookmarksScreen.kt @@ -188,7 +188,8 @@ fun BookmarksScreen( FilterBuilders.byIds(publicBookmarkIds), ), relays = connectedRelays, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) publicEventState.addItem(event) }, onEose = { _, _ -> }, @@ -209,7 +210,8 @@ fun BookmarksScreen( FilterBuilders.byIds(privateBookmarkIds), ), relays = connectedRelays, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) privateEventState.addItem(event) }, onEose = { _, _ -> }, diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt index b8fee1344..c493247a3 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/FeedScreen.kt @@ -279,7 +279,8 @@ fun FeedScreen( FeedMode.GLOBAL -> { createGlobalFeedSubscription( relays = configuredRelays, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) // Store metadata events in cache if (event is MetadataEvent) { localCache.consumeMetadata(event) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NotificationsScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NotificationsScreen.kt index e1be49646..1fe3d31fd 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NotificationsScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/NotificationsScreen.kt @@ -143,7 +143,8 @@ fun NotificationsScreen( createNotificationsSubscription( relays = connectedRelays, pubKeyHex = account.pubKeyHex, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) // Skip events from the user themselves (except zaps) if (event.pubKey == account.pubKeyHex && event !is LnZapEvent) { return@createNotificationsSubscription diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ReadsScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ReadsScreen.kt index 2d5aba286..c1e6d94bb 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ReadsScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ReadsScreen.kt @@ -62,6 +62,7 @@ import com.vitorpamplona.amethyst.commons.ui.components.LoadingState import com.vitorpamplona.amethyst.desktop.account.AccountState import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager +import com.vitorpamplona.amethyst.desktop.subscriptions.DesktopRelaySubscriptionsCoordinator import com.vitorpamplona.amethyst.desktop.subscriptions.FeedMode import com.vitorpamplona.amethyst.desktop.subscriptions.createContactListSubscription import com.vitorpamplona.amethyst.desktop.subscriptions.createFollowingLongFormFeedSubscription @@ -180,6 +181,7 @@ fun ReadsScreen( localCache: DesktopLocalCache, account: AccountState.LoggedIn? = null, nwcConnection: Nip47WalletConnect.Nip47URINorm? = null, + subscriptionsCoordinator: DesktopRelaySubscriptionsCoordinator? = null, onNavigateToProfile: (String) -> Unit = {}, onNavigateToArticle: (String) -> Unit = {}, onNavigateToThread: (String) -> Unit = {}, @@ -239,7 +241,8 @@ fun ReadsScreen( FeedMode.GLOBAL -> { createLongFormFeedSubscription( relays = connectedRelays, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) if (event is LongTextNoteEvent) { eventState.addItem(event) } diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ThreadScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ThreadScreen.kt index d4368f984..c9ab39e30 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ThreadScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/ThreadScreen.kt @@ -203,7 +203,8 @@ fun ThreadScreen( createNoteSubscription( relays = connectedRelays, noteId = noteId, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) if (event.id == noteId) { rootNote = event levelCache[event.id] = 0 @@ -224,7 +225,8 @@ fun ThreadScreen( createThreadRepliesSubscription( relays = connectedRelays, noteId = noteId, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) replyEventState.addItem(event) }, onEose = { _, _ -> diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/UserProfileScreen.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/UserProfileScreen.kt index c79b4e368..15ab92d4a 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/UserProfileScreen.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/UserProfileScreen.kt @@ -206,13 +206,26 @@ fun UserProfileScreen( } } - // Clear posts when profile changes + // Clear posts when profile changes, then hydrate from cache remember(pubKeyHex, retryTrigger) { eventState.clear() postsLoading = true postsError = null } + // Hydrate from cache — show previously loaded posts instantly + LaunchedEffect(pubKeyHex) { + val cachedNotes = + localCache.notes.filterIntoSet { _, note -> + note.event?.kind == 1 && note.author?.pubkeyHex == pubKeyHex + } + if (cachedNotes.isNotEmpty()) { + val events = cachedNotes.mapNotNull { it.event } + eventState.addItems(events) + postsLoading = false + } + } + // Subscribe to user metadata rememberSubscription(connectedRelays, pubKeyHex, retryTrigger, relayManager = relayManager) { if (connectedRelays.isNotEmpty()) { @@ -308,7 +321,8 @@ fun UserProfileScreen( createUserPostsSubscription( relays = connectedRelays, pubKeyHex = pubKeyHex, - onEvent = { event, _, _, _ -> + onEvent = { event, _, relay, _ -> + subscriptionsCoordinator?.consumeEvent(event, relay) eventState.addItem(event) }, onEose = { _, _ ->