Merge pull request #2649 from vitorpamplona/claude/fix-hand-raise-sync-Yf4b4

Fix stage presence sync and relay propagation in meeting rooms
This commit is contained in:
Vitor Pamplona
2026-04-29 18:26:21 -04:00
committed by GitHub
3 changed files with 27 additions and 3 deletions
@@ -195,6 +195,7 @@ import com.vitorpamplona.quartz.nip47WalletConnect.rpc.Request
import com.vitorpamplona.quartz.nip47WalletConnect.rpc.Response import com.vitorpamplona.quartz.nip47WalletConnect.rpc.Response
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark import com.vitorpamplona.quartz.nip51Lists.bookmarkList.tags.AddressBookmark
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
import com.vitorpamplona.quartz.nip56Reports.ReportType import com.vitorpamplona.quartz.nip56Reports.ReportType
@@ -980,7 +981,7 @@ class Account(
} }
linkedNote.event?.let { linkedEvent -> linkedNote.event?.let { linkedEvent ->
relayList.addAll(computeRelaysForChannels(linkedEvent)) relayList.addAll(computeRelayListToBroadcast(linkedEvent))
} }
} }
} }
@@ -1001,7 +1002,7 @@ class Account(
} }
linkedNote.event?.let { linkedEvent -> linkedNote.event?.let { linkedEvent ->
relayList.addAll(computeRelaysForChannels(linkedEvent)) relayList.addAll(computeRelayListToBroadcast(linkedEvent))
} }
} }
} }
@@ -1015,6 +1016,10 @@ class Account(
relayList.addAll(event.allRelayUrls()) relayList.addAll(event.allRelayUrls())
} }
if (event is MeetingRoomEvent) {
relayList.addAll(event.allRelayUrls())
}
if (event is LiveActivitiesEvent) { if (event is LiveActivitiesEvent) {
relayList.addAll(event.allRelayUrls()) relayList.addAll(event.allRelayUrls())
} }
@@ -25,6 +25,7 @@ import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEv
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.endpoint import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.endpoint
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.image import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.image
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.participants import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.participants
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.relays
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.summary import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.summary
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag
@@ -132,6 +133,14 @@ internal object RoomParticipantActions {
original.endpoint()?.let { endpoint(it) } original.endpoint()?.let { endpoint(it) }
original.summary()?.takeIf { it.isNotBlank() }?.let { summary(it) } original.summary()?.takeIf { it.isNotBlank() }?.let { summary(it) }
original.image()?.takeIf { it.isNotBlank() }?.let { image(it) } original.image()?.takeIf { it.isNotBlank() }?.let { image(it) }
// Preserve the room's `relays` tag — without it, the
// republished kind-30312 fans out only to the host's
// outbox, never reaching the room's own relay set
// (e.g. nostrnests's fixed five reads). The audience
// member would then never see their role grant and
// wouldn't appear on stage for any other participant
// listening on those relays.
original.relays().takeIf { it.isNotEmpty() }?.let { relays(it) }
if (others.isNotEmpty()) participants(others) if (others.isNotEmpty()) participants(others)
} }
} }
@@ -135,7 +135,6 @@ internal fun NestFullScreen(
val isHost = accountViewModel.account.signer.pubKey == event.pubKey val isHost = accountViewModel.account.signer.pubKey == event.pubKey
val myPubkey = accountViewModel.account.signer.pubKey val myPubkey = accountViewModel.account.signer.pubKey
val isOnStageMe = remember(onStage, myPubkey) { onStage.any { it.pubKey == myPubkey } }
val leaveScope = rememberCoroutineScope() val leaveScope = rememberCoroutineScope()
val topBarContext = LocalContext.current val topBarContext = LocalContext.current
@@ -152,6 +151,17 @@ internal fun NestFullScreen(
presences = presences, presences = presences,
) )
} }
// Tie the action bar's "am I on stage" gate to the same data
// source the StageGrid uses (role + presence.onstage flag),
// not just the kind-30312 role tag. Otherwise a host who taps
// "Leave Stage" flips presence to onstage=0 and disappears
// from the StageGrid, but the action bar keeps showing the
// Talk + Leave Stage cluster because it's still gated on
// role-only.
val isOnStageMe =
remember(participantGrid, myPubkey) {
participantGrid.onStage.any { it.pubkey == myPubkey }
}
// Same logic HandRaiseQueueSection uses internally — duplicated // Same logic HandRaiseQueueSection uses internally — duplicated
// here so the tab label can show a count without coupling the // here so the tab label can show a count without coupling the
// section to the screen. // section to the screen.