jiti-meet/react/features/filmstrip/actions.web.js

493 lines
16 KiB
JavaScript

// @flow
import type { Dispatch } from 'redux';
import { getSourceNameSignalingFeatureFlag } from '../base/config';
import {
getLocalParticipant,
getParticipantById,
getRemoteParticipantCount,
pinParticipant
} from '../base/participants';
import { shouldHideSelfView } from '../base/settings/functions.any';
import { getMaxColumnCount } from '../video-layout';
import {
ADD_STAGE_PARTICIPANT,
REMOVE_STAGE_PARTICIPANT,
SET_STAGE_PARTICIPANTS,
SET_FILMSTRIP_WIDTH,
SET_HORIZONTAL_VIEW_DIMENSIONS,
SET_STAGE_FILMSTRIP_DIMENSIONS,
SET_TILE_VIEW_DIMENSIONS,
SET_USER_FILMSTRIP_WIDTH,
SET_USER_IS_RESIZING,
SET_VERTICAL_VIEW_DIMENSIONS,
SET_VOLUME,
SET_MAX_STAGE_PARTICIPANTS,
TOGGLE_PIN_STAGE_PARTICIPANT,
CLEAR_STAGE_PARTICIPANTS
} from './actionTypes';
import {
HORIZONTAL_FILMSTRIP_MARGIN,
MAX_ACTIVE_PARTICIPANTS,
SCROLL_SIZE,
STAGE_VIEW_THUMBNAIL_VERTICAL_BORDER,
TILE_HORIZONTAL_MARGIN,
TILE_VERTICAL_CONTAINER_HORIZONTAL_MARGIN,
TILE_VERTICAL_MARGIN,
TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES,
TILE_VIEW_GRID_HORIZONTAL_MARGIN,
TILE_VIEW_GRID_VERTICAL_MARGIN,
VERTICAL_FILMSTRIP_VERTICAL_MARGIN
} from './constants';
import {
calculateNonResponsiveTileViewDimensions,
calculateResponsiveTileViewDimensions,
calculateThumbnailSizeForHorizontalView,
calculateThumbnailSizeForVerticalView,
getNumberOfPartipantsForTileView,
getVerticalViewMaxWidth,
isFilmstripResizable,
showGridInVerticalView
} from './functions';
import { isStageFilmstripAvailable } from './functions.web';
export * from './actions.any';
/**
* Sets the dimensions of the tile view grid.
*
* @returns {Function}
*/
export function setTileViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState();
const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
const {
disableResponsiveTiles,
disableTileEnlargement,
tileView = {}
} = state['features/base/config'];
const { numberOfVisibleTiles = TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES } = tileView;
const numberOfParticipants = getNumberOfPartipantsForTileView(state);
const maxColumns = getMaxColumnCount(state);
const {
height,
width,
columns,
rows
} = disableResponsiveTiles
? calculateNonResponsiveTileViewDimensions(state)
: calculateResponsiveTileViewDimensions({
clientWidth,
clientHeight,
disableTileEnlargement,
maxColumns,
numberOfParticipants,
desiredNumberOfVisibleTiles: numberOfVisibleTiles
});
const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height);
const availableHeight = clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN;
const hasScroll = availableHeight < thumbnailsTotalHeight;
const filmstripWidth
= Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, columns * (TILE_HORIZONTAL_MARGIN + width))
+ (hasScroll ? SCROLL_SIZE : 0);
const filmstripHeight = Math.min(availableHeight, thumbnailsTotalHeight);
dispatch({
type: SET_TILE_VIEW_DIMENSIONS,
dimensions: {
gridDimensions: {
columns,
rows
},
thumbnailSize: {
height,
width
},
filmstripHeight,
filmstripWidth,
hasScroll
}
});
};
}
/**
* Sets the dimensions of the thumbnails in vertical view.
*
* @returns {Function}
*/
export function setVerticalViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState();
const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui'];
const { width: filmstripWidth } = state['features/filmstrip'];
const disableSelfView = shouldHideSelfView(state);
const resizableFilmstrip = isFilmstripResizable(state);
const _verticalViewGrid = showGridInVerticalView(state);
const numberOfRemoteParticipants = getRemoteParticipantCount(state);
const { localScreenShare } = state['features/base/participants'];
let gridView = {};
let thumbnails = {};
let filmstripDimensions = {};
let hasScroll = false;
let remoteVideosContainerWidth;
let remoteVideosContainerHeight;
// grid view in the vertical filmstrip
if (_verticalViewGrid) {
const { tileView = {} } = state['features/base/config'];
const { numberOfVisibleTiles = TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES } = tileView;
const numberOfParticipants = getNumberOfPartipantsForTileView(state);
const maxColumns = getMaxColumnCount(state, {
width: filmstripWidth.current,
disableResponsiveTiles: false,
disableTileEnlargement: false
});
const {
height,
width,
columns,
rows
} = calculateResponsiveTileViewDimensions({
clientWidth: filmstripWidth.current,
clientHeight,
disableTileEnlargement: false,
maxColumns,
noHorizontalContainerMargin: true,
numberOfParticipants,
desiredNumberOfVisibleTiles: numberOfVisibleTiles
});
const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height);
hasScroll = clientHeight < thumbnailsTotalHeight;
const widthOfFilmstrip = (columns * (TILE_HORIZONTAL_MARGIN + width)) + (hasScroll ? SCROLL_SIZE : 0);
const filmstripHeight = Math.min(clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN, thumbnailsTotalHeight);
gridView = {
gridDimensions: {
columns,
rows
},
thumbnailSize: {
height,
width
},
hasScroll
};
filmstripDimensions = {
height: filmstripHeight,
width: widthOfFilmstrip
};
} else {
thumbnails = calculateThumbnailSizeForVerticalView(clientWidth, filmstripWidth.current, resizableFilmstrip);
remoteVideosContainerWidth
= thumbnails?.local?.width + TILE_VERTICAL_CONTAINER_HORIZONTAL_MARGIN + SCROLL_SIZE;
remoteVideosContainerHeight
= clientHeight - (disableSelfView ? 0 : thumbnails?.local?.height) - VERTICAL_FILMSTRIP_VERTICAL_MARGIN;
if (getSourceNameSignalingFeatureFlag(state)) {
// Account for the height of the local screen share thumbnail when calculating the height of the remote
// videos container.
const localCameraThumbnailHeight = thumbnails?.local?.height;
const localScreenShareThumbnailHeight
= localScreenShare && !disableSelfView ? thumbnails?.local?.height : 0;
remoteVideosContainerHeight = clientHeight
- localCameraThumbnailHeight
- localScreenShareThumbnailHeight
- VERTICAL_FILMSTRIP_VERTICAL_MARGIN;
}
hasScroll
= remoteVideosContainerHeight
< (thumbnails?.remote.height + TILE_VERTICAL_MARGIN) * numberOfRemoteParticipants;
}
dispatch({
type: SET_VERTICAL_VIEW_DIMENSIONS,
dimensions: {
...thumbnails,
remoteVideosContainer: _verticalViewGrid ? filmstripDimensions : {
width: remoteVideosContainerWidth,
height: remoteVideosContainerHeight
},
gridView,
hasScroll
}
});
};
}
/**
* Sets the dimensions of the thumbnails in horizontal view.
*
* @returns {Function}
*/
export function setHorizontalViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState();
const { clientHeight = 0, clientWidth = 0 } = state['features/base/responsive-ui'];
const disableSelfView = shouldHideSelfView(state);
const thumbnails = calculateThumbnailSizeForHorizontalView(clientHeight);
const remoteVideosContainerWidth
= clientWidth - (disableSelfView ? 0 : thumbnails?.local?.width) - HORIZONTAL_FILMSTRIP_MARGIN;
const remoteVideosContainerHeight
= thumbnails?.local?.height + TILE_VERTICAL_MARGIN + STAGE_VIEW_THUMBNAIL_VERTICAL_BORDER + SCROLL_SIZE;
const numberOfRemoteParticipants = getRemoteParticipantCount(state);
const hasScroll
= remoteVideosContainerHeight
< (thumbnails?.remote.width + TILE_HORIZONTAL_MARGIN) * numberOfRemoteParticipants;
dispatch({
type: SET_HORIZONTAL_VIEW_DIMENSIONS,
dimensions: {
...thumbnails,
remoteVideosContainer: {
width: remoteVideosContainerWidth,
height: remoteVideosContainerHeight
},
hasScroll
}
});
};
}
/**
* Sets the dimensions of the stage filmstrip tile view grid.
*
* @returns {Function}
*/
export function setStageFilmstripViewDimensions() {
return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState();
const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
const {
tileView = {}
} = state['features/base/config'];
const { visible } = state['features/filmstrip'];
const verticalWidth = visible ? getVerticalViewMaxWidth(state) : 0;
const { numberOfVisibleTiles = MAX_ACTIVE_PARTICIPANTS } = tileView;
const numberOfParticipants = state['features/filmstrip'].activeParticipants.length;
const availableWidth = clientWidth - verticalWidth;
const maxColumns = getMaxColumnCount(state, {
width: availableWidth,
disableResponsiveTiles: false,
disableTileEnlargement: false
});
const {
height,
width,
columns,
rows
} = calculateResponsiveTileViewDimensions({
clientWidth: availableWidth,
clientHeight,
disableTileEnlargement: false,
maxColumns,
noHorizontalContainerMargin: verticalWidth > 0,
numberOfParticipants,
numberOfVisibleTiles
});
const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height);
const hasScroll = clientHeight < thumbnailsTotalHeight;
const filmstripWidth
= Math.min(clientWidth - TILE_VIEW_GRID_HORIZONTAL_MARGIN, columns * (TILE_HORIZONTAL_MARGIN + width))
+ (hasScroll ? SCROLL_SIZE : 0);
const filmstripHeight = Math.min(clientHeight - TILE_VIEW_GRID_VERTICAL_MARGIN, thumbnailsTotalHeight);
dispatch({
type: SET_STAGE_FILMSTRIP_DIMENSIONS,
dimensions: {
gridDimensions: {
columns,
rows
},
thumbnailSize: {
height,
width
},
filmstripHeight,
filmstripWidth,
hasScroll
}
});
};
}
/**
* Emulates a click on the n-th video.
*
* @param {number} n - Number that identifies the video.
* @returns {Function}
*/
export function clickOnVideo(n: number) {
return (dispatch: Function, getState: Function) => {
const state = getState();
const { id: localId } = getLocalParticipant(state);
// Use the list that correctly represents the current order of the participants as visible in the UI.
const { remoteParticipants } = state['features/filmstrip'];
const participants = [ localId, ...remoteParticipants ];
if (participants.length - 1 < n) {
return;
}
const { id, pinned } = getParticipantById(state, participants[n]);
if (isStageFilmstripAvailable(state)) {
dispatch(togglePinStageParticipant(id));
} else {
dispatch(pinParticipant(pinned ? null : id));
}
};
}
/**
* Sets the volume for a thumbnail's audio.
*
* @param {string} participantId - The participant ID asociated with the audio.
* @param {string} volume - The volume level.
* @returns {{
* type: SET_VOLUME,
* participantId: string,
* volume: number
* }}
*/
export function setVolume(participantId: string, volume: number) {
return {
type: SET_VOLUME,
participantId,
volume
};
}
/**
* Sets the filmstrip's width.
*
* @param {number} width - The new width of the filmstrip.
* @returns {{
* type: SET_FILMSTRIP_WIDTH,
* width: number
* }}
*/
export function setFilmstripWidth(width: number) {
return {
type: SET_FILMSTRIP_WIDTH,
width
};
}
/**
* Sets the filmstrip's width and the user preferred width.
*
* @param {number} width - The new width of the filmstrip.
* @returns {{
* type: SET_USER_FILMSTRIP_WIDTH,
* width: number
* }}
*/
export function setUserFilmstripWidth(width: number) {
return {
type: SET_USER_FILMSTRIP_WIDTH,
width
};
}
/**
* Sets whether the user is resizing or not.
*
* @param {boolean} resizing - Whether the user is resizing or not.
* @returns {Object}
*/
export function setUserIsResizing(resizing: boolean) {
return {
type: SET_USER_IS_RESIZING,
resizing
};
}
/**
* Add participant to the active participants list.
*
* @param {string} participantId - The Id of the participant to be added.
* @param {boolean?} pinned - Whether the participant is pinned or not.
* @returns {Object}
*/
export function addStageParticipant(participantId, pinned = false) {
return {
type: ADD_STAGE_PARTICIPANT,
participantId,
pinned
};
}
/**
* Remove participant from the active participants list.
*
* @param {string} participantId - The Id of the participant to be removed.
* @returns {Object}
*/
export function removeStageParticipant(participantId) {
return {
type: REMOVE_STAGE_PARTICIPANT,
participantId
};
}
/**
* Sets the active participants list.
*
* @param {Array<Object>} queue - The new list.
* @returns {Object}
*/
export function setStageParticipants(queue) {
return {
type: SET_STAGE_PARTICIPANTS,
queue
};
}
/**
* Sets the max number of participants to be displayed on stage.
*
* @param {number} maxParticipants - Max number of participants.
* @returns {Object}
*/
export function setMaxStageParticipants(maxParticipants) {
return {
type: SET_MAX_STAGE_PARTICIPANTS,
maxParticipants
};
}
/**
* Toggles the pin state of the given participant.
*
* @param {string} participantId - The id of the participant to be toggled.
* @returns {Object}
*/
export function togglePinStageParticipant(participantId) {
return {
type: TOGGLE_PIN_STAGE_PARTICIPANT,
participantId
};
}
/**
* Clears the stage participants list.
*
* @returns {Object}
*/
export function clearStageParticipants() {
return {
type: CLEAR_STAGE_PARTICIPANTS
};
}