fix: display real avatars and resolved names in PiP overlay

Use useVoiceParticipantMeta hook to resolve avatar and display name
from space/DM member stores, matching VoiceUser and StreamTile behavior.
This commit is contained in:
Jannis Braun
2026-03-11 00:34:52 +01:00
parent 5300e78d9d
commit 9255683d8c
@@ -6,6 +6,15 @@ import { useUIStore } from '../../stores/uiStore';
import { useSpaceStore } from '../../stores/spaceStore'; import { useSpaceStore } from '../../stores/spaceStore';
import { Avatar } from '../ui/Avatar'; import { Avatar } from '../ui/Avatar';
import type { ParticipantInfo } from '../../hooks/useLiveKit'; import type { ParticipantInfo } from '../../hooks/useLiveKit';
import { useVoiceParticipantMeta } from '../../hooks/useVoiceParticipantMeta';
/** Stable fallback for useVoiceParticipantMeta when no participant exists */
const EMPTY_PARTICIPANT: ParticipantInfo = {
identity: '', userId: '', username: '', homeUserId: null,
isMuted: false, isDeafened: false, isCameraOn: false, isScreenSharing: false,
isLocal: false, audioTrack: null, videoTrack: null, screenTrack: null,
screenAudioTrack: null, lkVideoTrack: null, lkScreenTrack: null,
};
const PIP_WIDTH = 320; const PIP_WIDTH = 320;
const PIP_HEIGHT = 180; const PIP_HEIGHT = 180;
@@ -307,11 +316,19 @@ export function PictureInPicture() {
setPipCollapsed(true); setPipCollapsed(true);
}, [setPipCollapsed]); }, [setPipCollapsed]);
// Compute displayParticipant before early return so hook is called unconditionally
const displayParticipant = useMemo(
() => selectedStream?.participant ?? fallbackParticipant,
[selectedStream, fallbackParticipant],
);
const { displayName: resolvedName, avatar: resolvedAvatar } =
useVoiceParticipantMeta(displayParticipant ?? EMPTY_PARTICIPANT);
if (!shouldShow) return null; if (!shouldShow) return null;
const displayParticipant = selectedStream?.participant ?? fallbackParticipant;
const displayName = displayParticipant const displayName = displayParticipant
? (displayParticipant.isLocal ? `${displayParticipant.username} (You)` : displayParticipant.username) ? (displayParticipant.isLocal ? `${resolvedName} (You)` : resolvedName)
: channelName; : channelName;
const hasVideo = selectedStream !== null; const hasVideo = selectedStream !== null;
const isScreen = selectedStream?.type === 'screen'; const isScreen = selectedStream?.type === 'screen';
@@ -349,7 +366,8 @@ export function PictureInPicture() {
{displayParticipant ? ( {displayParticipant ? (
<div className="relative flex"> <div className="relative flex">
<Avatar <Avatar
name={displayParticipant.username} src={resolvedAvatar}
name={resolvedName}
size={64} size={64}
userId={displayParticipant.homeUserId ?? displayParticipant.userId} userId={displayParticipant.homeUserId ?? displayParticipant.userId}
/> />