import { Room } from 'matrix-js-sdk'; import React, { useContext, useMemo } from 'react'; import { useCallback, useEffect, useRef } from 'react'; import { Box } from 'folds'; import { RoomViewHeader } from './RoomViewHeader'; import { useCallState } from '../../pages/client/CallProvider'; import { RefContext } from '../../pages/call/PersistentCallContainer'; import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize'; function debounce any>(func: F, waitFor: number) { let timeoutId: ReturnType | null = null; return (...args: Parameters): void => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => func(...args), waitFor); }; } type OriginalStyles = { position?: string; top?: string; left?: string; width?: string; height?: string; zIndex?: string; display?: string; visibility?: string; pointerEvents?: string; border?: string; }; interface CallViewOutletContext { iframeRef: React.RefObject; backupIframeRef: React.RefObject; } export function CallView({ room, eventId }: { room: Room; eventId?: string }) { const { iframeRef, backupIframeRef } = useContext(RefContext); const iframeHostRef = useRef(null); const originalIframeStylesRef = useRef(null); const { activeCallRoomId, isPrimaryIframe, isChatOpen } = useCallState(); const isViewingActiveCall = useMemo( () => activeCallRoomId !== null && activeCallRoomId === room.roomId, [activeCallRoomId] ); const screenSize = useScreenSizeContext(); const isMobile = screenSize === ScreenSize.Mobile; const activeIframeDisplayRef = !isPrimaryIframe || isViewingActiveCall ? iframeRef : backupIframeRef; const applyFixedPositioningToIframe = useCallback(() => { const iframeElement = activeIframeDisplayRef?.current; const hostElement = iframeHostRef?.current; if (iframeElement && hostElement) { if (!originalIframeStylesRef.current) { const computed = window.getComputedStyle(iframeElement); originalIframeStylesRef.current = { position: iframeElement.style.position || computed.position, top: iframeElement.style.top || computed.top, left: iframeElement.style.left || computed.left, width: iframeElement.style.width || computed.width, height: iframeElement.style.height || computed.height, zIndex: iframeElement.style.zIndex || computed.zIndex, display: iframeElement.style.display || computed.display, visibility: iframeElement.style.visibility || computed.visibility, pointerEvents: iframeElement.style.pointerEvents || computed.pointerEvents, border: iframeElement.style.border || computed.border, }; } const hostRect = hostElement.getBoundingClientRect(); iframeElement.style.position = 'fixed'; iframeElement.style.top = `${hostRect.top}px`; iframeElement.style.left = `${hostRect.left}px`; iframeElement.style.width = `${hostRect.width}px`; iframeElement.style.height = `${hostRect.height}px`; iframeElement.style.border = 'none'; iframeElement.style.zIndex = '1000'; iframeElement.style.display = room.isCallRoom() ? 'block' : 'none'; iframeElement.style.visibility = 'visible'; iframeElement.style.pointerEvents = 'auto'; } }, [activeIframeDisplayRef, iframeHostRef]); const debouncedApplyFixedPositioning = useCallback(debounce(applyFixedPositioningToIframe, 50), [ applyFixedPositioningToIframe, ]); useEffect(() => { const iframeElement = activeIframeDisplayRef?.current; const hostElement = iframeHostRef?.current; if (isPrimaryIframe || (isViewingActiveCall && iframeElement && hostElement)) { applyFixedPositioningToIframe(); const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning); resizeObserver.observe(hostElement); window.addEventListener('scroll', debouncedApplyFixedPositioning, true); return () => { resizeObserver.disconnect(); window.removeEventListener('scroll', debouncedApplyFixedPositioning, true); if (iframeElement && originalIframeStylesRef.current) { const originalStyles = originalIframeStylesRef.current; (Object.keys(originalStyles) as Array).forEach((key) => { if (key in iframeElement.style) { iframeElement.style[key as any] = originalStyles[key] || ''; } }); } originalIframeStylesRef.current = null; }; } }, [ activeIframeDisplayRef, applyFixedPositioningToIframe, debouncedApplyFixedPositioning, isPrimaryIframe, isViewingActiveCall, ]); const isCallViewVisible = room.isCallRoom(); return (
); }