From 5c78b0dfcdcd7cdc31259f83d087fa3f515a2473 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 30 Apr 2026 19:05:44 -0400 Subject: [PATCH] Merge --- .../screen/loggedIn/nests/NestsFeedLoaded.kt | 24 ++++++++++--------- .../datasource/NestRoomFilterAssembler.kt | 23 ++++++++++-------- .../room/activity/NestActivityContent.kt | 2 +- .../nests/room/lobby/NestLobbyScreen.kt | 6 +++-- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt index 5b98e1ca3c..9de8568d52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/NestsFeedLoaded.kt @@ -56,6 +56,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState +import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteAndMap @@ -176,6 +177,7 @@ private fun NestFeedCard( true } } + val addressableNote = baseNote as? AddressableNote ?: return val onClick = remember(meetingEvent, isUiClosed) { @@ -205,7 +207,7 @@ private fun NestFeedCard( note = baseNote, accountViewModel = accountViewModel, ) { - ObserveAndRenderSpace(baseNote, accountViewModel, nav) + ObserveAndRenderSpace(addressableNote, accountViewModel, nav) } } } @@ -213,7 +215,7 @@ private fun NestFeedCard( @Composable fun ObserveAndRenderSpace( - baseNote: Note, + baseNote: AddressableNote, accountViewModel: AccountViewModel, nav: INav, ) { @@ -284,14 +286,14 @@ private const val PRESENCE_FRESHNESS_WINDOW_SECONDS = 180L */ @Composable private fun RenderLiveOrEndedFromPresence( - address: Address?, + note: AddressableNote?, accountViewModel: AccountViewModel, ) { - if (address == null) { + if (note == null) { LiveFlag() return } - val latestPresence by observeRoomLatestPresence(address, accountViewModel) + val latestPresence by observeRoomLatestPresence(note, accountViewModel) val fresh = latestPresence == null || latestPresence!! > TimeUtils.now() - PRESENCE_FRESHNESS_WINDOW_SECONDS if (fresh) LiveFlag() else EndedFlag() } @@ -310,12 +312,12 @@ private fun RenderLiveOrEndedFromPresence( @OptIn(ExperimentalCoroutinesApi::class) @Composable private fun observeRoomLatestPresence( - address: Address, + note: AddressableNote, accountViewModel: AccountViewModel, ): State { - NestRoomFilterAssemblerSubscription(address.toValue(), accountViewModel) + NestRoomFilterAssemblerSubscription(note, accountViewModel) - val channel = remember(address) { LocalCache.getOrCreateLiveChannel(address) } + val channel = remember(note.idHex) { LocalCache.getOrCreateLiveChannel(note.address) } val flow = remember(channel) { channel @@ -340,7 +342,7 @@ private fun observeRoomLatestPresence( @Composable fun RenderLiveSpacesThumb( card: NestCard, - baseNote: Note, + baseNote: AddressableNote, accountViewModel: AccountViewModel, nav: INav, ) { @@ -370,7 +372,7 @@ fun RenderLiveSpacesThumb( CrossfadeIfEnabled(targetState = card.status, accountViewModel = accountViewModel) { when (it) { StatusTag.STATUS.LIVE -> { - RenderLiveOrEndedFromPresence(card.id, accountViewModel) + RenderLiveOrEndedFromPresence(baseNote, accountViewModel) } StatusTag.STATUS.ENDED -> { @@ -419,7 +421,7 @@ fun RenderLiveSpacesThumb( @Composable fun SpaceHostAndReactions( name: String?, - baseNote: Note, + baseNote: AddressableNote, accountViewModel: AccountViewModel, nav: INav, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt index 7b1c2d1cd2..a4abe1c974 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/datasource/NestRoomFilterAssembler.kt @@ -26,6 +26,7 @@ import androidx.compose.runtime.remember import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.PerUniqueIdEoseManager import com.vitorpamplona.amethyst.service.relays.SincePerRelayMap import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -35,6 +36,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent +import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent /** @@ -46,7 +48,7 @@ import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresence */ @Stable class NestRoomQueryState( - val roomATag: String, + val note: AddressableNote, val account: Account, ) @@ -79,7 +81,8 @@ class NestRoomFilterSubAssembler( key: NestRoomQueryState, since: SincePerRelayMap?, ): List { - val relays = key.account.outboxRelays.flow.value + val relays = key.account.outboxRelays.flow.value + key.note.relays + ((key.note.event as? MeetingSpaceEvent)?.relays()?.toSet() ?: emptySet()) + return relays.flatMap { relay -> listOf( RelayBasedFilter( @@ -92,7 +95,7 @@ class NestRoomFilterSubAssembler( MeetingRoomPresenceEvent.KIND, ReactionEvent.KIND, ), - tags = mapOf("a" to listOf(key.roomATag)), + tags = mapOf("a" to listOf(key.note.idHex)), since = since?.get(relay)?.time, ), ), @@ -101,7 +104,7 @@ class NestRoomFilterSubAssembler( filter = Filter( kinds = listOf(AdminCommandEvent.KIND), - tags = mapOf("a" to listOf(key.roomATag), "p" to listOf(key.account.pubKey)), + tags = mapOf("a" to listOf(key.note.idHex), "p" to listOf(key.account.pubKey)), since = since?.get(relay)?.time, ), ), @@ -109,7 +112,7 @@ class NestRoomFilterSubAssembler( } } - override fun id(key: NestRoomQueryState): String = key.roomATag + override fun id(key: NestRoomQueryState): String = key.note.idHex } @Stable @@ -135,23 +138,23 @@ class NestRoomFilterAssembler( */ @Composable fun NestRoomFilterAssemblerSubscription( - roomATag: String, + note: AddressableNote, accountViewModel: AccountViewModel, ) = NestRoomFilterAssemblerSubscription( - roomATag, + note, accountViewModel.account, accountViewModel.dataSources().nestRoom, ) @Composable fun NestRoomFilterAssemblerSubscription( - roomATag: String, + note: AddressableNote, account: Account, filterAssembler: NestRoomFilterAssembler, ) { val state = - remember(roomATag, account.pubKey) { - NestRoomQueryState(roomATag, account) + remember(note, account.pubKey) { + NestRoomQueryState(note, account) } KeyDataSourceSubscription(state, filterAssembler) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt index 0c9418033e..8bac896c3b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/activity/NestActivityContent.kt @@ -161,7 +161,7 @@ private fun NestActivityBody( // Single REQ per relay covering chat, presence, reactions, admin // commands. See NestRoomFilterAssembler for the filter shape. - NestRoomFilterAssemblerSubscription(roomATag, accountViewModel) + NestRoomFilterAssemblerSubscription(roomNote, accountViewModel) // Read side: LocalCache → VM. Each kind has its own collector // (different VM hook per kind) plus the two eviction tickers. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt index cb1f9d86e6..e178deab8c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt @@ -62,6 +62,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import coil3.compose.AsyncImage import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.ui.navigation.navs.INav @@ -122,7 +123,7 @@ fun NestLobbyScreen( LoadAddressableNote(address, accountViewModel) { addressableNote -> addressableNote ?: return@LoadAddressableNote val event = addressableNote.event as? MeetingSpaceEvent ?: return@LoadAddressableNote - NestLobbyContent(event, accountViewModel, nav) + NestLobbyContent(event, addressableNote, accountViewModel, nav) } } @@ -130,6 +131,7 @@ fun NestLobbyScreen( @Composable private fun NestLobbyContent( event: MeetingSpaceEvent, + addressableNote: AddressableNote, accountViewModel: AccountViewModel, nav: INav, ) { @@ -137,7 +139,7 @@ private fun NestLobbyContent( // Keep cached chat / presence warm while the user is on the lobby. // No MoQ session is opened — that's gated behind the Open action. - NestRoomFilterAssemblerSubscription(roomATag, accountViewModel) + NestRoomFilterAssemblerSubscription(addressableNote, accountViewModel) // Composer for kind-1311 chat. Same widget the in-room screen uses, // so the user gets @-mention picker, file uploads, draft auto-save,