@ -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 ) ;
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 ) ;
let initialHeight = viewHeight / minVisibleRows ;
let minHeightEnforced = false ;
return {
height ,
width
} ;
if ( initialHeight < minHeight ) {
minHeightEnforced = true ;
initialHeight = minHeight ;
}
if ( disableTileEnlargement ) {
const aspectRatioHeight = initialWidth / aspectRatio ;
if ( aspectRatioHeight < minHeight ) { // we can't fit the required number of columns.
return ;
}
const height = Math . floor ( Math . min ( aspectRatioHeight , initialHeight ) ) ;
return {
height ,
width
width : Math . floor ( aspectRatio * height ) ,
minHeightEnforced ,
maxVisibleRows : Math . floor ( viewHeight / height )
} ;
}
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 ;
const initialRatio = initialWidth / initialHeight ;
let height = Math . floor ( initialHeight ) ;
if ( height > heightFromWidth && heightFromWidth < minHeight ) {
return {
height ,
width : height / TILE _PORTRAIT _ASPECT _RATIO
} ;
}
// 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 : Math . min ( height , heightFromWidth ) ,
width
height ,
width : Math . floor ( initialHeight * aspectRatio ) ,
minHeightEnforced ,
maxVisibleRows : Math . floor ( viewHeight / height )
} ;
} else if ( height < width ) {
} else if ( initialRatio >= TILE _PORTRAIT _ASPECT _RATIO ) {
return {
height ,
width : Math . min ( width , aspectRatio * height )
width : Math . floor ( initialWidth ) ,
minHeightEnforced ,
maxVisibleRows : Math . floor ( viewHeight / height )
} ;
}
} else if ( ! minHeightEnforced ) {
height = Math . floor ( initialWidth / TILE _PORTRAIT _ASPECT _RATIO ) ;
return {
height ,
width
} ;
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.
}
/ * *