fix(toolbar): Move buttons to overflow menu when the space isn't enough
This commit is contained in:
parent
27e1f5a1bc
commit
a9d82a79ea
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)(
|
||||||
|
|
|
@ -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 }>
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue