Up until now we relied on implicit loading of middlewares and reducers, through having imports in each feature's index.js. This leads to many complex import cycles which result in (sometimes) hard to fix bugs in addition to (often) breaking mobile because a web-only feature gets imported on mobile too, thanks to the implicit loading. This PR changes that to make the process explicit. Both middlewares and reducers are imported in a single place, the app entrypoint. They have been divided into 3 categories: any, web and native, which represent each of the platforms respectively. Ideally no feature should have an index.js exporting actions, action types and components, but that's a larger ordeal, so this is just the first step in getting there. In order to both set example and avoid large cycles the app feature has been refactored to not have an idex.js itself.
88 lines
2.7 KiB
JavaScript
88 lines
2.7 KiB
JavaScript
// @flow
|
|
|
|
import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
|
|
import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
|
|
import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
|
|
import { SCREEN_SHARE_PARTICIPANTS_UPDATED, SET_TILE_VIEW } from '../../video-layout/actionTypes';
|
|
import { SET_AUDIO_ONLY } from '../audio-only/actionTypes';
|
|
import { CONFERENCE_JOINED } from '../conference/actionTypes';
|
|
import { getParticipantById } from '../participants/functions';
|
|
import { MiddlewareRegistry } from '../redux';
|
|
|
|
import logger from './logger';
|
|
|
|
declare var APP: Object;
|
|
|
|
|
|
MiddlewareRegistry.register(store => next => action => {
|
|
const result = next(action);
|
|
|
|
switch (action.type) {
|
|
case APP_STATE_CHANGED:
|
|
case CONFERENCE_JOINED:
|
|
case SCREEN_SHARE_PARTICIPANTS_UPDATED:
|
|
case SELECT_LARGE_VIDEO_PARTICIPANT:
|
|
case SET_AUDIO_ONLY:
|
|
case SET_FILMSTRIP_ENABLED:
|
|
case SET_TILE_VIEW:
|
|
_updateLastN(store);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* Updates the last N value in the conference based on the current state of the redux store.
|
|
*
|
|
* @param {Store} store - The redux store.
|
|
* @private
|
|
* @returns {void}
|
|
*/
|
|
function _updateLastN({ getState }) {
|
|
const state = getState();
|
|
const { conference } = state['features/base/conference'];
|
|
const { enabled: audioOnly } = state['features/base/audio-only'];
|
|
const { appState } = state['features/background'] || {};
|
|
const { enabled: filmStripEnabled } = state['features/filmstrip'];
|
|
const config = state['features/base/config'];
|
|
|
|
if (!conference) {
|
|
logger.debug('There is no active conference, not updating last N');
|
|
|
|
return;
|
|
}
|
|
|
|
const defaultLastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
|
|
let lastN = defaultLastN;
|
|
|
|
if (typeof appState !== 'undefined' && appState !== 'active') {
|
|
lastN = 0;
|
|
} else if (audioOnly) {
|
|
const { screenShares, tileViewEnabled } = state['features/video-layout'];
|
|
const largeVideoParticipantId = state['features/large-video'].participantId;
|
|
const largeVideoParticipant
|
|
= largeVideoParticipantId ? getParticipantById(state, largeVideoParticipantId) : undefined;
|
|
|
|
if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) {
|
|
lastN = (screenShares || []).includes(largeVideoParticipantId) ? 1 : 0;
|
|
} else {
|
|
lastN = 0;
|
|
}
|
|
} else if (!filmStripEnabled) {
|
|
lastN = 1;
|
|
}
|
|
|
|
if (conference.getLastN() === lastN) {
|
|
return;
|
|
}
|
|
|
|
logger.info(`Setting last N to: ${lastN}`);
|
|
|
|
try {
|
|
conference.setLastN(lastN);
|
|
} catch (err) {
|
|
logger.error(`Failed to set lastN: ${err}`);
|
|
}
|
|
}
|