import { useEffect, useLayoutEffect, useRef, useState } from "react"; import Actions from "../../components/actions"; import TopBar from "../../components/top"; import { setCallIsFullscreen, setScreenRef, triggerCallLayoutCalculation, useCall, } from "../../store"; export default function Layout({ children }: { children: React.ReactNode }) { const screenRef = useRef(null); const topBarRef = useRef(null); const actionsRef = useRef(null); const hideChromeTimeoutRef = useRef | null>( null, ); const [overlayInsets, setOverlayInsets] = useState({ top: 0, bottom: 0 }); const [isImmersiveChromeVisible, setIsImmersiveChromeVisible] = useState(false); useEffect(() => { setScreenRef(screenRef); const screen = screenRef.current; const fullscreenDocument = screen?.ownerDocument; if (!screen || !fullscreenDocument) { return; } const handleFullscreenChange = () => { setCallIsFullscreen(fullscreenDocument.fullscreenElement === screen); triggerCallLayoutCalculation(); }; fullscreenDocument.addEventListener( "fullscreenchange", handleFullscreenChange, ); return () => { fullscreenDocument.removeEventListener( "fullscreenchange", handleFullscreenChange, ); }; }, []); const usersInFocusedViewHidden = useCall( (state) => state.usersInFocusedViewHidden, ); const view = useCall((state) => state.view); const callIsFullscreen = useCall((state) => state.callIsFullscreen); const isImmersiveFocusedView = callIsFullscreen && view === "focused" && usersInFocusedViewHidden; const immersiveChromeVisible = isImmersiveFocusedView && isImmersiveChromeVisible; useEffect(() => { if (!isImmersiveFocusedView) { if (hideChromeTimeoutRef.current) { clearTimeout(hideChromeTimeoutRef.current); hideChromeTimeoutRef.current = null; } } }, [isImmersiveFocusedView]); useEffect(() => { return () => { if (hideChromeTimeoutRef.current) { clearTimeout(hideChromeTimeoutRef.current); } }; }, []); useLayoutEffect(() => { const topBar = topBarRef.current; const actions = actionsRef.current; if (!topBar || !actions) { return; } const syncOverlayInsets = () => { setOverlayInsets({ top: Math.ceil(topBar.getBoundingClientRect().height), bottom: Math.ceil(actions.getBoundingClientRect().height), }); }; syncOverlayInsets(); const observer = new ResizeObserver(syncOverlayInsets); observer.observe(topBar); observer.observe(actions); return () => { observer.disconnect(); }; }, []); const scheduleChromeHide = () => { if (hideChromeTimeoutRef.current) { clearTimeout(hideChromeTimeoutRef.current); } hideChromeTimeoutRef.current = setTimeout(() => { setIsImmersiveChromeVisible(false); hideChromeTimeoutRef.current = null; }, 3000); }; const showImmersiveChrome = () => { if (!isImmersiveFocusedView) { return; } setIsImmersiveChromeVisible(true); scheduleChromeHide(); }; const hideImmersiveChrome = () => { if (hideChromeTimeoutRef.current) { clearTimeout(hideChromeTimeoutRef.current); hideChromeTimeoutRef.current = null; } setIsImmersiveChromeVisible(false); }; return (
{children}
); }