feat(DominantSpeakerName): Implement
This commit is contained in:
parent
b7ab3ea052
commit
7263829763
|
@ -105,12 +105,15 @@
|
|||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
pointer-events: all;
|
||||
background-color: #131519;
|
||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.toolbox-content-wrapper::after {
|
||||
content: '';
|
||||
background: $newToolbarBackgroundColor;
|
||||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||||
}
|
||||
|
||||
.toolbox-content-items {
|
||||
background: $newToolbarBackgroundColor;
|
||||
border-radius: 6px;
|
||||
|
@ -118,6 +121,7 @@
|
|||
padding: 6px;
|
||||
text-align: center;
|
||||
pointer-events: all;
|
||||
box-shadow: 0px 2px 8px 4px rgba(0, 0, 0, 0.25), 0px 0px 0px 1px rgba(0, 0, 0, 0.15);
|
||||
|
||||
>div {
|
||||
margin-left: 8px;
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
z-index: $subtitlesZ;
|
||||
|
||||
&.lifted {
|
||||
// Lift subtitle above toolbar+invite box.
|
||||
bottom: $newToolbarSize + 112px + 40px;
|
||||
// Lift subtitle above toolbar+dominant speaker box.
|
||||
bottom: $newToolbarSize + 36px + 40px;
|
||||
}
|
||||
|
||||
span {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// @flow
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The name to be displayed within the badge.
|
||||
*/
|
||||
name: string
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(theme => {
|
||||
return {
|
||||
badge: {
|
||||
background: 'rgba(0, 0, 0, 0.6)',
|
||||
borderRadius: '3px',
|
||||
color: theme.palette.text01,
|
||||
maxWidth: '50%',
|
||||
overflow: 'hidden',
|
||||
padding: '2px 16px',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Component that displays a name badge.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
const DisplayNameBadge = ({ name }: Props) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className = { classes.badge }>
|
||||
{name}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisplayNameBadge;
|
|
@ -0,0 +1,60 @@
|
|||
// @flow
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { getLocalParticipant } from '../../../base/participants';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
import { getLargeVideoParticipant } from '../../../large-video/functions';
|
||||
import { isToolboxVisible } from '../../../toolbox/functions.web';
|
||||
import { isLayoutTileView } from '../../../video-layout';
|
||||
|
||||
import DisplayNameBadge from './DisplayNameBadge';
|
||||
|
||||
const useStyles = makeStyles(theme => {
|
||||
return {
|
||||
badgeContainer: {
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
marginBottom: theme.spacing(2),
|
||||
transition: 'margin-bottom 0.3s'
|
||||
},
|
||||
containerElevated: {
|
||||
marginBottom: theme.spacing(7)
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Component that renders the dominant speaker's name as a badge above the toolbar in stage view.
|
||||
*
|
||||
* @returns {ReactElement|null}
|
||||
*/
|
||||
const DominantSpeakerName = () => {
|
||||
const classes = useStyles();
|
||||
const largeVideoParticipant = useSelector(getLargeVideoParticipant);
|
||||
const nameToDisplay = largeVideoParticipant?.name;
|
||||
const selectedId = largeVideoParticipant?.id;
|
||||
|
||||
const localParticipant = useSelector(getLocalParticipant);
|
||||
const localId = localParticipant?.id;
|
||||
|
||||
const isTileView = useSelector(isLayoutTileView);
|
||||
const toolboxVisible = useSelector(isToolboxVisible);
|
||||
|
||||
if (nameToDisplay && selectedId !== localId && !isTileView) {
|
||||
return (
|
||||
<div
|
||||
className = { `${classes.badgeContainer}${toolboxVisible ? '' : ` ${classes.containerElevated}`}` }>
|
||||
<DisplayNameBadge name = { nameToDisplay } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default DominantSpeakerName;
|
|
@ -3,3 +3,4 @@
|
|||
export { default as DisplayName } from './DisplayName';
|
||||
export { default as DisplayNameLabel } from './DisplayNameLabel';
|
||||
export { default as DisplayNamePrompt } from './DisplayNamePrompt';
|
||||
export { default as DominantSpeakerName } from './DominantSpeakerName';
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
|
||||
import { getParticipantById } from '../base/participants';
|
||||
|
||||
/**
|
||||
* Selector for the participant currently displaying on the large video.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function getLargeVideoParticipant(state: Object) {
|
||||
const { participantId } = state['features/large-video'];
|
||||
|
||||
return getParticipantById(state, participantId);
|
||||
}
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { getParticipantCountWithFake } from '../../base/participants';
|
||||
import { getLocalParticipant } from '../../base/participants';
|
||||
import { connect } from '../../base/redux';
|
||||
import { getLargeVideoParticipant } from '../../large-video/functions';
|
||||
import { isLayoutTileView } from '../../video-layout';
|
||||
|
||||
import {
|
||||
_abstractMapStateToProps,
|
||||
|
@ -74,9 +76,13 @@ class Captions
|
|||
* @returns {Object}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
const isTileView = isLayoutTileView(state);
|
||||
const largeVideoParticipant = getLargeVideoParticipant(state);
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
|
||||
return {
|
||||
..._abstractMapStateToProps(state),
|
||||
_isLifted: getParticipantCountWithFake(state) < 2
|
||||
_isLifted: largeVideoParticipant && largeVideoParticipant?.id !== localParticipant?.id && !isTileView
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import { connect } from '../../../base/redux';
|
|||
import { getLocalVideoTrack } from '../../../base/tracks';
|
||||
import { toggleChat } from '../../../chat';
|
||||
import { ChatButton } from '../../../chat/components';
|
||||
import { DominantSpeakerName } from '../../../display-name';
|
||||
import { EmbedMeetingButton } from '../../../embed-meeting';
|
||||
import { SharedDocumentButton } from '../../../etherpad';
|
||||
import { FeedbackButton } from '../../../feedback';
|
||||
|
@ -1145,6 +1146,7 @@ class Toolbox extends Component<Props> {
|
|||
onFocus = { this._onTabIn }
|
||||
onMouseOut = { this._onMouseOut }
|
||||
onMouseOver = { this._onMouseOver }>
|
||||
<DominantSpeakerName />
|
||||
<div className = 'toolbox-content-items'>
|
||||
{mainMenuButtons.map(({ Content, key, ...rest }) => Content !== Separator && (
|
||||
<Content
|
||||
|
|
|
@ -208,3 +208,13 @@ export function updateAutoPinnedParticipant(
|
|||
dispatch(pinParticipant(latestScreenShareParticipantId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for whether we are currently in tile view.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLayoutTileView(state: Object) {
|
||||
return getCurrentLayout(state) === LAYOUTS.TILE_VIEW;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue