snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
This commit is contained in:
93
react/features/multi-screen/middleware.web.ts
Normal file
93
react/features/multi-screen/middleware.web.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
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);
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user