Merge pull request #2080 from vitorpamplona/claude/preload-bookmark-events-hq9nL

Preload bookmark events to improve scrolling performance
This commit is contained in:
Vitor Pamplona
2026-04-02 15:42:56 -04:00
committed by GitHub
2 changed files with 61 additions and 0 deletions
@@ -31,8 +31,10 @@ import androidx.compose.material3.SecondaryScrollableTabRow
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -40,6 +42,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderQueryState
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
@@ -90,6 +93,9 @@ fun BookmarkListScreen(
pinnedNotesFeedViewModel.invalidateData() pinnedNotesFeedViewModel.invalidateData()
} }
// Preload all bookmarked and pinned events so they don't load one-by-one when scrolling
PreloadBookmarkEvents(bookmarkState, pinState, accountViewModel)
RenderBookmarkScreen(publicFeedViewModel, privateFeedViewModel, pinnedNotesFeedViewModel, accountViewModel, nav) RenderBookmarkScreen(publicFeedViewModel, privateFeedViewModel, pinnedNotesFeedViewModel, accountViewModel, nav)
} }
@@ -171,3 +177,28 @@ private fun RenderBookmarkScreen(
} }
} }
} }
@Composable
private fun PreloadBookmarkEvents(
bookmarkState: com.vitorpamplona.amethyst.commons.model.nip51Lists.BookmarkListState.BookmarkList?,
pinState: List<com.vitorpamplona.amethyst.model.Note>?,
accountViewModel: AccountViewModel,
) {
val eventFinder = accountViewModel.dataSources().eventFinder
val account = accountViewModel.account
val queries =
remember(bookmarkState, pinState) {
val allNotes = (bookmarkState?.public.orEmpty() + bookmarkState?.private.orEmpty() + pinState.orEmpty())
allNotes
.filter { it.event == null }
.map { EventFinderQueryState(it, account) }
}
DisposableEffect(queries) {
eventFinder.subscribe(queries)
onDispose {
eventFinder.unsubscribe(queries)
}
}
}
@@ -36,8 +36,10 @@ import androidx.compose.material3.SecondaryTabRow
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -45,6 +47,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderQueryState
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
@@ -81,6 +84,9 @@ fun OldBookmarkListScreen(
privateFeedViewModel.invalidateData() privateFeedViewModel.invalidateData()
} }
// Preload all bookmarked events so they don't load one-by-one when scrolling
PreloadOldBookmarkEvents(bookmarkState, accountViewModel)
RenderOldBookmarkScreen(publicFeedViewModel, privateFeedViewModel, accountViewModel, nav) RenderOldBookmarkScreen(publicFeedViewModel, privateFeedViewModel, accountViewModel, nav)
} }
@@ -172,3 +178,27 @@ private fun RenderOldBookmarkScreen(
} }
} }
} }
@Composable
private fun PreloadOldBookmarkEvents(
bookmarkState: com.vitorpamplona.amethyst.commons.model.nip51Lists.OldBookmarkListState.BookmarkList?,
accountViewModel: AccountViewModel,
) {
val eventFinder = accountViewModel.dataSources().eventFinder
val account = accountViewModel.account
val queries =
remember(bookmarkState) {
val allNotes = bookmarkState?.public.orEmpty() + bookmarkState?.private.orEmpty()
allNotes
.filter { it.event == null }
.map { EventFinderQueryState(it, account) }
}
DisposableEffect(queries) {
eventFinder.subscribe(queries)
onDispose {
eventFinder.unsubscribe(queries)
}
}
}