fix(toolbar): Move buttons to overflow menu when the space isn't enough

This commit is contained in:
Hristo Terezov 2019-03-05 14:26:45 +00:00
parent 27e1f5a1bc
commit a9d82a79ea
14 changed files with 378 additions and 30 deletions

View File

@ -40,3 +40,11 @@
.videocontainer .tOoji { .videocontainer .tOoji {
background: none; background: none;
} }
/**
* Override @atlaskit/InlineDialog styling for the overflowmenu so it displays
* with the correct height.
*/
.toolbox-button-wth-dialog .eYJELv {
max-height: initial;
}

View File

@ -190,6 +190,14 @@
cursor: initial; cursor: initial;
color: #3b475c; color: #3b475c;
} }
i.toggled {
background: inherit;
}
i.toggled:hover {
background: inherit;
}
} }
.beta-tag { .beta-tag {

View File

@ -66,7 +66,7 @@
} }
.info-dialog-dial-in { .info-dialog-dial-in {
white-space: nowrap; word-break: break-all;
.conference-id, .conference-id,
.phone-number { .phone-number {
@ -77,6 +77,7 @@
.info-dialog-icon { .info-dialog-icon {
color: #6453C0; color: #6453C0;
font-size: 16px; font-size: 16px;
min-width: 30px;
} }
.info-dialog-url-text, .info-dialog-url-text,

View File

@ -362,7 +362,8 @@
"numbers": "Dial-in Numbers", "numbers": "Dial-in Numbers",
"password": "Password:", "password": "Password:",
"title": "Share", "title": "Share",
"tooltip": "Share link and dial-in info for this meeting" "tooltip": "Share link and dial-in info for this meeting",
"label": "Meeting info"
}, },
"inviteDialog": { "inviteDialog": {
"alertOk": "Ok", "alertOk": "Ok",
@ -631,11 +632,14 @@
"callQuality": "Manage call quality", "callQuality": "Manage call quality",
"cameraDisabled": "Camera is not available", "cameraDisabled": "Camera is not available",
"chat": "Open / Close chat", "chat": "Open / Close chat",
"closeChat": "Close chat",
"documentClose": "Close shared document", "documentClose": "Close shared document",
"documentOpen": "Open shared document", "documentOpen": "Open shared document",
"enterFullScreen": "View full screen", "enterFullScreen": "View full screen",
"enterTileView": "Enter tile view",
"etherpad": "Open / Close shared document", "etherpad": "Open / Close shared document",
"exitFullScreen": "Exit full screen", "exitFullScreen": "Exit full screen",
"exitTileView": "Exit tile view",
"feedback": "Leave feedback", "feedback": "Leave feedback",
"filmstrip": "Show / Hide videos", "filmstrip": "Show / Hide videos",
"fullscreen": "View / Exit full screen", "fullscreen": "View / Exit full screen",
@ -644,13 +648,16 @@
"lock": "Lock / Unlock room", "lock": "Lock / Unlock room",
"login": "Login", "login": "Login",
"logout": "Logout", "logout": "Logout",
"lowerYourHand": "Lower your hand",
"micDisabled": "Microphone is not available", "micDisabled": "Microphone is not available",
"micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.", "micMutedPopup": "Your microphone has been muted so that you would fully enjoy your shared video.",
"moreActions": "More actions", "moreActions": "More actions",
"mute": "Mute / Unmute", "mute": "Mute / Unmute",
"openChat": "Open chat",
"pip": "Enter Picture-in-Picture mode", "pip": "Enter Picture-in-Picture mode",
"profile": "Edit your profile", "profile": "Edit your profile",
"raiseHand": "Raise / Lower your hand", "raiseHand": "Raise / Lower your hand",
"raiseYourHand": "Raise your hand",
"Settings": "Settings", "Settings": "Settings",
"sharedvideo": "Share a YouTube video", "sharedvideo": "Share a YouTube video",
"sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other members.", "sharedVideoMutedPopup": "Your shared video has been muted so that you can talk to the other members.",
@ -658,6 +665,10 @@
"shortcuts": "View shortcuts", "shortcuts": "View shortcuts",
"sip": "Call SIP number", "sip": "Call SIP number",
"speakerStats": "Speaker stats", "speakerStats": "Speaker stats",
"startScreenSharing": "Start screen sharing",
"startSubtitles": "Start subtitles",
"stopScreenSharing": "Stop screen sharing",
"stopSubtitles": "Stop subtitles",
"stopSharedVideo": "Stop YouTube video", "stopSharedVideo": "Stop YouTube video",
"talkWhileMutedPopup": "Trying to speak? You are muted.", "talkWhileMutedPopup": "Trying to speak? You are muted.",
"tileViewToggle": "Toggle tile view", "tileViewToggle": "Toggle tile view",
@ -666,7 +677,7 @@
"videomute": "Start / Stop camera" "videomute": "Start / Stop camera"
}, },
"transcribing": { "transcribing": {
"ccButtonTooltip": "Start / Stop showing subtitles", "ccButtonTooltip": "Start / Stop subtitles",
"error": "Transcribing failed. Please try again.", "error": "Transcribing failed. Please try again.",
"expandedLabel": "Transcribing is currently on", "expandedLabel": "Transcribing is currently on",
"failedToStart": "Transcribing failed to start", "failedToStart": "Transcribing failed to start",

View File

@ -160,8 +160,9 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
* @returns {string} * @returns {string}
*/ */
_getIconName() { _getIconName() {
return (this._isToggled() ? this.toggledIconName : this.iconName) return (
|| this.iconName; this._isToggled() ? this.toggledIconName : this.iconName
) || this.iconName;
} }
/** /**

View File

@ -5,3 +5,4 @@ export { default as AbstractButton } from './AbstractButton';
export type { Props as AbstractButtonProps } from './AbstractButton'; export type { Props as AbstractButtonProps } from './AbstractButton';
export { default as AbstractHangupButton } from './AbstractHangupButton'; export { default as AbstractHangupButton } from './AbstractHangupButton';
export { default as AbstractVideoMuteButton } from './AbstractVideoMuteButton'; export { default as AbstractVideoMuteButton } from './AbstractVideoMuteButton';
export { default as OverflowMenuItem } from './OverflowMenuItem';

View File

@ -5,12 +5,13 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createToolbarEvent, sendAnalytics } from '../../analytics'; import { createToolbarEvent, sendAnalytics } from '../../analytics';
import { openDialog } from '../../base/dialog';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet'; import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
import { getParticipantCount } from '../../base/participants'; import { getParticipantCount } from '../../base/participants';
import { OverflowMenuItem } from '../../base/toolbox';
import { getActiveSession } from '../../recording'; import { getActiveSession } from '../../recording';
import { ToolbarButton } from '../../toolbox'; import { ToolbarButton } from '../../toolbox';
import { updateDialInNumbers } from '../actions'; import { updateDialInNumbers } from '../actions';
import { InfoDialog } from './info-dialog'; import { InfoDialog } from './info-dialog';
@ -59,6 +60,11 @@ type Props = {
*/ */
dispatch: Dispatch<*>, dispatch: Dispatch<*>,
/**
* Whether to show the label or not.
*/
showLabel: boolean,
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
*/ */
@ -122,6 +128,8 @@ class InfoDialogButton extends Component<Props, State> {
// Bind event handlers so they are only bound once for every instance. // Bind event handlers so they are only bound once for every instance.
this._onDialogClose = this._onDialogClose.bind(this); this._onDialogClose = this._onDialogClose.bind(this);
this._onDialogToggle = this._onDialogToggle.bind(this); this._onDialogToggle = this._onDialogToggle.bind(this);
this._onClickOverflowMenuButton
= this._onClickOverflowMenuButton.bind(this);
} }
/** /**
@ -142,16 +150,28 @@ class InfoDialogButton extends Component<Props, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { _dialIn, _liveStreamViewURL, t } = this.props; const { _dialIn, _liveStreamViewURL, showLabel, t } = this.props;
const { showDialog } = this.state; const { showDialog } = this.state;
const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`; const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`;
if (showLabel) {
return (
<OverflowMenuItem
accessibilityLabel = { t('info.accessibilityLabel') }
icon = 'icon-info'
key = 'info-button'
onClick = { this._onClickOverflowMenuButton }
text = { t('info.label') } />
);
}
return ( return (
<div className = 'toolbox-button-wth-dialog'> <div className = 'toolbox-button-wth-dialog'>
<InlineDialog <InlineDialog
content = { content = {
<InfoDialog <InfoDialog
dialIn = { _dialIn } dialIn = { _dialIn }
isInlineDialog = { true }
liveStreamViewURL = { _liveStreamViewURL } liveStreamViewURL = { _liveStreamViewURL }
onClose = { this._onDialogClose } /> } onClose = { this._onDialogClose } /> }
isOpen = { showDialog } isOpen = { showDialog }
@ -179,6 +199,23 @@ class InfoDialogButton extends Component<Props, State> {
this.setState({ showDialog: false }); this.setState({ showDialog: false });
} }
_onClickOverflowMenuButton: () => void;
/**
* Opens the Info dialog.
*
* @returns {void}
*/
_onClickOverflowMenuButton() {
const { _dialIn, _liveStreamViewURL } = this.props;
this.props.dispatch(openDialog(InfoDialog, {
dialIn: _dialIn,
liveStreamViewURL: _liveStreamViewURL,
isInlineDialog: false
}));
}
_onDialogToggle: () => void; _onDialogToggle: () => void;
/** /**

View File

@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { setPassword } from '../../../base/conference'; import { setPassword } from '../../../base/conference';
import { getInviteURL } from '../../../base/connection'; import { getInviteURL } from '../../../base/connection';
import { Dialog } from '../../../base/dialog';
import { translate } from '../../../base/i18n'; import { translate } from '../../../base/i18n';
import { isLocalParticipantModerator } from '../../../base/participants'; import { isLocalParticipantModerator } from '../../../base/participants';
@ -66,6 +67,11 @@ type Props = {
*/ */
dispatch: Dispatch<*>, dispatch: Dispatch<*>,
/**
* Whether is Atlaskit InlineDialog or a normal dialog.
*/
isInlineDialog: boolean,
/** /**
* The current known URL for a live stream in progress. * The current known URL for a live stream in progress.
*/ */
@ -187,9 +193,14 @@ class InfoDialog extends Component<Props, State> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { liveStreamViewURL, onMouseOver, t } = this.props; const {
isInlineDialog,
liveStreamViewURL,
onMouseOver,
t
} = this.props;
return ( const inlineDialog = (
<div <div
className = 'info-dialog' className = 'info-dialog'
onMouseOver = { onMouseOver } > onMouseOver = { onMouseOver } >
@ -246,6 +257,20 @@ class InfoDialog extends Component<Props, State> {
value = { this._getTextToCopy() } /> value = { this._getTextToCopy() } />
</div> </div>
); );
if (isInlineDialog) {
return inlineDialog;
}
return (
<Dialog
cancelTitleKey = 'dialog.close'
submitDisabled = { true }
titleKey = 'info.label'
width = 'small'>
{ inlineDialog }
</Dialog>
);
} }
/** /**

View File

@ -83,6 +83,7 @@ class PasswordForm extends Component<Props, State> {
this._onEnteredPasswordChange this._onEnteredPasswordChange
= this._onEnteredPasswordChange.bind(this); = this._onEnteredPasswordChange.bind(this);
this._onPasswordSubmit = this._onPasswordSubmit.bind(this); this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
} }
/** /**
@ -119,6 +120,7 @@ class PasswordForm extends Component<Props, State> {
return ( return (
<form <form
className = 'info-password-form' className = 'info-password-form'
onKeyDown = { this._onKeyDown }
onSubmit = { this._onPasswordSubmit }> onSubmit = { this._onPasswordSubmit }>
<input <input
autoFocus = { true } autoFocus = { true }
@ -175,9 +177,26 @@ class PasswordForm extends Component<Props, State> {
*/ */
_onPasswordSubmit(event) { _onPasswordSubmit(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
this.props.onSubmit(this.state.enteredPassword); this.props.onSubmit(this.state.enteredPassword);
} }
_onKeyDown: (Object) => void;
/**
* Stops the the EnterKey for propagation in order to prevent the dialog
* to close.
*
* @param {Object} event - The key event.
* @private
* @returns {void}
*/
_onKeyDown(event) {
if (event.key === 'Enter') {
event.stopPropagation();
}
}
} }
export default translate(PasswordForm); export default translate(PasswordForm);

