Add backupIframeRef so we can re-add the lobby screen for non-joined calls (for viewing their text channels)

This commit is contained in:
Gigiaj 2025-05-09 09:38:43 -05:00
parent 0be5fb9732
commit a690dbd2ca

View file

@ -1,9 +1,10 @@
import { Room } from 'matrix-js-sdk'; import { Room } from 'matrix-js-sdk';
import React from 'react'; import React, { useMemo } from 'react';
import { useCallback, useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { useOutletContext } from 'react-router-dom'; import { useOutletContext } from 'react-router-dom';
import { Box } from 'folds'; import { Box } from 'folds';
import { RoomViewHeader } from './RoomViewHeader'; import { RoomViewHeader } from './RoomViewHeader';
import { useCallState } from '../../pages/client/CallProvider';
function debounce<F extends (...args: any[]) => any>(func: F, waitFor: number) { function debounce<F extends (...args: any[]) => any>(func: F, waitFor: number) {
let timeoutId: ReturnType<typeof setTimeout> | null = null; let timeoutId: ReturnType<typeof setTimeout> | null = null;
@ -28,23 +29,30 @@ type OriginalStyles = {
border?: string; border?: string;
}; };
export function CallView({ room, eventId }: { room: Room; eventId?: string }) { interface CallViewOutletContext {
const { iframeRef } = useOutletContext<{
iframeRef: React.RefObject<HTMLIFrameElement | null>; iframeRef: React.RefObject<HTMLIFrameElement | null>;
}>(); backupIframeRef: React.RefObject<HTMLIFrameElement | null>;
}
export function CallView({ room, eventId }: { room: Room; eventId?: string }) {
const { iframeRef, backupIframeRef } = useOutletContext<CallViewOutletContext>();
const iframeHostRef = useRef<HTMLDivElement>(null); const iframeHostRef = useRef<HTMLDivElement>(null);
const originalIframeStylesRef = useRef<OriginalStyles | null>(null); const originalIframeStylesRef = useRef<OriginalStyles | null>(null);
const { activeCallRoomId, isPrimaryIframe } = useCallState();
const isViewingActiveCall = useMemo(
() => activeCallRoomId !== null && activeCallRoomId === room.roomId,
[activeCallRoomId]
);
const shouldDisplayCallIFrame = const activeIframeDisplayRef =
room && typeof room.isCallRoom === 'function' && room.isCallRoom(); !isPrimaryIframe || isViewingActiveCall ? iframeRef : backupIframeRef;
const applyFixedPositioningToIframe = useCallback(() => { const applyFixedPositioningToIframe = useCallback(() => {
const iframeElement = iframeRef?.current; const iframeElement = activeIframeDisplayRef?.current;
const hostElement = iframeHostRef?.current; const hostElement = iframeHostRef?.current;
if (iframeElement && hostElement) { if (iframeElement && hostElement) {
// Save original styles only ONCE per "portaling" session
if (!originalIframeStylesRef.current) { if (!originalIframeStylesRef.current) {
const computed = window.getComputedStyle(iframeElement); const computed = window.getComputedStyle(iframeElement);
originalIframeStylesRef.current = { originalIframeStylesRef.current = {
@ -63,29 +71,27 @@ export function CallView({ room, eventId }: { room: Room; eventId?: string }) {
const hostRect = hostElement.getBoundingClientRect(); const hostRect = hostElement.getBoundingClientRect();
// Apply fixed positioning relative to the viewport, but aligned with the host
iframeElement.style.position = 'fixed'; iframeElement.style.position = 'fixed';
iframeElement.style.top = `${hostRect.top}px`; iframeElement.style.top = `${hostRect.top}px`;
iframeElement.style.left = `${hostRect.left}px`; iframeElement.style.left = `${hostRect.left}px`;
iframeElement.style.width = `${hostRect.width}px`; iframeElement.style.width = `${hostRect.width}px`;
iframeElement.style.height = `${hostRect.height}px`; iframeElement.style.height = `${hostRect.height}px`;
iframeElement.style.border = 'none'; iframeElement.style.border = 'none';
iframeElement.style.zIndex = '1000'; // Ensure it's on top iframeElement.style.zIndex = '1000';
iframeElement.style.display = 'block'; iframeElement.style.display = 'block';
iframeElement.style.visibility = 'visible'; iframeElement.style.visibility = 'visible';
iframeElement.style.pointerEvents = 'auto'; iframeElement.style.pointerEvents = 'auto';
} }
}, [iframeRef, iframeHostRef]); }, [activeIframeDisplayRef, iframeHostRef]);
const debouncedApplyFixedPositioning = useCallback(debounce(applyFixedPositioningToIframe, 50), [ const debouncedApplyFixedPositioning = useCallback(debounce(applyFixedPositioningToIframe, 50), [
applyFixedPositioningToIframe, applyFixedPositioningToIframe,
]); ]);
useEffect(() => { useEffect(() => {
const iframeElement = iframeRef?.current; const iframeElement = activeIframeDisplayRef?.current;
const hostElement = iframeHostRef?.current; const hostElement = iframeHostRef?.current;
if (shouldDisplayCallIFrame && iframeElement && hostElement) { if (isPrimaryIframe || (isViewingActiveCall && iframeElement && hostElement)) {
applyFixedPositioningToIframe(); applyFixedPositioningToIframe();
const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning); const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning);
@ -99,32 +105,30 @@ export function CallView({ room, eventId }: { room: Room; eventId?: string }) {
if (iframeElement && originalIframeStylesRef.current) { if (iframeElement && originalIframeStylesRef.current) {
const originalStyles = originalIframeStylesRef.current; const originalStyles = originalIframeStylesRef.current;
(Object.keys(originalStyles) as Array<keyof OriginalStyles>).forEach((key) => { (Object.keys(originalStyles) as Array<keyof OriginalStyles>).forEach((key) => {
iframeElement.style[key] = originalStyles[key] || ''; if (key in iframeElement.style) {
iframeElement.style[key as any] = originalStyles[key] || '';
}
}); });
} }
originalIframeStylesRef.current = null; originalIframeStylesRef.current = null;
}; };
} }
if (iframeElement && originalIframeStylesRef.current) {
const originalStyles = originalIframeStylesRef.current;
(Object.keys(originalStyles) as Array<keyof OriginalStyles>).forEach((key) => {
iframeElement.style[key] = originalStyles[key] || '';
});
originalIframeStylesRef.current = null;
}
}, [ }, [
shouldDisplayCallIFrame, activeIframeDisplayRef,
iframeRef,
applyFixedPositioningToIframe, applyFixedPositioningToIframe,
debouncedApplyFixedPositioning, debouncedApplyFixedPositioning,
isPrimaryIframe,
isViewingActiveCall,
]); ]);
const isCallViewVisible = room.isCallRoom();
return ( return (
<Box <Box
direction="Column" direction="Column"
style={{ style={{
width: '60%', width: '60%',
display: room.isCallRoom() ? 'flex' : 'none', display: isCallViewVisible ? 'flex' : 'none',
}} }}
> >
<RoomViewHeader /> <RoomViewHeader />