Files
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

94 lines
3.4 KiB
TypeScript

import { IStore } from '../app/types';
import { CONFERENCE_FAILED, CONFERENCE_JOINED, CONFERENCE_LEFT } from '../base/conference/actionTypes';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { REMOVE_SECOND_SCREEN, RESET_SECOND_SCREENS, SET_SECOND_SCREEN } from './actionTypes';
import { resetSecondScreens } from './actions.web';
import {
closeAllSecondScreens,
closeSecondScreenHandle,
getHandle,
handleSecondScreenOpenError,
isSecondScreenEnabled,
openOrUpdateSecondScreen,
preloadScreenDetails
} from './functions.web';
import './subscriber.web';
/**
* Middleware that reconciles the live second-screen windows with the requested
* state, tears them all down when the conference ends, and closes any that are
* still open when the main window itself goes away.
*
* @param {IStore} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register((store: IStore) => {
// Close every second-screen window when the main window goes away (tab closed,
// reloaded, or navigated away). The CONFERENCE_LEFT/FAILED path below only
// covers leaving the meeting from within the app; closing the main window
// directly dispatches neither, so without this the popups are orphaned on the
// second display. Closing from an unloading opener is best-effort. Skip
// event.persisted (bfcache eviction): the page may be restored via pageshow
// with the second screens still expected, so only tear down on a real unload.
window.addEventListener('pagehide', (event: PageTransitionEvent) => {
if (!event.persisted) {
closeAllSecondScreens(store);
}
});
return next => action => {
switch (action.type) {
case SET_SECOND_SCREEN: {
const result = next(action);
openOrUpdateSecondScreen(store, action.id, action.screenId)
.catch(e => handleSecondScreenOpenError(store, action.id, e));
return result;
}
case REMOVE_SECOND_SCREEN: {
// Capture the handle, then remove the entry first so the portal unmounts
// (stopping its cloned track) while the window is still open; only then
// close the window.
const handle = getHandle(store.getState(), action.id);
const result = next(action);
closeSecondScreenHandle(handle, action.id);
return result;
}
case RESET_SECOND_SCREENS:
// Same ordering: close the windows while their entries are still in state.
closeAllSecondScreens(store);
return next(action);
case CONFERENCE_JOINED: {
const result = next(action);
// Warm the screen details so an in-app trigger can open its window
// without awaiting, which is what keeps the click's user activation
// (see openOrUpdateSecondScreen). Never prompts on its own.
if (isSecondScreenEnabled(store.getState())) {
preloadScreenDetails();
}
return result;
}
case CONFERENCE_FAILED:
case CONFERENCE_LEFT:
// Resetting closes every second-screen window (via the RESET_SECOND_SCREENS
// case above), so there is no need to close them explicitly here.
store.dispatch(resetSecondScreens());
break;
}
return next(action);
};
});