fix(voice): release call modals when fullscreen ends (#3149)

This commit is contained in:
Hampus
2026-10-03 02:13:46 +02:00
committed by GitHub
parent d6fb3b2c50
commit cf9752db4f
3 changed files with 27 additions and 10 deletions
@@ -134,6 +134,13 @@ class ModalState {
}; };
} }
releasePortalHost(host: HTMLElement): void {
if (!this.modals.some((modal) => modal.portalHost === host)) return;
this.modals = this.modals.map((modal) =>
modal.portalHost === host ? {...modal, portalHost: null, ownerDocument: this.resolveOwnerDocument(null)} : modal,
);
}
pop(key?: string | number, ownerDocument?: Document): void { pop(key?: string | number, ownerDocument?: Document): void {
let removed: ModalEntry | undefined; let removed: ModalEntry | undefined;
let wasTopmost = false; let wasTopmost = false;
@@ -20,7 +20,7 @@ import {BottomSheet} from '@app/features/ui/bottom_sheet/BottomSheet';
import * as ToastCommands from '@app/features/ui/commands/ToastCommands'; import * as ToastCommands from '@app/features/ui/commands/ToastCommands';
import FocusRing from '@app/features/ui/focus_ring/FocusRing'; import FocusRing from '@app/features/ui/focus_ring/FocusRing';
import {usePopout} from '@app/features/ui/hooks/usePopout'; import {usePopout} from '@app/features/ui/hooks/usePopout';
import {PortalHostContext, setActivePortalHost} from '@app/features/ui/overlay/PortalHostContext'; import {PortalHostContext} from '@app/features/ui/overlay/PortalHostContext';
import {Popout as PopoverPopout} from '@app/features/ui/popover/PopoverPopout'; import {Popout as PopoverPopout} from '@app/features/ui/popover/PopoverPopout';
import ContextMenu, {isContextMenuNodeTarget} from '@app/features/ui/state/ContextMenu'; import ContextMenu, {isContextMenuNodeTarget} from '@app/features/ui/state/ContextMenu';
import KeyboardMode from '@app/features/ui/state/KeyboardMode'; import KeyboardMode from '@app/features/ui/state/KeyboardMode';
@@ -40,7 +40,10 @@ import {StreamFocusHeaderInfo} from '@app/features/voice/components/StreamFocusH
import {getStreamKey} from '@app/features/voice/components/StreamKeys'; import {getStreamKey} from '@app/features/voice/components/StreamKeys';
import {useStreamSpectators} from '@app/features/voice/components/useStreamSpectators'; import {useStreamSpectators} from '@app/features/voice/components/useStreamSpectators';
import {useStreamTrackInfo} from '@app/features/voice/components/useStreamTrackInfo'; import {useStreamTrackInfo} from '@app/features/voice/components/useStreamTrackInfo';
import {useVoiceCallAppFullscreen} from '@app/features/voice/components/useVoiceCallAppFullscreen'; import {
useVoiceCallAppFullscreen,
useVoiceCallFullscreenPortalHost,
} from '@app/features/voice/components/useVoiceCallAppFullscreen';
import {useVoiceCallTracksAndLayout} from '@app/features/voice/components/useVoiceCallTracksAndLayout'; import {useVoiceCallTracksAndLayout} from '@app/features/voice/components/useVoiceCallTracksAndLayout';
import {useVoiceEngineConnectionState} from '@app/features/voice/components/useVoiceEngineConnectionState'; import {useVoiceEngineConnectionState} from '@app/features/voice/components/useVoiceEngineConnectionState';
import {VoiceCallCornerControls} from '@app/features/voice/components/VoiceCallCornerControls'; import {VoiceCallCornerControls} from '@app/features/voice/components/VoiceCallCornerControls';
@@ -422,14 +425,7 @@ const VoiceCallViewInner = observer(
}, [enterVoiceCallAppFullscreen, fullscreenRequestNonce]); }, [enterVoiceCallAppFullscreen, fullscreenRequestNonce]);
const inheritedPortalHost = useContext(PortalHostContext); const inheritedPortalHost = useContext(PortalHostContext);
const effectivePortalHost = isVoiceCallAppFullscreen || inPopout ? portalHost : null; const effectivePortalHost = isVoiceCallAppFullscreen || inPopout ? portalHost : null;
useEffect(() => { useVoiceCallFullscreenPortalHost(isVoiceCallAppFullscreen, effectivePortalHost);
if (!isVoiceCallAppFullscreen) return;
if (!effectivePortalHost) return;
setActivePortalHost(effectivePortalHost);
return () => {
setActivePortalHost(null);
};
}, [isVoiceCallAppFullscreen, effectivePortalHost]);
const FavoriteIcon = useMemo(() => { const FavoriteIcon = useMemo(() => {
const Icon = forwardRef<SVGSVGElement, React.ComponentProps<typeof StarIcon>>((props, ref) => ( const Icon = forwardRef<SVGSVGElement, React.ComponentProps<typeof StarIcon>>((props, ref) => (
<StarIcon <StarIcon
@@ -7,6 +7,8 @@ import {
supportsWebkitRequestFullscreen, supportsWebkitRequestFullscreen,
} from '@app/features/platform/types/Browser'; } from '@app/features/platform/types/Browser';
import {Logger} from '@app/features/platform/utils/AppLogger'; import {Logger} from '@app/features/platform/utils/AppLogger';
import {setActivePortalHost} from '@app/features/ui/overlay/PortalHostContext';
import Modal from '@app/features/ui/state/Modal';
import {VOICE_CALL_FULLSCREEN_ENABLED} from '@app/features/voice/components/VoiceCallFullscreenFeatureFlag'; import {VOICE_CALL_FULLSCREEN_ENABLED} from '@app/features/voice/components/VoiceCallFullscreenFeatureFlag';
import VoiceCallFullscreen from '@app/features/voice/state/VoiceCallFullscreen'; import VoiceCallFullscreen from '@app/features/voice/state/VoiceCallFullscreen';
import type {ExtendedHTMLElement} from '@app/types/browser.d'; import type {ExtendedHTMLElement} from '@app/types/browser.d';
@@ -192,6 +194,18 @@ export function useVoiceCallAppFullscreen(options: UseVoiceCallAppFullscreenOpti
}; };
} }
export function useVoiceCallFullscreenPortalHost(active: boolean, host: HTMLElement | null): void {
useEffect(() => {
if (!active) return;
if (!host) return;
setActivePortalHost(host);
return () => {
setActivePortalHost(null);
Modal.releasePortalHost(host);
};
}, [active, host]);
}
interface UseVoiceCallFullscreenViewStateOptions { interface UseVoiceCallFullscreenViewStateOptions {
active: boolean; active: boolean;
scopeKey: string; scopeKey: string;