mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
feat: warm each group's recent messages on a relay's channel list
Opening a group from the relay's channel list used to start its chat from a cold load. Mount the existing RelayGroupWarmupSubscription on every visible card (content-only — the directory subscription already streams metadata), so a tap lands on already-cached messages. Add a contentLimit to the warmup (default 50, unchanged for discovery's "50+" signal); the channel list passes ~10 — a first screen's worth. Bounded to visible rows by the LazyColumn and released as they scroll off. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B5MLY4hq5LXJ2D5WeLRyXj
This commit is contained in:
+18
-1
@@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarExtensibleWithBackButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupWarmupSubscription
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.datasource.RelayGroupsOnRelaySubscription
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
@@ -67,11 +68,15 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
||||
import com.vitorpamplona.quartz.nip29RelayGroups.metadata.GroupMetadataEvent
|
||||
|
||||
/** A first screen's worth of recent messages to prefetch per visible group card, ahead of a tap. */
|
||||
private const val CHANNEL_LIST_WARMUP_LIMIT = 10
|
||||
|
||||
/**
|
||||
* Lists every channel a relay hosts (its kind 39000-39003 directory), so the user
|
||||
* can browse and open channels on that relay. The relay's directory is streamed by
|
||||
* [RelayGroupsOnRelaySubscription] and consumed into per-group channels; this
|
||||
* screen reads them back for the relay and renders them.
|
||||
* screen reads them back for the relay and renders them. Each visible card also warms
|
||||
* its group's recent messages so opening a chat lands on cached content.
|
||||
*/
|
||||
@Composable
|
||||
fun RelayGroupChannelListScreen(
|
||||
@@ -156,6 +161,18 @@ private fun RelayGroupChannelRow(
|
||||
val joined = channel.membershipOf(myPubkey).isMember()
|
||||
val memberCount = channel.memberCount()
|
||||
|
||||
// Anticipate a tap: while this row is on-screen, prefetch a first screen's worth of recent
|
||||
// messages for its group (content only — the directory subscription already streams metadata),
|
||||
// so opening the chat lands on cached content instead of a blank load. Bounded to visible rows
|
||||
// by the LazyColumn, and released as they scroll off.
|
||||
RelayGroupWarmupSubscription(
|
||||
channel,
|
||||
accountViewModel.dataSources().relayGroupWarmup,
|
||||
accountViewModel,
|
||||
contentOnly = true,
|
||||
contentLimit = CHANNEL_LIST_WARMUP_LIMIT,
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
|
||||
+8
-5
@@ -40,6 +40,8 @@ class RelayGroupWarmupQueryState(
|
||||
val channel: RelayGroupChannel,
|
||||
/** When true, prefetch only recent content — the caller's screen already streams metadata. */
|
||||
val contentOnly: Boolean = false,
|
||||
/** How many recent content events to prefetch ahead of a tap. */
|
||||
val contentLimit: Int = RELAY_GROUP_WARMUP_LIMIT,
|
||||
)
|
||||
|
||||
/** Newest content kinds we prefetch so opening the card lands on populated screens. */
|
||||
@@ -47,11 +49,12 @@ private val RELAY_GROUP_WARMUP_CONTENT_KINDS =
|
||||
listOf(ChatEvent.KIND, PollEvent.KIND, ThreadEvent.KIND, CommentEvent.KIND)
|
||||
|
||||
/**
|
||||
* How many recent events to pull ahead of a tap — enough to fill the first screen AND drive the
|
||||
* discovery card's "50+ messages" activity signal (a chat that returns the full page reads as
|
||||
* "50+"; fewer shows the exact loaded count).
|
||||
* Default number of recent events to pull ahead of a tap — enough to fill the first screen AND drive
|
||||
* the discovery card's "50+ messages" activity signal (a chat that returns the full page reads as
|
||||
* "50+"; fewer shows the exact loaded count). Callers that only need a first-screen preview (e.g. a
|
||||
* relay's channel list) pass a smaller [RelayGroupWarmupQueryState.contentLimit].
|
||||
*/
|
||||
private const val RELAY_GROUP_WARMUP_LIMIT = 50
|
||||
const val RELAY_GROUP_WARMUP_LIMIT = 50
|
||||
|
||||
/**
|
||||
* Warms a NIP-29 group referenced inline (a group-link card) without opening it:
|
||||
@@ -92,7 +95,7 @@ class RelayGroupWarmupSubAssembler(
|
||||
Filter(
|
||||
kinds = RELAY_GROUP_WARMUP_CONTENT_KINDS,
|
||||
tags = mapOf(GroupIdTag.TAG_NAME to listOf(groupId.id)),
|
||||
limit = RELAY_GROUP_WARMUP_LIMIT,
|
||||
limit = key.contentLimit,
|
||||
since = since?.get(groupId.relayUrl)?.time,
|
||||
),
|
||||
)
|
||||
|
||||
+3
-2
@@ -37,10 +37,11 @@ fun RelayGroupWarmupSubscription(
|
||||
dataSource: RelayGroupWarmupFilterAssembler,
|
||||
accountViewModel: AccountViewModel,
|
||||
contentOnly: Boolean = false,
|
||||
contentLimit: Int = RELAY_GROUP_WARMUP_LIMIT,
|
||||
) {
|
||||
val state =
|
||||
remember(channel.groupId, contentOnly) {
|
||||
RelayGroupWarmupQueryState(channel, contentOnly)
|
||||
remember(channel.groupId, contentOnly, contentLimit) {
|
||||
RelayGroupWarmupQueryState(channel, contentOnly, contentLimit)
|
||||
}
|
||||
|
||||
LifecycleAwareKeyDataSourceSubscription(state, dataSource)
|
||||
|
||||
Reference in New Issue
Block a user