2025-05-08 17:57:57 -05:00
|
|
|
import { Room } from 'matrix-js-sdk';
|
2025-05-23 00:01:19 -05:00
|
|
|
import React, { useContext, useMemo, useCallback, useEffect, useRef } from 'react';
|
2025-05-08 17:57:57 -05:00
|
|
|
import { Box } from 'folds';
|
2025-05-22 19:57:40 -05:00
|
|
|
import { useCallState } from '../../pages/client/call/CallProvider';
|
|
|
|
|
import {
|
|
|
|
|
PrimaryRefContext,
|
|
|
|
|
BackupRefContext,
|
|
|
|
|
} from '../../pages/client/call/PersistentCallContainer';
|
2025-05-10 08:58:03 -05:00
|
|
|
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
2025-07-31 21:05:15 +02:00
|
|
|
import { useDebounce } from '../../hooks/useDebounce';
|
2025-05-08 17:57:57 -05:00
|
|
|
|
|
|
|
|
type OriginalStyles = {
|
|
|
|
|
position?: string;
|
|
|
|
|
top?: string;
|
|
|
|
|
left?: string;
|
|
|
|
|
width?: string;
|
|
|
|
|
height?: string;
|
|
|
|
|
zIndex?: string;
|
|
|
|
|
display?: string;
|
|
|
|
|
visibility?: string;
|
|
|
|
|
pointerEvents?: string;
|
|
|
|
|
border?: string;
|
|
|
|
|
};
|
|
|
|
|
|
2025-06-18 17:26:57 -05:00
|
|
|
export function CallView({ room }: { room: Room }) {
|
2025-05-10 20:41:06 -05:00
|
|
|
const primaryIframeRef = useContext(PrimaryRefContext);
|
|
|
|
|
const backupIframeRef = useContext(BackupRefContext);
|
2025-05-08 17:57:57 -05:00
|
|
|
const iframeHostRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
const originalIframeStylesRef = useRef<OriginalStyles | null>(null);
|
2025-05-10 08:58:03 -05:00
|
|
|
const { activeCallRoomId, isPrimaryIframe, isChatOpen } = useCallState();
|
2025-05-09 09:38:43 -05:00
|
|
|
const isViewingActiveCall = useMemo(
|
|
|
|
|
() => activeCallRoomId !== null && activeCallRoomId === room.roomId,
|
2025-05-10 20:41:06 -05:00
|
|
|
[activeCallRoomId, room.roomId]
|
2025-05-09 09:38:43 -05:00
|
|
|
);
|
2025-05-08 17:57:57 -05:00
|
|
|
|
2025-05-10 08:58:03 -05:00
|
|
|
const screenSize = useScreenSizeContext();
|
2025-07-31 21:05:15 +02:00
|
|
|
/* eslint-disable-next-line no-nested-ternary */
|
2025-05-22 19:42:46 -05:00
|
|
|
const activeIframeDisplayRef = isPrimaryIframe
|
|
|
|
|
? isViewingActiveCall
|
|
|
|
|
? primaryIframeRef
|
|
|
|
|
: backupIframeRef
|
|
|
|
|
: isViewingActiveCall
|
|
|
|
|
? backupIframeRef
|
|
|
|
|
: primaryIframeRef;
|
2025-05-08 17:57:57 -05:00
|
|
|
|
|
|
|
|
const applyFixedPositioningToIframe = useCallback(() => {
|
2025-05-09 09:38:43 -05:00
|
|
|
const iframeElement = activeIframeDisplayRef?.current;
|
2025-05-08 17:57:57 -05:00
|
|
|
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';
|
2025-05-09 09:38:43 -05:00
|
|
|
iframeElement.style.zIndex = '1000';
|
2025-05-09 14:17:25 -05:00
|
|
|
iframeElement.style.display = room.isCallRoom() ? 'block' : 'none';
|
2025-05-08 17:57:57 -05:00
|
|
|
iframeElement.style.visibility = 'visible';
|
|
|
|
|
iframeElement.style.pointerEvents = 'auto';
|
|
|
|
|
}
|
2025-05-10 20:41:06 -05:00
|
|
|
}, [activeIframeDisplayRef, room]);
|
2025-05-08 17:57:57 -05:00
|
|
|
|
2025-07-31 21:05:15 +02:00
|
|
|
const debouncedApplyFixedPositioning = useDebounce(applyFixedPositioningToIframe, {
|
|
|
|
|
wait: 50,
|
|
|
|
|
immediate: false,
|
|
|
|
|
});
|
2025-05-08 17:57:57 -05:00
|
|
|
useEffect(() => {
|
2025-05-09 09:38:43 -05:00
|
|
|
const iframeElement = activeIframeDisplayRef?.current;
|
2025-05-08 17:57:57 -05:00
|
|
|
const hostElement = iframeHostRef?.current;
|
|
|
|
|
|
2025-05-11 17:54:11 -05:00
|
|
|
if (room.isCallRoom() || (isViewingActiveCall && iframeElement && hostElement)) {
|
2025-05-08 17:57:57 -05:00
|
|
|
applyFixedPositioningToIframe();
|
|
|
|
|
|
|
|
|
|
const resizeObserver = new ResizeObserver(debouncedApplyFixedPositioning);
|
2025-07-31 21:05:15 +02:00
|
|
|
if (hostElement) resizeObserver.observe(hostElement);
|
2025-05-08 17:57:57 -05:00
|
|
|
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<keyof OriginalStyles>).forEach((key) => {
|
2025-05-09 09:38:43 -05:00
|
|
|
if (key in iframeElement.style) {
|
|
|
|
|
iframeElement.style[key as any] = originalStyles[key] || '';
|
|
|
|
|
}
|
2025-05-08 17:57:57 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
originalIframeStylesRef.current = null;
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-07-31 21:05:15 +02:00
|
|
|
|
|
|
|
|
return undefined;
|
2025-05-22 19:57:40 -05:00
|
|
|
}, [
|
|
|
|
|
activeIframeDisplayRef,
|
|
|
|
|
applyFixedPositioningToIframe,
|
|
|
|
|
debouncedApplyFixedPositioning,
|
|
|
|
|
isPrimaryIframe,
|
|
|
|
|
isViewingActiveCall,
|
|
|
|
|
room,
|
|
|
|
|
]);
|
2025-05-08 17:57:57 -05:00
|
|
|
|
2025-07-31 21:05:15 +02:00
|
|
|
const isCallViewVisible = room.isCallRoom() && (screenSize === ScreenSize.Desktop || !isChatOpen);
|
2025-05-09 09:38:43 -05:00
|
|
|
|
2025-05-08 17:57:57 -05:00
|
|
|
return (
|
2025-07-31 21:05:15 +02:00
|
|
|
<Box grow="Yes" direction="Column" style={{ display: isCallViewVisible ? 'flex' : 'none' }}>
|
2025-05-08 17:57:57 -05:00
|
|
|
<div
|
|
|
|
|
ref={iframeHostRef}
|
|
|
|
|
style={{
|
|
|
|
|
width: '100%',
|
|
|
|
|
height: '100%',
|
|
|
|
|
position: 'relative',
|
|
|
|
|
pointerEvents: 'none',
|
2025-07-31 21:05:15 +02:00
|
|
|
display: 'flex',
|
2025-05-08 17:57:57 -05:00
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
);
|
|
|
|
|
}
|