feat: show voice room participants before joining

This commit is contained in:
2026-06-08 23:16:59 +05:30
committed by hodlbod
parent 8ba76a60e7
commit 7c0ee6ae71
4 changed files with 85 additions and 26 deletions
+32 -18
View File
@@ -4,6 +4,7 @@
import {loadProfile, displayProfileByPubkey} from "@welshman/app"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import ProfileCircle from "@app/components/ProfileCircle.svelte"
import ProfileCircles from "@app/components/ProfileCircles.svelte"
import RoomImage from "@app/components/RoomImage.svelte"
import RoomName from "@app/components/RoomName.svelte"
import {makeRoomPath} from "@app/util/routes"
@@ -20,7 +21,11 @@
voiceState,
type VoiceParticipant,
} from "@app/call/stores"
import {cancelJoinVoiceRoom, deriveVoiceParticipants} from "@app/call/voice"
import {
cancelJoinVoiceRoom,
deriveVoiceParticipants,
loadVoiceParticipants,
} from "@app/call/voice"
interface Props {
url: string
@@ -32,6 +37,7 @@
const {url, h, replaceState = false, notification = false}: Props = $props()
const participants = deriveVoiceParticipants(url, h)
const participantPubkeys = $derived($participants.flatMap(p => (p.pubkey ? [p.pubkey] : [])))
const isActive = $derived(
$voiceState === VoiceState.Connected && $currentVoiceRoom?.id === makeRoomId(url, h),
)
@@ -53,6 +59,10 @@
pushModal(VoiceRoomJoinDialog, {url, h})
}
$effect(() => {
void loadVoiceParticipants(url, h)
})
$effect(() => {
for (const p of $participants) {
if (p.pubkey) loadProfile(p.pubkey)
@@ -75,29 +85,33 @@
{/if}
<RoomName {url} {h} />
</div>
{#if $participants.length > 0}
{#each $participants as p (participantKey(p as VoiceParticipant))}
<div class="flex items-center gap-2 ml-6">
<div
class={cx(
"inline-flex shrink-0 items-center justify-center rounded-full transition-shadow",
isActive && $isParticipantSpeaking(p) && "ring-2 ring-success",
)}>
<ProfileCircle pubkey={p.pubkey} size={5} class="h-5 w-5" />
</div>
<span class="ellipsize min-w-0 flex-1 text-xs opacity-70">
{p.pubkey ? displayProfileByPubkey(p.pubkey) : "Unknown"}
</span>
{#if isActive}
{@const media = $mediaStateByIdentity(p.identity)}
{#if participantPubkeys.length > 0}
{#if isActive}
{#each $participants as p (participantKey(p as VoiceParticipant))}
{@const media = $mediaStateByIdentity(p.identity)}
<div class="flex items-center gap-2 ml-6">
<div
class={cx(
"inline-flex shrink-0 items-center justify-center rounded-full transition-shadow",
$isParticipantSpeaking(p) && "ring-2 ring-success",
)}>
<ProfileCircle pubkey={p.pubkey} size={5} class="h-5 w-5" />
</div>
<span class="ellipsize min-w-0 flex-1 text-xs opacity-70">
{p.pubkey ? displayProfileByPubkey(p.pubkey) : "Unknown"}
</span>
<VoiceParticipantMediaBadges
muted={media.muted}
cameraOn={media.cameraOn}
size={3}
class="shrink-0" />
{/if}
</div>
{/each}
{:else}
<div class="ml-6">
<ProfileCircles pubkeys={participantPubkeys} size={5} limit={3} />
</div>
{/each}
{/if}
{/if}
</div>
</SecondaryNavItem>