fix(app-call): utilise popout window opened by manager (#2960)

This commit is contained in:
omster
2026-10-03 01:11:23 +02:00
committed by GitHub
parent 597116a0b4
commit a95172bf88
4 changed files with 16 additions and 9 deletions
@@ -36,6 +36,7 @@ interface PopoutWindowProps {
onRestore: () => void;
onClosed: (windowGeneration: number) => void;
onWindowOpened?: (childWindow: Window, windowGeneration: number) => void;
existingWindow?: Window | null;
children: React.ReactNode;
}
@@ -82,6 +83,7 @@ export const PopoutWindow: React.FC<PopoutWindowProps> = ({
onRestore,
onClosed,
onWindowOpened,
existingWindow,
children,
}) => {
const [childState, setChildState] = useState<PopoutChildState | null>(null);
@@ -89,11 +91,14 @@ export const PopoutWindow: React.FC<PopoutWindowProps> = ({
const onWindowOpenedRef = useRef(onWindowOpened);
const initialSizeRef = useRef({width, height});
const initialTitleRef = useRef(title);
const initialWindowRef = useRef(existingWindow);
onClosedRef.current = onClosed;
onWindowOpenedRef.current = onWindowOpened;
useEffect(() => {
const features = `width=${initialSizeRef.current.width},height=${initialSizeRef.current.height}`;
const childWindow = window.open('about:blank', windowKey, features);
const adoptedWindow = initialWindowRef.current;
const childWindow =
adoptedWindow && !adoptedWindow.closed ? adoptedWindow : window.open('about:blank', windowKey, features);
if (!childWindow) {
logger.warn('Failed to open popout window', {windowKey});
onClosedRef.current(windowGeneration);
@@ -92,6 +92,7 @@ const VoicePopoutWindowRenderer = observer(function VoicePopoutWindowRenderer({
onRestore={handleRestore}
onClosed={handleClosed}
onWindowOpened={handleWindowOpened}
existingWindow={PopoutWindowManager.getChildWindow(key)}
data-flx="voice.voice-popout-host.popout-window"
>
<VoicePopoutScopeContext.Provider value={descriptor.kind}>
@@ -830,6 +830,7 @@ class MediaEngineFacade extends Store {
ToastCommands.createToast({
type: 'info',
children: this.i18n._(RECONNECT_SUCCEEDED_PICK_A_SCREEN_AGAIN_IF_YOU_DESCRIPTOR),
timeout: 5000,
});
}
}
@@ -57,12 +57,6 @@ export function isVoicePopoutAlwaysOnTopSupported(): boolean {
return typeof getElectronAPI()?.popoutSetAlwaysOnTop === 'function';
}
interface PopoutChildWindow {
closed: boolean;
focus: () => void;
close: () => void;
}
interface AlwaysOnTopOperationState {
readonly descriptor: VoicePopoutDescriptor;
desired: boolean;
@@ -71,7 +65,7 @@ interface AlwaysOnTopOperationState {
class PopoutWindowManagerStore {
popouts: Record<string, VoicePopoutDescriptor> = {};
alwaysOnTopKeys: Record<string, true> = {};
private readonly childWindows = new Map<string, PopoutChildWindow>();
private readonly childWindows = new Map<string, Window>();
private readonly alwaysOnTopOperations = new Map<string, AlwaysOnTopOperationState>();
private nextPopoutGeneration = 1;
@@ -110,6 +104,12 @@ class PopoutWindowManagerStore {
return null;
}
getChildWindow(key: string): Window | null {
const childWindow = this.childWindows.get(key);
if (!childWindow || childWindow.closed) return null;
return childWindow;
}
isOpen(key: string): boolean {
return key in this.popouts;
}
@@ -148,7 +148,7 @@ class PopoutWindowManagerStore {
}
}
attachWindow(key: string, generation: number, childWindow: PopoutChildWindow | null): void {
attachWindow(key: string, generation: number, childWindow: Window | null): void {
if (!this.isCurrentPopout(key, generation)) return;
if (childWindow === null) {
this.childWindows.delete(key);