feat(tile-view): Optimize grid dimnsions.
Now the algorithm that calculates the rows/columns/thumbnail-width/thumbnail-height configuration will go trough all possible configurations and will choose the one that covers with thumbnails the biggest area of the window.
This commit is contained in:
parent
3884862996
commit
e7c4a55add
|
@ -73,6 +73,10 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.filmstrip__videos.has-scroll {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
.remote-videos {
|
||||
box-sizing: border-box;
|
||||
|
||||
|
@ -90,7 +94,6 @@
|
|||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
|
||||
.videocontainer {
|
||||
border: 0;
|
||||
|
|
|
@ -216,6 +216,7 @@ export default [
|
|||
'testing',
|
||||
'toolbarButtons',
|
||||
'toolbarConfig',
|
||||
'tileView',
|
||||
'transcribingEnabled',
|
||||
'useHostPageLocalStorage',
|
||||
'useTurnUdp',
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// @flow
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { getLocalParticipant, getParticipantById, pinParticipant } from '../base/participants';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { shouldHideSelfView } from '../base/settings/functions.any';
|
||||
import { getTileViewGridDimensions } from '../video-layout';
|
||||
import { getMaxColumnCount } from '../video-layout';
|
||||
|
||||
import {
|
||||
SET_FILMSTRIP_WIDTH,
|
||||
|
@ -21,15 +25,20 @@ import {
|
|||
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 {
|
||||
calculateNotResponsiveTileViewDimensions,
|
||||
calculateResponsiveTileViewDimensions,
|
||||
calculateThumbnailSizeForHorizontalView,
|
||||
calculateThumbnailSizeForTileView,
|
||||
calculateThumbnailSizeForVerticalView,
|
||||
isFilmstripResizable,
|
||||
showGridInVerticalView
|
||||
} from './functions';
|
||||
import { getNumberOfPartipantsForTileView } from './functions.web';
|
||||
|
||||
export * from './actions.any';
|
||||
|
||||
|
@ -41,37 +50,56 @@ export * from './actions.any';
|
|||
* resolved to Redux state using the {@code toState} function.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function setTileViewDimensions(dimensions: Object) {
|
||||
export function setTileViewDimensions() {
|
||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||
const state = getState();
|
||||
const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
|
||||
const { disableResponsiveTiles, disableTileEnlargement } = state['features/base/config'];
|
||||
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
|
||||
} = calculateThumbnailSizeForTileView({
|
||||
...dimensions,
|
||||
width,
|
||||
columns,
|
||||
rows
|
||||
} = disableResponsiveTiles
|
||||
? calculateNotResponsiveTileViewDimensions(state)
|
||||
: calculateResponsiveTileViewDimensions({
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
disableResponsiveTiles,
|
||||
disableTileEnlargement
|
||||
disableTileEnlargement,
|
||||
isVerticalFilmstrip: false,
|
||||
maxColumns,
|
||||
numberOfParticipants,
|
||||
numberOfVisibleTiles
|
||||
});
|
||||
const { columns, rows } = dimensions;
|
||||
const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height);
|
||||
const hasScroll = clientHeight < thumbnailsTotalHeight;
|
||||
const filmstripWidth = (columns * (TILE_HORIZONTAL_MARGIN + width)) + (hasScroll ? SCROLL_SIZE : 0);
|
||||
const filmstripHeight = Math.min(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_TILE_VIEW_DIMENSIONS,
|
||||
dimensions: {
|
||||
gridDimensions: dimensions,
|
||||
gridDimensions: {
|
||||
columns,
|
||||
rows
|
||||
},
|
||||
thumbnailSize: {
|
||||
height,
|
||||
width
|
||||
},
|
||||
filmstripHeight,
|
||||
filmstripWidth
|
||||
filmstripWidth,
|
||||
hasScroll
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -97,26 +125,34 @@ export function setVerticalViewDimensions() {
|
|||
|
||||
// grid view in the vertical filmstrip
|
||||
if (_verticalViewGrid) {
|
||||
const dimensions = getTileViewGridDimensions(state, filmstripWidth.current);
|
||||
const { 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
|
||||
} = calculateThumbnailSizeForTileView({
|
||||
...dimensions,
|
||||
width,
|
||||
columns,
|
||||
rows
|
||||
} = calculateResponsiveTileViewDimensions({
|
||||
clientWidth: filmstripWidth.current,
|
||||
clientHeight,
|
||||
disableResponsiveTiles: false,
|
||||
disableTileEnlargement: false,
|
||||
isVerticalFilmstrip: true
|
||||
isVerticalFilmstrip: true,
|
||||
maxColumns,
|
||||
numberOfParticipants,
|
||||
numberOfVisibleTiles
|
||||
});
|
||||
const { columns, rows } = dimensions;
|
||||
const thumbnailsTotalHeight = rows * (TILE_VERTICAL_MARGIN + height);
|
||||
const hasScroll = clientHeight < thumbnailsTotalHeight;
|
||||
const widthOfFilmstrip = (columns * (TILE_HORIZONTAL_MARGIN + width)) + (hasScroll ? SCROLL_SIZE : 0);
|
||||
const filmstripHeight = Math.min(clientHeight, thumbnailsTotalHeight);
|
||||
|
||||
gridView = {
|
||||
gridDimensions: dimensions,
|
||||
gridDimensions: {
|
||||
columns,
|
||||
rows
|
||||
},
|
||||
thumbnailSize: {
|
||||
height,
|
||||
width
|
||||
|
|
|
@ -767,6 +767,7 @@ function _mapStateToProps(state) {
|
|||
gridDimensions: dimensions = {},
|
||||
filmstripHeight,
|
||||
filmstripWidth,
|
||||
hasScroll = false,
|
||||
thumbnailSize: tileViewThumbnailSize
|
||||
} = state['features/filmstrip'].tileViewDimensions;
|
||||
const _currentLayout = getCurrentLayout(state);
|
||||
|
@ -796,7 +797,7 @@ function _mapStateToProps(state) {
|
|||
const shouldReduceHeight = reduceHeight && (
|
||||
isMobileBrowser() || _currentLayout !== LAYOUTS.VERTICAL_FILMSTRIP_VIEW);
|
||||
|
||||
const videosClassName = `filmstrip__videos${visible ? '' : ' hidden'}`;
|
||||
let videosClassName = `filmstrip__videos${visible ? '' : ' hidden'}`;
|
||||
const className = `${remoteVideosVisible || _verticalViewGrid ? '' : 'hide-videos'} ${
|
||||
shouldReduceHeight ? 'reduce-height' : ''
|
||||
} ${shiftRight ? 'shift-right' : ''} ${collapseTileView ? 'collapse' : ''} ${visible ? '' : 'hidden'}`.trim();
|
||||
|
@ -804,6 +805,9 @@ function _mapStateToProps(state) {
|
|||
|
||||
switch (_currentLayout) {
|
||||
case LAYOUTS.TILE_VIEW:
|
||||
if (hasScroll) {
|
||||
videosClassName += ' has-scroll';
|
||||
}
|
||||
_thumbnailSize = tileViewThumbnailSize;
|
||||
remoteFilmstripHeight = filmstripHeight - (collapseTileView && filmstripPadding > 0 ? filmstripPadding : 0);
|
||||
remoteFilmstripWidth = filmstripWidth;
|
||||
|
|
|
@ -28,16 +28,6 @@ export const SQUARE_TILE_ASPECT_RATIO = 1;
|
|||
*/
|
||||
export const DISPLAY_DRAWER_THRESHOLD = 512;
|
||||
|
||||
/**
|
||||
* Breakpoint past which a single column view is enforced in tile view.
|
||||
*/
|
||||
export const SINGLE_COLUMN_BREAKPOINT = 300;
|
||||
|
||||
/**
|
||||
* Breakpoint past which a two column view is enforced in tile view.
|
||||
*/
|
||||
export const TWO_COLUMN_BREAKPOINT = 1000;
|
||||
|
||||
/**
|
||||
* Breakpoint past which the aspect ratio is switched in tile view.
|
||||
* Also, past this breakpoint, if there are two participants in the conference, we enforce
|
||||
|
@ -57,9 +47,14 @@ export const TILE_MIN_HEIGHT_SMALL = 150;
|
|||
export const TILE_MIN_HEIGHT_LARGE = 200;
|
||||
|
||||
/**
|
||||
* Aspect ratio for portrait tiles. (height / width).
|
||||
* Aspect ratio for portrait tiles.
|
||||
*/
|
||||
export const TILE_PORTRAIT_ASPECT_RATIO = 1.3;
|
||||
export const TILE_PORTRAIT_ASPECT_RATIO = 1 / 1.3;
|
||||
|
||||
/**
|
||||
* The default number of visible tiles for tile view.
|
||||
*/
|
||||
export const TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES = 25;
|
||||
|
||||
/**
|
||||
* The default number of columns for tile view.
|
||||
|
@ -150,14 +145,14 @@ export const TILE_VERTICAL_CONTAINER_HORIZONTAL_MARGIN = 2;
|
|||
*
|
||||
* @type {number}
|
||||
*/
|
||||
export const TILE_VIEW_GRID_VERTICAL_MARGIN = 12;
|
||||
export const TILE_VIEW_GRID_VERTICAL_MARGIN = 14;
|
||||
|
||||
/**
|
||||
* The horizontal margin of the tile grid container.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
export const TILE_VIEW_GRID_HORIZONTAL_MARGIN = 12;
|
||||
export const TILE_VIEW_GRID_HORIZONTAL_MARGIN = 14;
|
||||
|
||||
/**
|
||||
* The height of the whole toolbar.
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
getPinnedParticipant
|
||||
} from '../base/participants';
|
||||
import { toState } from '../base/redux';
|
||||
import { shouldHideSelfView } from '../base/settings/functions.any';
|
||||
import {
|
||||
getLocalVideoTrack,
|
||||
getTrackByMediaTypeAndParticipant,
|
||||
|
@ -17,7 +18,11 @@ import {
|
|||
isRemoteTrackMuted
|
||||
} from '../base/tracks/functions';
|
||||
import { isTrackStreamingStatusActive, isParticipantConnectionStatusActive } from '../connection-indicator/functions';
|
||||
import { getCurrentLayout, LAYOUTS } from '../video-layout';
|
||||
import {
|
||||
getCurrentLayout,
|
||||
getNotResponsiveTileViewGridDimensions,
|
||||
LAYOUTS
|
||||
} from '../video-layout';
|
||||
|
||||
import {
|
||||
ASPECT_RATIO_BREAKPOINT,
|
||||
|
@ -27,7 +32,6 @@ import {
|
|||
DISPLAY_VIDEO,
|
||||
FILMSTRIP_GRID_BREAKPOINT,
|
||||
INDICATORS_TOOLTIP_POSITION,
|
||||
SCROLL_SIZE,
|
||||
SQUARE_TILE_ASPECT_RATIO,
|
||||
TILE_ASPECT_RATIO,
|
||||
TILE_HORIZONTAL_MARGIN,
|
||||
|
@ -35,6 +39,7 @@ import {
|
|||
TILE_MIN_HEIGHT_SMALL,
|
||||
TILE_PORTRAIT_ASPECT_RATIO,
|
||||
TILE_VERTICAL_MARGIN,
|
||||
TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES,
|
||||
TILE_VIEW_GRID_HORIZONTAL_MARGIN,
|
||||
TILE_VIEW_GRID_VERTICAL_MARGIN,
|
||||
VERTICAL_VIEW_HORIZONTAL_MARGIN
|
||||
|
@ -187,6 +192,211 @@ export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0,
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum height of a thumbnail.
|
||||
*
|
||||
* @param {number} clientWidth - The width of the window.
|
||||
* @returns {number} The minimum height of a thumbnail.
|
||||
*/
|
||||
export function getThumbnailMinHeight(clientWidth) {
|
||||
return clientWidth < ASPECT_RATIO_BREAKPOINT ? TILE_MIN_HEIGHT_SMALL : TILE_MIN_HEIGHT_LARGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default aspect ratio for a tile.
|
||||
*
|
||||
* @param {boolean} disableResponsiveTiles - Indicates whether the responsive tiles functionality is disabled.
|
||||
* @param {boolean} disableTileEnlargement - Indicates whether the tiles enlargement functionality is disabled.
|
||||
* @param {number} clientWidth - The width of the window.
|
||||
* @returns {number} The default aspect ratio for a tile.
|
||||
*/
|
||||
export function getTileDefaultAspectRatio(disableResponsiveTiles, disableTileEnlargement, clientWidth) {
|
||||
if (!disableResponsiveTiles && disableTileEnlargement && clientWidth < ASPECT_RATIO_BREAKPOINT) {
|
||||
return SQUARE_TILE_ASPECT_RATIO;
|
||||
}
|
||||
|
||||
return TILE_ASPECT_RATIO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants that will be displayed in tile view.
|
||||
*
|
||||
* @param {Object} state - The redux store state.
|
||||
* @returns {number} The number of participants that will be displayed in tile view.
|
||||
*/
|
||||
export function getNumberOfPartipantsForTileView(state) {
|
||||
const { iAmRecorder } = state['features/base/config'];
|
||||
const disableSelfView = shouldHideSelfView(state);
|
||||
const numberOfParticipants = getParticipantCountWithFake(state)
|
||||
- (iAmRecorder ? 1 : 0)
|
||||
- (disableSelfView ? 1 : 0);
|
||||
|
||||
return numberOfParticipants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dimensions (thumbnail width/height and columns/row) for tile view when the responsive tiles are
|
||||
* disabled.
|
||||
*
|
||||
* @param {Object} state - The redux store state.
|
||||
* @returns {Object} - The dimensions.
|
||||
*/
|
||||
export function calculateNotResponsiveTileViewDimensions(state) {
|
||||
const { clientHeight, clientWidth } = state['features/base/responsive-ui'];
|
||||
const { disableTileEnlargement } = state['features/base/config'];
|
||||
const { columns: c, minVisibleRows, rows: r } = getNotResponsiveTileViewGridDimensions(state);
|
||||
const size = calculateThumbnailSizeForTileView({
|
||||
columns: c,
|
||||
minVisibleRows,
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
disableTileEnlargement,
|
||||
disableResponsiveTiles: true
|
||||
});
|
||||
|
||||
if (typeof size === 'undefined') { // The columns don't fit into the screen. We will have horizontal scroll.
|
||||
const aspectRatio = disableTileEnlargement
|
||||
? getTileDefaultAspectRatio(true, disableTileEnlargement, clientWidth)
|
||||
: TILE_PORTRAIT_ASPECT_RATIO;
|
||||
|
||||
const height = getThumbnailMinHeight(clientWidth);
|
||||
|
||||
return {
|
||||
height,
|
||||
width: aspectRatio * height,
|
||||
columns: c,
|
||||
rows: r
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
height: size.height,
|
||||
width: size.width,
|
||||
columns: c,
|
||||
rows: r
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dimensions (thumbnail width/height and columns/row) for tile view when the responsive tiles are
|
||||
* enabled.
|
||||
*
|
||||
* @param {Object} state - The redux store state.
|
||||
* @returns {Object} - The dimensions.
|
||||
*/
|
||||
export function calculateResponsiveTileViewDimensions({
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
disableTileEnlargement = false,
|
||||
isVerticalFilmstrip = false,
|
||||
maxColumns,
|
||||
numberOfParticipants,
|
||||
numberOfVisibleTiles = TILE_VIEW_DEFAULT_NUMBER_OF_VISIBLE_TILES
|
||||
}) {
|
||||
let height, width;
|
||||
let columns, rows;
|
||||
|
||||
let dimensions = {
|
||||
maxArea: 0
|
||||
};
|
||||
let minHeightEnforcedDimensions = {
|
||||
maxArea: 0
|
||||
};
|
||||
let zeroVisibleRowsDimensions = {
|
||||
maxArea: 0
|
||||
};
|
||||
|
||||
for (let c = 1; c <= Math.min(maxColumns, numberOfParticipants); c++) {
|
||||
const r = Math.ceil(numberOfParticipants / c);
|
||||
|
||||
// we want to display as much as possible tumbnails up to numberOfVisibleTiles
|
||||
const visibleRows
|
||||
= numberOfParticipants <= numberOfVisibleTiles ? r : Math.floor(numberOfVisibleTiles / c);
|
||||
|
||||
const size = calculateThumbnailSizeForTileView({
|
||||
columns: c,
|
||||
minVisibleRows: visibleRows,
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
disableTileEnlargement,
|
||||
disableResponsiveTiles: false,
|
||||
isVerticalFilmstrip
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
if (typeof size !== 'undefined') {
|
||||
|
||||
const { height: currentHeight, width: currentWidth, minHeightEnforced, maxVisibleRows } = size;
|
||||
|
||||
console.error(`Num col = ${c}, visibleRows=${visibleRows}, hxw=${
|
||||
currentHeight}x${currentWidth}, maxVisibleRows=${maxVisibleRows}`);
|
||||
let area = currentHeight * currentWidth * Math.min(c * maxVisibleRows, numberOfParticipants);
|
||||
|
||||
// we have a preference to show more columns if possible, that's why even if the area is equal we
|
||||
// overwrite.
|
||||
if (!minHeightEnforced && area > dimensions.maxArea) {
|
||||
dimensions = {
|
||||
maxArea: area,
|
||||
height: currentHeight,
|
||||
width: currentWidth,
|
||||
columns: c,
|
||||
rows: r
|
||||
};
|
||||
} else if (minHeightEnforced) {
|
||||
// eslint-disable-next-line max-depth
|
||||
if (area > minHeightEnforcedDimensions.maxArea) {
|
||||
minHeightEnforcedDimensions = {
|
||||
maxArea: area,
|
||||
height: currentHeight,
|
||||
width: currentWidth,
|
||||
columns: c,
|
||||
rows: r
|
||||
};
|
||||
} else if (maxVisibleRows === 0) {
|
||||
area = currentHeight * currentWidth * Math.min(c, numberOfParticipants);
|
||||
|
||||
// eslint-disable-next-line max-depth
|
||||
if (area > zeroVisibleRowsDimensions.maxArea) {
|
||||
zeroVisibleRowsDimensions = {
|
||||
maxArea: area,
|
||||
height: currentHeight,
|
||||
width: currentWidth,
|
||||
columns: c,
|
||||
rows: r
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error(`Num col = ${c}, visibleRows=${visibleRows} not possible`);
|
||||
}
|
||||
}
|
||||
|
||||
if (dimensions.maxArea > 0) {
|
||||
({ height, width, columns, rows } = dimensions);
|
||||
} else if (minHeightEnforcedDimensions.maxArea > 0) {
|
||||
({ height, width, columns, rows } = minHeightEnforcedDimensions);
|
||||
} else if (zeroVisibleRowsDimensions.maxArea > 0) {
|
||||
({ height, width, columns, rows } = zeroVisibleRowsDimensions);
|
||||
} else { // This would mean that we can't fit even one thumbnail with minimal size.
|
||||
const aspectRatio = disableTileEnlargement
|
||||
? getTileDefaultAspectRatio(false, disableTileEnlargement, clientWidth)
|
||||
: TILE_PORTRAIT_ASPECT_RATIO;
|
||||
|
||||
height = getThumbnailMinHeight(clientWidth);
|
||||
width = aspectRatio * height;
|
||||
columns = 1;
|
||||
rows = numberOfParticipants;
|
||||
}
|
||||
|
||||
return {
|
||||
height,
|
||||
width,
|
||||
columns,
|
||||
rows
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the size for thumbnails when in tile view layout.
|
||||
*
|
||||
|
@ -196,90 +406,78 @@ export function calculateThumbnailSizeForVerticalView(clientWidth: number = 0,
|
|||
export function calculateThumbnailSizeForTileView({
|
||||
columns,
|
||||
minVisibleRows,
|
||||
rows,
|
||||
clientWidth,
|
||||
clientHeight,
|
||||
disableResponsiveTiles,
|
||||
disableTileEnlargement,
|
||||
disableResponsiveTiles = false,
|
||||
disableTileEnlargement = false,
|
||||
isVerticalFilmstrip = false
|
||||
}: Object) {
|
||||
let aspectRatio = TILE_ASPECT_RATIO;
|
||||
|
||||
if (!disableResponsiveTiles && clientWidth < ASPECT_RATIO_BREAKPOINT) {
|
||||
aspectRatio = SQUARE_TILE_ASPECT_RATIO;
|
||||
}
|
||||
|
||||
const minHeight = clientWidth < ASPECT_RATIO_BREAKPOINT ? TILE_MIN_HEIGHT_SMALL : TILE_MIN_HEIGHT_LARGE;
|
||||
const aspectRatio = getTileDefaultAspectRatio(disableResponsiveTiles, disableTileEnlargement, clientWidth);
|
||||
const minHeight = getThumbnailMinHeight(clientWidth);
|
||||
const viewWidth = clientWidth - (columns * TILE_HORIZONTAL_MARGIN)
|
||||
- (isVerticalFilmstrip ? 0 : TILE_VIEW_GRID_HORIZONTAL_MARGIN);
|
||||
const viewHeight = clientHeight - (minVisibleRows * TILE_VERTICAL_MARGIN) - TILE_VIEW_GRID_VERTICAL_MARGIN;
|
||||
const initialWidth = viewWidth / columns;
|
||||
const initialHeight = viewHeight / minVisibleRows;
|
||||
const aspectRatioHeight = initialWidth / aspectRatio;
|
||||
const noScrollHeight = (clientHeight / rows) - TILE_VERTICAL_MARGIN;
|
||||
const scrollInitialWidth = (viewWidth - SCROLL_SIZE) / columns;
|
||||
let height = Math.floor(Math.min(aspectRatioHeight, initialHeight));
|
||||
let width = Math.floor(aspectRatio * height);
|
||||
let initialHeight = viewHeight / minVisibleRows;
|
||||
let minHeightEnforced = false;
|
||||
|
||||
if (height > noScrollHeight && width > scrollInitialWidth) { // we will have scroll and we need more space for it.
|
||||
const scrollAspectRatioHeight = scrollInitialWidth / aspectRatio;
|
||||
|
||||
// Recalculating width/height to fit the available space when a scroll is displayed.
|
||||
// NOTE: Math.min(scrollAspectRatioHeight, initialHeight) would be enough to recalculate but since the new
|
||||
// height value can theoretically be dramatically smaller and the scroll may not be neccessary anymore we need
|
||||
// to compare it with noScrollHeight( the optimal height to fit all thumbnails without scroll) and get the
|
||||
// bigger one. This way we ensure that we always strech the thumbnails as close as we can to the edges of the
|
||||
// window.
|
||||
height = Math.floor(Math.max(Math.min(scrollAspectRatioHeight, initialHeight), noScrollHeight));
|
||||
width = Math.floor(aspectRatio * height);
|
||||
|
||||
return {
|
||||
height,
|
||||
width
|
||||
};
|
||||
if (initialHeight < minHeight) {
|
||||
minHeightEnforced = true;
|
||||
initialHeight = minHeight;
|
||||
}
|
||||
|
||||
if (disableTileEnlargement) {
|
||||
return {
|
||||
height,
|
||||
width
|
||||
};
|
||||
const aspectRatioHeight = initialWidth / aspectRatio;
|
||||
|
||||
if (aspectRatioHeight < minHeight) { // we can't fit the required number of columns.
|
||||
return;
|
||||
}
|
||||
|
||||
if (initialHeight > noScrollHeight) {
|
||||
height = Math.max(height, viewHeight / rows, minHeight);
|
||||
width = Math.max(width, initialWidth);
|
||||
} else {
|
||||
height = Math.max(initialHeight, minHeight);
|
||||
width = initialWidth;
|
||||
}
|
||||
|
||||
if (height > width) {
|
||||
const heightFromWidth = TILE_PORTRAIT_ASPECT_RATIO * width;
|
||||
|
||||
if (height > heightFromWidth && heightFromWidth < minHeight) {
|
||||
return {
|
||||
height,
|
||||
width: height / TILE_PORTRAIT_ASPECT_RATIO
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
height: Math.min(height, heightFromWidth),
|
||||
width
|
||||
};
|
||||
} else if (height < width) {
|
||||
return {
|
||||
height,
|
||||
width: Math.min(width, aspectRatio * height)
|
||||
};
|
||||
}
|
||||
const height = Math.floor(Math.min(aspectRatioHeight, initialHeight));
|
||||
|
||||
return {
|
||||
height,
|
||||
width
|
||||
width: Math.floor(aspectRatio * height),
|
||||
minHeightEnforced,
|
||||
maxVisibleRows: Math.floor(viewHeight / height)
|
||||
};
|
||||
}
|
||||
|
||||
const initialRatio = initialWidth / initialHeight;
|
||||
let height = Math.floor(initialHeight);
|
||||
|
||||
// The biggest area of the grid will be when the grid's height is equal to clientHeight or when the grid's width is
|
||||
// equal to clientWidth.
|
||||
|
||||
if (initialRatio > aspectRatio) {
|
||||
return {
|
||||
height,
|
||||
width: Math.floor(initialHeight * aspectRatio),
|
||||
minHeightEnforced,
|
||||
maxVisibleRows: Math.floor(viewHeight / height)
|
||||
};
|
||||
} else if (initialRatio >= TILE_PORTRAIT_ASPECT_RATIO) {
|
||||
return {
|
||||
height,
|
||||
width: Math.floor(initialWidth),
|
||||
minHeightEnforced,
|
||||
maxVisibleRows: Math.floor(viewHeight / height)
|
||||
};
|
||||
} else if (!minHeightEnforced) {
|
||||
height = Math.floor(initialWidth / TILE_PORTRAIT_ASPECT_RATIO);
|
||||
|
||||
if (height >= minHeight) {
|
||||
return {
|
||||
height,
|
||||
width: Math.floor(initialWidth),
|
||||
minHeightEnforced,
|
||||
maxVisibleRows: Math.floor(viewHeight / height)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// else
|
||||
// We can't fit that number of columns with the desired min height and aspect ratio.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,9 +44,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
|
||||
switch (layout) {
|
||||
case LAYOUTS.TILE_VIEW: {
|
||||
const { gridDimensions } = state['features/filmstrip'].tileViewDimensions;
|
||||
|
||||
store.dispatch(setTileViewDimensions(gridDimensions));
|
||||
store.dispatch(setTileViewDimensions());
|
||||
break;
|
||||
}
|
||||
case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { getParticipantCountWithFake } from '../base/participants';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { getTileViewGridDimensions, shouldDisplayTileView } from '../video-layout';
|
||||
import { shouldDisplayTileView } from '../video-layout';
|
||||
|
||||
import { setTileViewDimensions } from './actions';
|
||||
import './subscriber.any';
|
||||
|
@ -34,9 +34,7 @@ StateListenerRegistry.register(
|
|||
StateListenerRegistry.register(
|
||||
/* selector */ state => shouldDisplayTileView(state),
|
||||
/* listener */ (isTileView, store) => {
|
||||
const state = store.getState();
|
||||
|
||||
if (isTileView) {
|
||||
store.dispatch(setTileViewDimensions(getTileViewGridDimensions(state)));
|
||||
store.dispatch(setTileViewDimensions());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
import { isMobileBrowser } from '../base/environment/utils';
|
||||
import { getParticipantCountWithFake } from '../base/participants';
|
||||
import { StateListenerRegistry, equals } from '../base/redux';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { clientResized } from '../base/responsive-ui';
|
||||
import { shouldHideSelfView } from '../base/settings';
|
||||
import { setFilmstripVisible } from '../filmstrip/actions';
|
||||
import { getParticipantsPaneOpen } from '../participants-pane/functions';
|
||||
import { setOverflowDrawer } from '../toolbox/actions.web';
|
||||
import { getCurrentLayout, getTileViewGridDimensions, shouldDisplayTileView, LAYOUTS } from '../video-layout';
|
||||
import { getCurrentLayout, shouldDisplayTileView, LAYOUTS } from '../video-layout';
|
||||
|
||||
import {
|
||||
setHorizontalViewDimensions,
|
||||
|
@ -17,9 +17,7 @@ import {
|
|||
} from './actions';
|
||||
import {
|
||||
ASPECT_RATIO_BREAKPOINT,
|
||||
DISPLAY_DRAWER_THRESHOLD,
|
||||
SINGLE_COLUMN_BREAKPOINT,
|
||||
TWO_COLUMN_BREAKPOINT
|
||||
DISPLAY_DRAWER_THRESHOLD
|
||||
} from './constants';
|
||||
import { isFilmstripResizable } from './functions.web';
|
||||
import './subscriber.any';
|
||||
|
@ -40,12 +38,7 @@ StateListenerRegistry.register(
|
|||
const resizableFilmstrip = isFilmstripResizable(state);
|
||||
|
||||
if (shouldDisplayTileView(state)) {
|
||||
const gridDimensions = getTileViewGridDimensions(state);
|
||||
const oldGridDimensions = state['features/filmstrip'].tileViewDimensions.gridDimensions;
|
||||
|
||||
if (!equals(gridDimensions, oldGridDimensions)) {
|
||||
store.dispatch(setTileViewDimensions(gridDimensions));
|
||||
}
|
||||
store.dispatch(setTileViewDimensions());
|
||||
}
|
||||
if (resizableFilmstrip) {
|
||||
store.dispatch(setVerticalViewDimensions());
|
||||
|
@ -60,11 +53,9 @@ StateListenerRegistry.register(
|
|||
StateListenerRegistry.register(
|
||||
/* selector */ state => getCurrentLayout(state),
|
||||
/* listener */ (layout, store) => {
|
||||
const state = store.getState();
|
||||
|
||||
switch (layout) {
|
||||
case LAYOUTS.TILE_VIEW:
|
||||
store.dispatch(setTileViewDimensions(getTileViewGridDimensions(state)));
|
||||
store.dispatch(setTileViewDimensions());
|
||||
break;
|
||||
case LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW:
|
||||
store.dispatch(setHorizontalViewDimensions());
|
||||
|
@ -132,50 +123,6 @@ StateListenerRegistry.register(
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Symbol mapping used for the tile view responsiveness computation.
|
||||
*/
|
||||
const responsiveColumnMapping = {
|
||||
multipleColumns: Symbol('multipleColumns'),
|
||||
singleColumn: Symbol('singleColumn'),
|
||||
twoColumns: Symbol('twoColumns'),
|
||||
twoParticipantsSingleColumn: Symbol('twoParticipantsSingleColumn')
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for changes in the screen size to recompute
|
||||
* the dimensions of the tile view grid and the tiles for responsiveness.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => {
|
||||
const { clientWidth } = state['features/base/responsive-ui'];
|
||||
|
||||
if (clientWidth < TWO_COLUMN_BREAKPOINT && clientWidth >= ASPECT_RATIO_BREAKPOINT) {
|
||||
// Forcing the recomputation of tiles when screen switches in or out of
|
||||
// the (TWO_COLUMN_BREAKPOINT, ASPECT_RATIO_BREAKPOINT] interval.
|
||||
return responsiveColumnMapping.twoColumns;
|
||||
} else if (clientWidth < ASPECT_RATIO_BREAKPOINT && clientWidth >= SINGLE_COLUMN_BREAKPOINT) {
|
||||
// Forcing the recomputation of tiles when screen switches in or out of
|
||||
// the (ASPECT_RATIO_BREAKPOINT, SINGLE_COLUMN_BREAKPOINT] interval.
|
||||
return responsiveColumnMapping.twoParticipantsSingleColumn;
|
||||
} else if (clientWidth < SINGLE_COLUMN_BREAKPOINT) {
|
||||
// Forcing the recomputation of tiles when screen switches below SINGLE_COLUMN_BREAKPOINT.
|
||||
return responsiveColumnMapping.singleColumn;
|
||||
}
|
||||
|
||||
// Forcing the recomputation of tiles when screen switches above TWO_COLUMN_BREAKPOINT.
|
||||
return responsiveColumnMapping.multipleColumns;
|
||||
},
|
||||
/* listener */ (_, store) => {
|
||||
const state = store.getState();
|
||||
|
||||
if (shouldDisplayTileView(state)) {
|
||||
const gridDimensions = getTileViewGridDimensions(state);
|
||||
|
||||
store.dispatch(setTileViewDimensions(gridDimensions));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Listens for changes in the filmstrip width to determine the size of the tiles.
|
||||
*/
|
||||
|
|
|
@ -5,17 +5,13 @@ import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
|
|||
import {
|
||||
getPinnedParticipant,
|
||||
getParticipantCount,
|
||||
pinParticipant,
|
||||
getParticipantCountWithFake
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { shouldHideSelfView } from '../base/settings/functions.any';
|
||||
import {
|
||||
ASPECT_RATIO_BREAKPOINT,
|
||||
DEFAULT_MAX_COLUMNS,
|
||||
ABSOLUTE_MAX_COLUMNS,
|
||||
SINGLE_COLUMN_BREAKPOINT,
|
||||
TWO_COLUMN_BREAKPOINT
|
||||
ABSOLUTE_MAX_COLUMNS
|
||||
} from '../filmstrip/constants';
|
||||
import { getNumberOfPartipantsForTileView } from '../filmstrip/functions.web';
|
||||
import { isVideoPlaying } from '../shared-video/functions';
|
||||
|
||||
import { LAYOUTS } from './constants';
|
||||
|
@ -62,32 +58,10 @@ export function getCurrentLayout(state: Object) {
|
|||
* @param {number} width - Custom width to use for calculation.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getMaxColumnCount(state: Object, width: ?number) {
|
||||
export function getMaxColumnCount() {
|
||||
const configuredMax = (typeof interfaceConfig === 'undefined'
|
||||
? DEFAULT_MAX_COLUMNS
|
||||
: interfaceConfig.TILE_VIEW_MAX_COLUMNS) || DEFAULT_MAX_COLUMNS;
|
||||
const { disableResponsiveTiles } = state['features/base/config'];
|
||||
|
||||
if (!disableResponsiveTiles) {
|
||||
const { clientWidth } = state['features/base/responsive-ui'];
|
||||
const widthToUse = width || clientWidth;
|
||||
const participantCount = getParticipantCount(state);
|
||||
|
||||
// If there are just two participants in a conference, enforce single-column view for mobile size.
|
||||
if (participantCount === 2 && widthToUse < ASPECT_RATIO_BREAKPOINT) {
|
||||
return Math.min(1, Math.max(configuredMax, 1));
|
||||
}
|
||||
|
||||
// Enforce single column view at very small screen widths.
|
||||
if (widthToUse < SINGLE_COLUMN_BREAKPOINT) {
|
||||
return Math.min(1, Math.max(configuredMax, 1));
|
||||
}
|
||||
|
||||
// Enforce two column view below breakpoint.
|
||||
if (widthToUse < TWO_COLUMN_BREAKPOINT) {
|
||||
return Math.min(2, Math.max(configuredMax, 1));
|
||||
}
|
||||
}
|
||||
|
||||
return Math.min(Math.max(configuredMax, 1), ABSOLUTE_MAX_COLUMNS);
|
||||
}
|
||||
|
@ -102,22 +76,10 @@ export function getMaxColumnCount(state: Object, width: ?number) {
|
|||
* @returns {Object} An object is return with the desired number of columns,
|
||||
* rows, and visible rows (the rest should overflow) for the tile view layout.
|
||||
*/
|
||||
export function getTileViewGridDimensions(state: Object, width: ?number) {
|
||||
const maxColumns = getMaxColumnCount(state, width);
|
||||
|
||||
// When in tile view mode, we must discount ourselves (the local participant) because our
|
||||
// tile is not visible.
|
||||
const { iAmRecorder } = state['features/base/config'];
|
||||
const disableSelfView = shouldHideSelfView(state);
|
||||
const numberOfParticipants = getParticipantCountWithFake(state)
|
||||
- (iAmRecorder ? 1 : 0)
|
||||
- (disableSelfView ? 1 : 0);
|
||||
const isWeb = navigator.product !== 'ReactNative';
|
||||
|
||||
// When there are 3 participants in the call we want them to be placed on a single row unless the maxColumn setting
|
||||
// is lower.
|
||||
const columnsToMaintainASquare
|
||||
= isWeb && numberOfParticipants === 3 ? 3 : Math.ceil(Math.sqrt(numberOfParticipants));
|
||||
export function getNotResponsiveTileViewGridDimensions(state: Object) {
|
||||
const maxColumns = getMaxColumnCount(state);
|
||||
const numberOfParticipants = getNumberOfPartipantsForTileView(state);
|
||||
const columnsToMaintainASquare = Math.ceil(Math.sqrt(numberOfParticipants));
|
||||
const columns = Math.min(columnsToMaintainASquare, maxColumns);
|
||||
const rows = Math.ceil(numberOfParticipants / columns);
|
||||
const minVisibleRows = Math.min(maxColumns, rows);
|
||||
|
|
Loading…
Reference in New Issue