View File

@ -19,6 +19,8 @@ class ClosedCaptionButton
iconName = 'icon-closed_caption'; iconName = 'icon-closed_caption';
toggledIconName = 'icon-closed_caption toggled'; toggledIconName = 'icon-closed_caption toggled';
tooltip = 'transcribing.ccButtonTooltip'; tooltip = 'transcribing.ccButtonTooltip';
label = 'toolbar.startSubtitles';
toggledLabel = 'toolbar.stopSubtitles';
} }
export default translate(connect(_abstractMapStateToProps)( export default translate(connect(_abstractMapStateToProps)(

View File

@ -16,6 +16,7 @@ import {
getParticipants, getParticipants,
participantUpdated participantUpdated
} from '../../../base/participants'; } from '../../../base/participants';
import { OverflowMenuItem } from '../../../base/toolbox';
import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks'; import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
import { ChatCounter, toggleChat } from '../../../chat'; import { ChatCounter, toggleChat } from '../../../chat';
import { toggleDocument } from '../../../etherpad'; import { toggleDocument } from '../../../etherpad';
@ -56,7 +57,6 @@ import {
import AudioMuteButton from '../AudioMuteButton'; import AudioMuteButton from '../AudioMuteButton';
import HangupButton from '../HangupButton'; import HangupButton from '../HangupButton';
import OverflowMenuButton from './OverflowMenuButton'; import OverflowMenuButton from './OverflowMenuButton';
import OverflowMenuItem from './OverflowMenuItem';
import OverflowMenuProfileItem from './OverflowMenuProfileItem'; import OverflowMenuProfileItem from './OverflowMenuProfileItem';
import ToolbarButton from './ToolbarButton'; import ToolbarButton from './ToolbarButton';
import VideoMuteButton from '../VideoMuteButton'; import VideoMuteButton from '../VideoMuteButton';
@ -177,6 +177,17 @@ type Props = {
t: Function t: Function
}; };
/**
* The type of the React {@code Component} state of {@link Toolbox}.
*/
type State = {
/**
* The width of the browser's window.
*/
windowWidth: number
};
declare var APP: Object; declare var APP: Object;
declare var interfaceConfig: Object; declare var interfaceConfig: Object;
@ -185,7 +196,7 @@ declare var interfaceConfig: Object;
* *
* @extends Component * @extends Component
*/ */
class Toolbox extends Component<Props> { class Toolbox extends Component<Props, State> {
/** /**
* Initializes a new {@code Toolbox} instance. * Initializes a new {@code Toolbox} instance.
* *
@ -198,6 +209,7 @@ class Toolbox extends Component<Props> {
// Bind event handlers so they are only bound once per instance. // Bind event handlers so they are only bound once per instance.
this._onMouseOut = this._onMouseOut.bind(this); this._onMouseOut = this._onMouseOut.bind(this);
this._onMouseOver = this._onMouseOver.bind(this); this._onMouseOver = this._onMouseOver.bind(this);
this._onResize = this._onResize.bind(this);
this._onSetOverflowVisible = this._onSetOverflowVisible.bind(this); this._onSetOverflowVisible = this._onSetOverflowVisible.bind(this);
this._onShortcutToggleChat = this._onShortcutToggleChat.bind(this); this._onShortcutToggleChat = this._onShortcutToggleChat.bind(this);
@ -232,6 +244,10 @@ class Toolbox extends Component<Props> {
= this._onToolbarToggleSharedVideo.bind(this); = this._onToolbarToggleSharedVideo.bind(this);
this._onToolbarOpenLocalRecordingInfoDialog this._onToolbarOpenLocalRecordingInfoDialog
= this._onToolbarOpenLocalRecordingInfoDialog.bind(this); = this._onToolbarOpenLocalRecordingInfoDialog.bind(this);
this.state = {
windowWidth: window.innerWidth
};
} }
/** /**
@ -273,6 +289,8 @@ class Toolbox extends Component<Props> {
shortcut.helpDescription); shortcut.helpDescription);
} }
}); });
window.addEventListener('resize', this._onResize);
} }
/** /**
@ -303,6 +321,8 @@ class Toolbox extends Component<Props> {
componentWillUnmount() { componentWillUnmount() {
[ 'C', 'D', 'R', 'S' ].forEach(letter => [ 'C', 'D', 'R', 'S' ].forEach(letter =>
APP.keyboardshortcut.unregisterShortcut(letter)); APP.keyboardshortcut.unregisterShortcut(letter));
window.removeEventListener('resize', this._onResize);
} }
/** /**
@ -482,6 +502,24 @@ class Toolbox extends Component<Props> {
this.props.dispatch(setToolbarHovered(true)); this.props.dispatch(setToolbarHovered(true));
} }
_onResize: () => void;
/**
* A window resize handler used to calculate the number of buttons we can
* fit in the toolbar.
*
* @private
* @returns {void}
*/
_onResize() {
const width = window.innerWidth;
if (this.state.windowWidth !== width) {
this.setState({ windowWidth: width });
}
}
_onSetOverflowVisible: (boolean) => void; _onSetOverflowVisible: (boolean) => void;
/** /**
@ -788,13 +826,30 @@ class Toolbox extends Component<Props> {
this.props.dispatch(openDialog(LocalRecordingInfoDialog)); this.props.dispatch(openDialog(LocalRecordingInfoDialog));
} }
/**
* Returns true if the the desktop sharing button should be visible and
* false otherwise.
*
* @returns {boolean}
*/
_isDesktopSharingButtonVisible() {
const {
_desktopSharingEnabled,
_desktopSharingDisabledTooltipKey
} = this.props;
return _desktopSharingEnabled || _desktopSharingDisabledTooltipKey;
}
/** /**
* Renders a button for toggleing screen sharing. * Renders a button for toggleing screen sharing.
* *
* @private * @private
* @param {boolean} isInOverflowMenu - True if the button is moved to the
* overflow menu.
* @returns {ReactElement|null} * @returns {ReactElement|null}
*/ */
_renderDesktopSharingButton() { _renderDesktopSharingButton(isInOverflowMenu = false) {
const { const {
_desktopSharingEnabled, _desktopSharingEnabled,
_desktopSharingDisabledTooltipKey, _desktopSharingDisabledTooltipKey,
@ -802,13 +857,28 @@ class Toolbox extends Component<Props> {
t t
} = this.props; } = this.props;
const visible if (!this._isDesktopSharingButtonVisible()) {
= _desktopSharingEnabled || _desktopSharingDisabledTooltipKey;
if (!visible) {
return null; return null;
} }
if (isInOverflowMenu) {
return (
<OverflowMenuItem
accessibilityLabel
= { t('toolbar.accessibilityLabel.shareYourScreen') }
disabled = { _desktopSharingEnabled }
icon = { 'icon-share-desktop' }
key = 'desktop'
onClick = { this._onToolbarToggleScreenshare }
text = {
t(`toolbar.${
_screensharing
? 'stopScreenSharing' : 'startScreenSharing'}`
)
} />
);
}
const classNames = `icon-share-desktop ${ const classNames = `icon-share-desktop ${
_screensharing ? 'toggled' : ''} ${ _screensharing ? 'toggled' : ''} ${
_desktopSharingEnabled ? '' : 'disabled'}`; _desktopSharingEnabled ? '' : 'disabled'}`;
@ -826,6 +896,15 @@ class Toolbox extends Component<Props> {
); );
} }
/**
* Returns true if the profile button is visible and false otherwise.
*
* @returns {boolean}
*/
_isProfileVisible() {
return this.props._isGuest && this._shouldShowButton('profile');
}
/** /**
* Renders the list elements of the overflow menu. * Renders the list elements of the overflow menu.
* *
@ -838,14 +917,12 @@ class Toolbox extends Component<Props> {
_etherpadInitialized, _etherpadInitialized,
_feedbackConfigured, _feedbackConfigured,
_fullScreen, _fullScreen,
_isGuest,
_sharingVideo, _sharingVideo,
t t
} = this.props; } = this.props;
return [ return [
_isGuest this._isProfileVisible()
&& this._shouldShowButton('profile')
&& <OverflowMenuProfileItem && <OverflowMenuProfileItem
key = 'profile' key = 'profile'
onClick = { this._onToolbarToggleProfile } />, onClick = { this._onToolbarToggleProfile } />,
@ -924,6 +1001,88 @@ class Toolbox extends Component<Props> {
]; ];
} }
/**
* Renders a list of buttons that are moved to the overflow menu.
*
* @private
* @param {Array<string>} movedButtons - The names of the buttons to be
* moved.
* @returns {Array<ReactElement>}
*/
_renderMovedButtons(movedButtons) {
const {
_chatOpen,
_raisedHand,
t
} = this.props;
return movedButtons.map(buttonName => {
switch (buttonName) {
case 'desktop':
return this._renderDesktopSharingButton(true);
case 'raisehand':
return (
<OverflowMenuItem
accessibilityLabel =
{ t('toolbar.accessibilityLabel.raiseHand') }
icon = { 'icon-raised-hand' }
key = 'raisedHand'
onClick = { this._onToolbarToggleRaiseHand }
text = {
t(`toolbar.${
_raisedHand
? 'lowerYourHand' : 'raiseYourHand'}`
)
} />
);
case 'chat':
return (
<OverflowMenuItem
accessibilityLabel =
{ t('toolbar.accessibilityLabel.chat') }
icon = { 'icon-chat' }
key = 'chat'
onClick = { this._onToolbarToggleChat }
text = {
t(`toolbar.${
_chatOpen ? 'closeChat' : 'openChat'}`
)
} />
);
case 'closedcaptions':
return <ClosedCaptionButton showLabel = { true } />;
case 'info':
return <InfoDialogButton showLabel = { true } />;
case 'invite':
return (
<OverflowMenuItem
accessibilityLabel =
{ t('toolbar.accessibilityLabel.invite') }
icon = 'icon-invite'
key = 'invite'
onClick = { this._onToolbarOpenInvite }
text = { t('toolbar.invite') } />
);
case 'tileview':
return <TileViewButton showLabel = { true } />;
case 'localrecording':
return (
<OverflowMenuItem
accessibilityLabel
= { t('toolbar.accessibilityLabel.localRecording') }
icon = { 'icon-thumb-menu icon-rec' }
key = 'localrecording'
onClick = {
this._onToolbarOpenLocalRecordingInfoDialog
}
text = { t('localRecording.dialogTitle') } />
);
default:
return null;
}
});
}
/** /**
* Renders the toolbox content. * Renders the toolbox content.
* *
@ -941,13 +1100,86 @@ class Toolbox extends Component<Props> {
const overflowHasItems = Boolean(overflowMenuContent.filter( const overflowHasItems = Boolean(overflowMenuContent.filter(
child => child).length); child => child).length);
const toolbarAccLabel = 'toolbar.accessibilityLabel.moreActionsMenu'; const toolbarAccLabel = 'toolbar.accessibilityLabel.moreActionsMenu';
const buttonsLeft = [];
const buttonsRight = [];
const maxNumberOfButtonsPerGroup = Math.floor(
(
this.state.windowWidth
- 168 // the width of the central group by design
- 48 // the minimum space between the button groups
)
/ 56 // the width + padding of a button
/ 2 // divide by the number of groups(left and right group)
);
if (this._shouldShowButton('desktop')
&& this._isDesktopSharingButtonVisible()) {
buttonsLeft.push('desktop');
}
if (this._shouldShowButton('raisehand')) {
buttonsLeft.push('raisehand');
}
if (this._shouldShowButton('chat')) {
buttonsLeft.push('chat');
}
if (this._shouldShowButton('closedcaptions')) {
buttonsLeft.push('closedcaptions');
}
if (overflowHasItems) {
buttonsRight.push('overflowmenu');
}
if (this._shouldShowButton('info')) {
buttonsRight.push('info');
}
if (this._shouldShowButton('invite') && !_hideInviteButton) {
buttonsRight.push('invite');
}
if (this._shouldShowButton('tileview')) {
buttonsRight.push('tileview');
}
if (this._shouldShowButton('localrecording')) {
buttonsRight.push('localrecording');
}
const movedButtons = [];
if (buttonsLeft.length > maxNumberOfButtonsPerGroup) {
movedButtons.push(...buttonsLeft.splice(
maxNumberOfButtonsPerGroup,
buttonsLeft.length - maxNumberOfButtonsPerGroup));
if (buttonsRight.indexOf('overflowmenu') === -1) {
buttonsRight.unshift('overflowmenu');
}
}
if (buttonsRight.length > maxNumberOfButtonsPerGroup) {
if (buttonsRight.indexOf('overflowmenu') === -1) {
buttonsRight.unshift('overflowmenu');
}
let numberOfButtons = maxNumberOfButtonsPerGroup;
// make sure the more button will be displayed when we move buttons.
if (numberOfButtons === 0) {
numberOfButtons++;
}
movedButtons.push(...buttonsRight.splice(
numberOfButtons,
buttonsRight.length - numberOfButtons));
}
overflowMenuContent.splice(
1, 0, ...this._renderMovedButtons(movedButtons));
return ( return (
<div className = 'toolbox-content'> <div className = 'toolbox-content'>
<div className = 'button-group-left'> <div className = 'button-group-left'>
{ this._shouldShowButton('desktop') { buttonsLeft.indexOf('desktop') !== -1
&& this._renderDesktopSharingButton() } && this._renderDesktopSharingButton() }
{ this._shouldShowButton('raisehand') { buttonsLeft.indexOf('raisehand') !== -1
&& <ToolbarButton && <ToolbarButton
accessibilityLabel = accessibilityLabel =
{ {
@ -958,7 +1190,7 @@ class Toolbox extends Component<Props> {
: 'icon-raised-hand' } : 'icon-raised-hand' }
onClick = { this._onToolbarToggleRaiseHand } onClick = { this._onToolbarToggleRaiseHand }
tooltip = { t('toolbar.raiseHand') } /> } tooltip = { t('toolbar.raiseHand') } /> }
{ this._shouldShowButton('chat') { buttonsLeft.indexOf('chat') !== -1
&& <div className = 'toolbar-button-with-badge'> && <div className = 'toolbar-button-with-badge'>
<ToolbarButton <ToolbarButton
accessibilityLabel = accessibilityLabel =
@ -971,7 +1203,7 @@ class Toolbox extends Component<Props> {
<ChatCounter /> <ChatCounter />
</div> } </div> }
{ {
this._shouldShowButton('closedcaptions') buttonsLeft.indexOf('closedcaptions') !== -1
&& <ClosedCaptionButton /> && <ClosedCaptionButton />
} }
</div> </div>
@ -984,24 +1216,26 @@ class Toolbox extends Component<Props> {
visible = { this._shouldShowButton('camera') } /> visible = { this._shouldShowButton('camera') } />
</div> </div>
<div className = 'button-group-right'> <div className = 'button-group-right'>
{ this._shouldShowButton('localrecording') { buttonsRight.indexOf('localrecording') !== -1
&& <LocalRecordingButton && <LocalRecordingButton
onClick = { onClick = {
this._onToolbarOpenLocalRecordingInfoDialog this._onToolbarOpenLocalRecordingInfoDialog
} /> } />
} }
{ this._shouldShowButton('tileview') { buttonsRight.indexOf('tileview') !== -1
&& <TileViewButton /> } && <TileViewButton /> }
{ this._shouldShowButton('invite') { buttonsRight.indexOf('invite') !== -1
&& !_hideInviteButton
&& <ToolbarButton && <ToolbarButton
accessibilityLabel = accessibilityLabel =
{ t('toolbar.accessibilityLabel.invite') } { t('toolbar.accessibilityLabel.invite') }
iconName = 'icon-invite' iconName = 'icon-invite'
onClick = { this._onToolbarOpenInvite } onClick = { this._onToolbarOpenInvite }
tooltip = { t('toolbar.invite') } /> } tooltip = { t('toolbar.invite') } /> }
{ this._shouldShowButton('info') && <InfoDialogButton /> } {
{ overflowHasItems buttonsRight.indexOf('info') !== -1
&& <InfoDialogButton />
}
{ buttonsRight.indexOf('overflowmenu') !== -1
&& <OverflowMenuButton && <OverflowMenuButton
isOpen = { _overflowMenuVisible } isOpen = { _overflowMenuVisible }
onVisibilityChange = { this._onSetOverflowVisible }> onVisibilityChange = { this._onSetOverflowVisible }>

View File

@ -38,7 +38,8 @@ type Props = AbstractButtonProps & {
class TileViewButton<P: Props> extends AbstractButton<P, *> { class TileViewButton<P: Props> extends AbstractButton<P, *> {
accessibilityLabel = 'toolbar.accessibilityLabel.tileView'; accessibilityLabel = 'toolbar.accessibilityLabel.tileView';
iconName = 'icon-tiles-many'; iconName = 'icon-tiles-many';
label = 'toolbar.tileViewToggle'; label = 'toolbar.enterTileView';
toggledLabel = 'toolbar.exitTileView';
toggledIconName = 'icon-tiles-many toggled'; toggledIconName = 'icon-tiles-many toggled';
tooltip = 'toolbar.tileViewToggle'; tooltip = 'toolbar.tileViewToggle';