import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useSetAtom } from 'jotai'; import { Box, Button, Icon, Icons, Text, config, toRem } from 'folds'; import { CallEmbed } from '../../plugins/call'; import { CallControls } from './CallControls'; import { callChatAtom } from '../../state/callEmbed'; import { CONTROLS_AUTOHIDE_MS, wantsBrowserFullscreen } from './landscapeCall'; const isStandalone = (): boolean => window.matchMedia?.('(display-mode: standalone)').matches || (navigator as { standalone?: boolean }).standalone === true; /** * [Gitea #126] Full-screen call controls. Taps inside the call frame never * reach us, so while the controls are hidden a transparent layer covers the * call: the first tap shows them (and is otherwise swallowed, as in native * video apps); with them up the layer is gone, so the call stays usable. They * hide again after a few seconds without a touch. The first tap in an Android * browser tab also enters the browser's own full screen (hides the address * bar); it is left again when this unmounts (rotate back, hang up, exit). */ export function ImmersiveCallOverlay({ callEmbed, onExit, }: { callEmbed: CallEmbed; onExit: () => void; }) { const [shown, setShown] = useState(false); const timer = useRef(undefined); const enteredFullscreen = useRef(false); const setChat = useSetAtom(callChatAtom); const armHide = useCallback(() => { window.clearTimeout(timer.current); timer.current = window.setTimeout(() => setShown(false), CONTROLS_AUTOHIDE_MS); }, []); useEffect( () => () => { window.clearTimeout(timer.current); if (enteredFullscreen.current && document.fullscreenElement === document.documentElement) { document.exitFullscreen().catch(() => undefined); } }, [], ); const reveal = () => { if ( wantsBrowserFullscreen({ userAgent: navigator.userAgent, standalone: isStandalone(), fullscreenEnabled: !!document.fullscreenEnabled, alreadyFullscreen: !!document.fullscreenElement, }) ) { document.documentElement .requestFullscreen({ navigationUI: 'hide' }) .then(() => { enteredFullscreen.current = true; }) .catch(() => undefined); } setShown(true); armHide(); }; if (!shown) { return (
(e.key === 'Enter' || e.key === ' ') && reveal()} style={{ position: 'absolute', inset: 0, pointerEvents: 'auto' }} /> ); } return ( ); }