feat(cache): seed Reads and Bookmarks screens from cache on compose

Both screens now show cached data instantly on navigation instead of
showing loading states while re-fetching from relays.

- BookmarksScreen: reads cached BookmarkListEvent from addressableNotes,
  seeds public bookmark events from notes cache
- ReadsScreen: seeds long-form notes (kind 30023) from notes cache

Relay subscriptions still run to fetch fresh data in parallel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-03-23 14:36:09 +02:00
parent f27c8811d5
commit 3b489fb3cb
2 changed files with 34 additions and 0 deletions
@@ -121,6 +121,27 @@ fun BookmarksScreen(
}
}
// Seed from cache — bookmark list event may already be in addressableNotes
LaunchedEffect(account.pubKeyHex) {
val address = BookmarkListEvent.createBookmarkAddress(account.pubKeyHex)
val cachedNote = localCache.getOrCreateAddressableNote(address)
val cachedEvent = cachedNote.event as? BookmarkListEvent
if (cachedEvent != null) {
bookmarkList = cachedEvent
publicBookmarkIds =
cachedEvent
.publicBookmarks()
.filterIsInstance<EventBookmark>()
.map { it.eventId }
// Seed public events from cache
publicBookmarkIds.forEach { id ->
val note = localCache.getNoteIfExists(id)
val event = note?.event
if (event != null) publicEventState.addItem(event)
}
}
}
// Subscribe to user's bookmark list (kind 30001)
rememberSubscription(connectedRelays, account.pubKeyHex, relayManager = relayManager) {
if (connectedRelays.isNotEmpty()) {
@@ -46,6 +46,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -207,6 +208,18 @@ fun ReadsScreen(
var eoseReceivedCount by remember { mutableStateOf(0) }
val initialLoadComplete = eoseReceivedCount > 0
// Seed from cache — long-form notes already consumed are in cache
LaunchedEffect(Unit) {
val cached =
localCache.notes.filterIntoSet { _, note ->
note.event is LongTextNoteEvent
}
cached.forEach { note ->
(note.event as? LongTextNoteEvent)?.let { eventState.addItem(it) }
}
if (cached.isNotEmpty()) eoseReceivedCount++
}
// Load followed users for Following feed mode
rememberSubscription(connectedRelays, account, feedMode, relayManager = relayManager) {
val connectedRelays = connectedRelays