import { PARTICIPANT_LEFT } from '../base/participants/actionTypes'; import ReducerRegistry from '../base/redux/ReducerRegistry'; import { REMOVE_STAGE_PARTICIPANT, SET_STAGE_PARTICIPANTS, SET_FILMSTRIP_ENABLED, SET_FILMSTRIP_VISIBLE, SET_FILMSTRIP_WIDTH, SET_HORIZONTAL_VIEW_DIMENSIONS, SET_REMOTE_PARTICIPANTS, SET_STAGE_FILMSTRIP_DIMENSIONS, SET_TILE_VIEW_DIMENSIONS, SET_USER_FILMSTRIP_WIDTH, SET_USER_IS_RESIZING, SET_VERTICAL_VIEW_DIMENSIONS, SET_VISIBLE_REMOTE_PARTICIPANTS, SET_VOLUME, SET_MAX_STAGE_PARTICIPANTS, CLEAR_STAGE_PARTICIPANTS, SET_SCREENSHARING_TILE_DIMENSIONS, SET_USER_FILMSTRIP_HEIGHT, SET_FILMSTRIP_HEIGHT, SET_TOP_PANEL_VISIBILITY, SET_SCREENSHARE_FILMSTRIP_PARTICIPANT } from './actionTypes'; const DEFAULT_STATE = { /** * The list of participants to be displayed on the stage filmstrip. */ activeParticipants: [], /** * The indicator which determines whether the {@link Filmstrip} is enabled. * * @public * @type {boolean} */ enabled: true, /** * The horizontal view dimensions. * * @public * @type {Object} */ horizontalViewDimensions: {}, /** * Whether or not the user is actively resizing the filmstrip. * * @public * @type {boolean} */ isResizing: false, /** * The current max number of participants to be displayed on the stage filmstrip. * * @public * @type {Number} */ maxStageParticipants: 1, /** * The custom audio volume levels per participant. * * @type {Object} */ participantsVolume: {}, /** * The ordered IDs of the remote participants displayed in the filmstrip. * * @public * @type {Array} */ remoteParticipants: [], /** * The dimensions of the screenshare filmstrip. */ screenshareFilmstripDimensions: {}, /** * The id of the participant whose screenshare to * display on the screenshare filmstrip. */ screenshareFilmstripParticipantId: null, /** * The stage filmstrip view dimensions. * * @public * @type {Object} */ stageFilmstripDimensions: {}, /** * The tile view dimensions. * * @public * @type {Object} */ tileViewDimensions: {}, /** * The height of the resizable top panel. */ topPanelHeight: { /** * Current height. Affected by: user top panel resize, * window resize. */ current: null, /** * Height set by user resize. Used as the preferred height. */ userSet: null }, /** * The indicator determines if the top panel is visible. */ topPanelVisible: true, /** * The vertical view dimensions. * * @public * @type {Object} */ verticalViewDimensions: {}, /** * The indicator which determines whether the {@link Filmstrip} is visible. * * @public * @type {boolean} */ visible: true, /** * The end index in the remote participants array that is visible in the filmstrip. * * @public * @type {number} */ visibleParticipantsEndIndex: 0, /** * The start index in the remote participants array that is visible in the filmstrip. * * @public * @type {number} */ visibleParticipantsStartIndex: 0, /** * The visible remote participants in the filmstrip. * * @public * @type {Set} */ visibleRemoteParticipants: new Set(), /** * The width of the resizable filmstrip. * * @public * @type {Object} */ width: { /** * Current width. Affected by: user filmstrip resize, * window resize, panels open/ close. */ current: null, /** * Width set by user resize. Used as the preferred width. */ userSet: null } }; interface Dimensions { height: number; width: number; } interface FilmstripDimensions { filmstripHeight?: number; filmstripWidth?: number; gridDimensions?: { columns: number; rows: number; }; hasScroll?: boolean; thumbnailSize?: Dimensions; } export interface IFilmstripState { activeParticipants: Array<{ participantId: string; pinned?: boolean; }>; enabled: boolean; horizontalViewDimensions: { hasScroll?: boolean; local?: Dimensions; remote?: Dimensions; remoteVideosContainer?: Dimensions; }; isResizing: boolean; maxStageParticipants: number; participantsVolume: { [participantId: string]: number; }; remoteParticipants: string[]; screenshareFilmstripDimensions: { filmstripHeight?: number; filmstripWidth?: number; thumbnailSize?: Dimensions; }; screenshareFilmstripParticipantId?: string | null; stageFilmstripDimensions: FilmstripDimensions; tileViewDimensions?: FilmstripDimensions; topPanelHeight: { current: number | null; userSet: number | null; }; topPanelVisible: boolean; verticalViewDimensions: { gridView?: { gridDimensions: { columns: number; rows: number; }; hasScroll: boolean; thumbnailSize: Dimensions; }; hasScroll?: boolean; local?: Dimensions; remote?: Dimensions; remoteVideosContainer?: Dimensions; }; visible: boolean; visibleParticipantsEndIndex: number; visibleParticipantsStartIndex: number; visibleRemoteParticipants: Set; width: { current: number | null; userSet: number | null; }; } ReducerRegistry.register( 'features/filmstrip', (state = DEFAULT_STATE, action): IFilmstripState => { switch (action.type) { case SET_FILMSTRIP_ENABLED: return { ...state, enabled: action.enabled }; case SET_FILMSTRIP_VISIBLE: return { ...state, visible: action.visible }; case SET_HORIZONTAL_VIEW_DIMENSIONS: return { ...state, horizontalViewDimensions: action.dimensions }; case SET_REMOTE_PARTICIPANTS: { state.remoteParticipants = action.participants; const { visibleParticipantsStartIndex: startIndex, visibleParticipantsEndIndex: endIndex } = state; state.visibleRemoteParticipants = new Set(state.remoteParticipants.slice(startIndex, endIndex + 1)); return { ...state }; } case SET_TILE_VIEW_DIMENSIONS: return { ...state, tileViewDimensions: action.dimensions }; case SET_VERTICAL_VIEW_DIMENSIONS: return { ...state, verticalViewDimensions: action.dimensions }; case SET_VOLUME: return { ...state, participantsVolume: { ...state.participantsVolume, // NOTE: This would fit better in the features/base/participants. But currently we store // the participants as an array which will make it expensive to search for the volume for // every participant separately. [action.participantId]: action.volume } }; case SET_VISIBLE_REMOTE_PARTICIPANTS: { const { endIndex, startIndex } = action; const { remoteParticipants } = state; const visibleRemoteParticipants = new Set(remoteParticipants.slice(startIndex, endIndex + 1)); return { ...state, visibleParticipantsStartIndex: startIndex, visibleParticipantsEndIndex: endIndex, visibleRemoteParticipants }; } case PARTICIPANT_LEFT: { const { id, local } = action.participant; if (local) { return state; } delete state.participantsVolume[id]; return { ...state }; } case SET_FILMSTRIP_HEIGHT:{ return { ...state, topPanelHeight: { ...state.topPanelHeight, current: action.height } }; } case SET_FILMSTRIP_WIDTH: { return { ...state, width: { ...state.width, current: action.width } }; } case SET_USER_FILMSTRIP_HEIGHT: { const { height } = action; return { ...state, topPanelHeight: { current: height, userSet: height } }; } case SET_USER_FILMSTRIP_WIDTH: { const { width } = action; return { ...state, width: { current: width, userSet: width } }; } case SET_USER_IS_RESIZING: { return { ...state, isResizing: action.resizing }; } case SET_STAGE_FILMSTRIP_DIMENSIONS: { return { ...state, stageFilmstripDimensions: action.dimensions }; } case SET_STAGE_PARTICIPANTS: { return { ...state, activeParticipants: action.queue }; } case REMOVE_STAGE_PARTICIPANT: { return { ...state, activeParticipants: state.activeParticipants.filter(p => p.participantId !== action.participantId) }; } case SET_MAX_STAGE_PARTICIPANTS: { return { ...state, maxStageParticipants: action.maxParticipants }; } case CLEAR_STAGE_PARTICIPANTS: { return { ...state, activeParticipants: [] }; } case SET_SCREENSHARING_TILE_DIMENSIONS: { return { ...state, screenshareFilmstripDimensions: action.dimensions }; } case SET_TOP_PANEL_VISIBILITY: { return { ...state, topPanelVisible: action.visible }; } case SET_SCREENSHARE_FILMSTRIP_PARTICIPANT: { return { ...state, screenshareFilmstripParticipantId: action.participantId }; } } return state; });