feat(audio-screen-share): improved ux flow (#9411)

* add button state / helper dialog

* new audio screen share flow

* change error message

* address a couple of merge conflicts

* fix lint

* address code review

* address code review

* restrict audio screen share on mobile browsers
This commit is contained in:
Andrei Gavrilescu 2021-07-07 11:07:30 +03:00 committed by GitHub
parent 58ef72dce5
commit da7358d564
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 531 additions and 43 deletions

View File

@ -1867,7 +1867,6 @@ export default {
await this.useVideoStream(desktopVideoStream);
}
if (this._desktopAudioStream) {
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
// api.
@ -2463,8 +2462,8 @@ export default {
});
APP.UI.addListener(
UIEvents.TOGGLE_SCREENSHARING, audioOnly => {
this.toggleScreenSharing(undefined, { audioOnly });
UIEvents.TOGGLE_SCREENSHARING, ({ enabled, audioOnly }) => {
this.toggleScreenSharing(enabled, { audioOnly });
}
);
},

View File

@ -41,6 +41,8 @@ $flagsImagePath: "../images/";
@import 'modals/feedback/feedback';
@import 'modals/invite/info';
@import 'modals/settings/settings';
@import 'modals/screen-share/share-audio';
@import 'modals/screen-share/share-screen-warning';
@import 'modals/speaker_stats/speaker_stats';
@import 'modals/video-quality/video-quality';
@import 'modals/virtual-background/virtual-background';

View File

@ -0,0 +1,22 @@
.share-audio-dialog {
.share-audio-animation {
width: 100%;
height: 90%;
object-fit: contain;
}
input[type="checkbox"] + svg + span {
color: #9FB0CC;
}
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
&:last-child {
display: none;
}
}
}

View File

@ -0,0 +1,23 @@
.share-screen-warn-dialog {
font-size: 14px;
.separator-line {
margin: 24px 0 24px -20px;
padding: 0 20px;
width: 100%;
height: 1px;
background: #5E6D7A;
&:last-child {
display: none;
}
}
.header {
font-weight: 600;
}
.description {
margin-top: 16px;
}
}

BIN
images/share-audio.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

View File

@ -215,6 +215,7 @@
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
"grantModeratorDialog": "Are you sure you want to make this participant a moderator?",
"grantModeratorTitle": "Grant moderator",
"hideShareAudioHelper": "Don't show this dialog again",
"IamHost": "I am the host",
"incorrectRoomLockPassword": "Incorrect password",
"incorrectPassword": "Incorrect username or password",
@ -303,6 +304,13 @@
"sessTerminated": "Call terminated",
"sessionRestarted": "Call restarted by the bridge",
"Share": "Share",
"shareAudio": "Continue",
"shareAudioTitle" : "How to share audio",
"shareAudioWarningTitle": "You need to stop screen sharing before sharing audio",
"shareAudioWarningH1": "If you want to share just audio:",
"shareAudioWarningD1": "you need to stop screen sharing before sharing your audio.",
"shareAudioWarningD2": "you need to restart your screen sharing and check the \"share audio\" option.",
"shareMediaWarningGenericH2": "If you want to share your screen and audio",
"shareVideoLinkError": "Please provide a correct youtube link.",
"shareVideoTitle": "Share video",
"shareYourScreen": "Share your screen",
@ -310,6 +318,10 @@
"startLiveStreaming": "Start live stream",
"startRecording": "Start recording",
"startRemoteControlErrorMessage": "An error occurred while trying to start the remote control session!",
"shareScreenWarningTitle": "You need to stop audio sharing before sharing your screen",
"shareScreenWarningH1": "If you want to share just your screen:",
"shareScreenWarningD1": "you need to stop audio sharing before sharing your screen.",
"shareScreenWarningD2": "you need to stop audio sharing, start screen sharing and check the \"share audio\" option.",
"stopLiveStreaming": "Stop live stream",
"stopRecording": "Stop recording",
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
@ -544,7 +556,7 @@
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
"raisedHand": "{{name}} would like to speak.",
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
"screenShareNoAudioTitle": "Share audio was not checked",
"screenShareNoAudioTitle": "Couldn't share system audio!",
"somebody": "Somebody",
"startSilentTitle": "You joined with no audio output!",
"startSilentDescription": "Rejoin the meeting to enable audio",
@ -899,6 +911,7 @@
"speakerStats": "Speaker stats",
"startScreenSharing": "Start screen sharing",
"startSubtitles": "Start subtitles",
"stopAudioSharing": "Stop audio sharing",
"stopScreenSharing": "Stop screen sharing",
"stopSubtitles": "Stop subtitles",
"stopSharedVideo": "Stop video",

View File

@ -49,6 +49,8 @@ import {
import { toggleLobbyMode } from '../../react/features/lobby/actions';
import { RECORDING_TYPES } from '../../react/features/recording/constants';
import { getActiveSession } from '../../react/features/recording/functions';
import { isScreenAudioSupported } from '../../react/features/screen-share';
import { startScreenShareFlow, startAudioScreenShareFlow } from '../../react/features/screen-share/actions';
import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any';
import { toggleTileView, setTileView } from '../../react/features/video-layout';
import { muteAllParticipants } from '../../react/features/video-menu/actions';
@ -220,6 +222,16 @@ function initCommands() {
sendAnalytics(createApiEvent('raise-hand.toggled'));
APP.store.dispatch(raiseHand(!raisedHand));
},
'toggle-share-audio': () => {
sendAnalytics(createApiEvent('audio.screen.sharing.toggled'));
if (isScreenAudioSupported()) {
APP.store.dispatch(startAudioScreenShareFlow());
return;
}
logger.error('Audio screen sharing is not supported by the current platform!');
},
/**
* Callback to invoke when the "toggle-share-screen" command is received.
@ -596,9 +608,7 @@ function shouldBeEnabled() {
*/
function toggleScreenSharing(enable) {
if (JitsiMeetJS.isDesktopSharingEnabled()) {
APP.conference.toggleScreenSharing(enable).catch(() => {
logger.warn('Failed to toggle screen-sharing');
});
APP.store.dispatch(startScreenShareFlow(enable));
}
}

View File

@ -60,6 +60,7 @@ const commands = {
toggleChat: 'toggle-chat',
toggleFilmStrip: 'toggle-film-strip',
toggleRaiseHand: 'toggle-raise-hand',
toggleShareAudio: 'toggle-share-audio',
toggleShareScreen: 'toggle-share-screen',
toggleTileView: 'toggle-tile-view',
toggleVirtualBackgroundDialog: 'toggle-virtual-background',

View File

@ -111,6 +111,7 @@ export { default as IconShareDesktop } from './share-desktop.svg';
export { default as IconShareDoc } from './share-doc.svg';
export { default as IconShareVideo } from './shared-video.svg';
export { default as IconSmile } from './smile.svg';
export { default as IconStopAudioShare } from './stop-audio-share.svg';
export { default as IconSwitchCamera } from './switch-camera.svg';
export { default as IconTileView } from './tiles-many.svg';
export { default as IconToggleRecording } from './camera-take-picture.svg';

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.57392 5.35509L6.56245 5.36465L3.11271 1.9149C2.78183 1.58402 2.24546 1.58394 1.91469 1.91471C1.58392 2.24548 1.58401 2.78185 1.91488 3.11272L5.25574 6.45358L5.00001 6.66669H2.50001C2.03977 6.66669 1.66667 7.03978 1.66667 7.50002V12.5C1.66667 12.9603 2.03977 13.3334 2.50001 13.3334H5.00001L9.3166 16.9305C9.39148 16.9929 9.48586 17.0271 9.58334 17.0271C9.81346 17.0271 10 16.8405 10 16.6104V11.1978L11.6667 12.8645V13.3334C11.8158 13.3334 11.9627 13.3236 12.1067 13.3046L13.4679 14.6657C12.9091 14.8816 12.3017 15 11.6667 15V16.6667C12.7697 16.6667 13.8102 16.3988 14.7267 15.9245L16.8873 18.0851C17.2182 18.416 17.7545 18.4161 18.0853 18.0853C18.4161 17.7546 18.416 17.2182 18.0851 16.8873L16.1405 14.9427C16.1442 14.9394 16.1478 14.936 16.1515 14.9327L14.9712 13.7524C14.9675 13.7557 14.9638 13.759 14.9601 13.7622L13.7777 12.5798C13.7815 12.5767 13.7854 12.5735 13.7892 12.5704L12.6003 11.3814C12.5961 11.3843 12.5919 11.3871 12.5877 11.3899L10 8.8022V8.78118L8.33334 7.11451V7.13553L7.74583 6.54802L7.75729 6.53846L6.57392 5.35509ZM11.9766 8.36212L11.6667 8.0522V6.66669C13.5076 6.66669 15 8.15907 15 10C15 10.4129 14.9249 10.8083 14.7877 11.1732L13.3046 9.6901C13.1782 9.01814 12.6486 8.48848 11.9766 8.36212ZM16.04 12.4255L17.2535 13.639C17.9364 12.5927 18.3333 11.3427 18.3333 10C18.3333 6.31812 15.3486 3.33335 11.6667 3.33335V5.00002C14.4281 5.00002 16.6667 7.2386 16.6667 10C16.6667 10.8802 16.4393 11.7072 16.04 12.4255ZM10 6.38553L7.88064 4.26616L9.3166 3.06953C9.49338 2.92221 9.75611 2.9461 9.90343 3.12288C9.96583 3.19776 10 3.29215 10 3.38962V6.38553ZM5.60342 8.33335L6.43911 7.63695L8.33334 9.53118V13.9416L5.60342 11.6667H3.33334V8.33335H5.60342Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -248,3 +248,13 @@ function _getUserSelectedDeviceId(options) {
? foundMatchBasedOnLabel.deviceId : userSelectedDeviceId;
}
/**
* Should we hide the helper dialog when a user tries to do audio only screen sharing.
*
* @param {Object} state - The state of the application.
* @returns {boolean}
*/
export function shouldHideShareAudioHelper(state: Object): boolean {
return state['features/base/settings'].hideShareAudioHelper;
}

View File

@ -26,6 +26,7 @@ const DEFAULT_STATE = {
localFlipX: true,
micDeviceId: undefined,
serverURL: undefined,
hideShareAudioHelper: false,
startAudioOnly: false,
startWithAudioMuted: false,
startWithVideoMuted: false,

View File

@ -145,7 +145,10 @@ MiddlewareRegistry.register(store => next => action => {
return;
}
APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING, action.audioOnly);
const { enabled, audioOnly } = action;
APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING, { enabled,
audioOnly });
}
break;

View File

@ -1,6 +1,14 @@
// @flow
import { openDialog } from '../base/dialog/actions';
import { browser } from '../base/lib-jitsi-meet';
import { shouldHideShareAudioHelper } from '../base/settings';
import { toggleScreensharing } from '../base/tracks';
import { SET_SCREEN_AUDIO_SHARE_STATE, SET_SCREENSHARE_CAPTURE_FRAME_RATE } from './actionTypes';
import { ShareAudioDialog } from './components';
import ShareMediaWarningDialog from './components/ShareScreenWarningDialog';
import { isAudioOnlySharing, isScreenVideoShared } from './functions';
/**
* Updates the current known status of the shared video.
@ -33,3 +41,61 @@ export function setScreenshareFramerate(captureFrameRate: number) {
captureFrameRate
};
}
/**
* Start the audio only screen sharing flow. Function will switch between off and on states depending on the context.
*
* @param {Object} state - The state of the application.
* @returns {void}
*/
export function startAudioScreenShareFlow() {
return (dispatch: Object => Object, getState: () => any) => {
const state = getState();
const audioOnlySharing = isAudioOnlySharing(state);
// If we're already in a normal screen sharing session, warn the user.
if (isScreenVideoShared(state)) {
dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: true }));
return;
}
// If users opted out of the helper dialog toggle directly.
// If we're in an electron environment the helper dialog is not needed as there's only one option
// available for audio screen sharing, namely full window audio.
// If we're already sharing audio, toggle off.
if (shouldHideShareAudioHelper(state) || browser.isElectron() || audioOnlySharing) {
// We don't want to explicity set the screens share state, by passing undefined we let the
// underlying logic decide if it's on or off.
dispatch(toggleScreensharing(undefined, true));
return;
}
dispatch(openDialog(ShareAudioDialog));
};
}
/**
* Start normal screen sharing flow.Function will switch between off and on states depending on the context, and if
* not explicity told otherwise.
*
* @param {boolean} enabled - Explicitly set the screen sharing state. This has been kept for backward compatibility
* with the external API exposed by the iframe, even though it might not be used.
* @returns {void}
*/
export function startScreenShareFlow(enabled: boolean) {
return (dispatch: Object => Object, getState: () => any) => {
const state = getState();
const audioOnlySharing = isAudioOnlySharing(state);
// If we're in an audio screen sharing session, warn the user.
if (audioOnlySharing) {
dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: false }));
return;
}
dispatch(toggleScreensharing(enabled));
};
}

View File

@ -0,0 +1,80 @@
// @flow
import type { Dispatch } from 'redux';
import { translate } from '../../base/i18n';
import {
IconShareAudio,
IconStopAudioShare
} from '../../base/icons';
import { connect } from '../../base/redux';
import {
AbstractButton,
type AbstractButtonProps
} from '../../base/toolbox/components';
import { setOverflowMenuVisible } from '../../toolbox/actions';
import { startAudioScreenShareFlow } from '../actions';
import { isAudioOnlySharing } from '../functions';
type Props = AbstractButtonProps & {
/**
* The redux {@code dispatch} function.
*/
dispatch: Dispatch<any>,
/**
* Whether or not the local participant is audio only screen sharing.
*/
_isAudioOnlySharing: boolean
}
/**
* Component that renders a toolbar button for toggling audio only screen share.
*/
class ShareAudioButton extends AbstractButton<Props, *> {
accessibilityLabel = 'toolbar.accessibilityLabel.shareaudio';
icon = IconShareAudio;
label = 'toolbar.shareaudio';
tooltip = 'toolbar.shareaudio';
toggledIcon = IconStopAudioShare;
toggledLabel = 'toolbar.stopAudioSharing';
/**
* Handles clicking / pressing the button, and opens a new dialog.
*
* @private
* @returns {void}
*/
_handleClick() {
this.props.dispatch(startAudioScreenShareFlow());
this.props.dispatch(setOverflowMenuVisible(false));
}
/**
* Indicates whether this button is in toggled state or not.
*
* @override
* @protected
* @returns {boolean}
*/
_isToggled() {
return this.props._isAudioOnlySharing;
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
*/
function _mapStateToProps(state: Object): $Shape<Props> {
return {
_isAudioOnlySharing: isAudioOnlySharing(state)
};
}
export default translate(connect(_mapStateToProps)(ShareAudioButton));

View File

@ -0,0 +1,128 @@
// @flow
import { Checkbox } from '@atlaskit/checkbox';
import React, { Component } from 'react';
import type { Dispatch } from 'redux';
import { Dialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import {
updateSettings,
shouldHideShareAudioHelper
} from '../../base/settings';
import { toggleScreensharing } from '../../base/tracks';
/**
* The type of the React {@code Component} props of {@link ShareAudioDialog}.
*/
export type Props = {
/**
* The redux {@code dispatch} function.
*/
dispatch: Dispatch<any>,
/**
* Boolean stored in local storage that determines whether or not the dialog will be displayed again.
*/
_shouldHideShareAudioHelper: boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/**
* Component that displays the audio screen share helper dialog.
*/
class ShareAudioDialog extends Component<Props> {
/**
* Instantiates a new component.
*
* @inheritdoc
*/
constructor(props) {
super(props);
this._onContinue = this._onContinue.bind(this);
this._onSelectHideShareAudioHelper = this._onSelectHideShareAudioHelper.bind(this);
}
_onContinue: () => boolean;
/**
* Continue the normal screen sharing flow when the user clicks continue.
*
* @returns {boolean}
*/
_onContinue() {
// Pass undefined as the first parameter so the underlying logic decides weather or not to stop screen sharing.
this.props.dispatch(toggleScreensharing(undefined, true));
return true;
}
_onSelectHideShareAudioHelper: (Object) => void;
/**
* Callback invoked when the hide audio helper checkbox has been selected. This setting will be persisted in
* the local storage, thus the dialog won't be displayed again.
*
* @param {Object} e - The key event to handle.
* @returns {void}
*/
_onSelectHideShareAudioHelper({ target: { checked } }) {
this.props.dispatch(updateSettings({ hideShareAudioHelper: checked }));
}
/**
* Implements {@Component#render}.
*
* @inheritdoc
*/
render() {
const { t } = this.props;
return (
<Dialog
hideCancelButton = { false }
okKey = { t('dialog.shareAudio') }
onSubmit = { this._onContinue }
titleKey = { t('dialog.shareAudioTitle') }
width = { 'medium' } >
<div className = 'share-audio-dialog'>
<img
className = 'share-audio-animation'
src = 'images/share-audio.gif' />
<Checkbox
isChecked = { this.props._shouldHideShareAudioHelper }
label = { t('dialog.hideShareAudioHelper') }
name = 'hide-share-audio-helper'
// eslint-disable-next-line react/jsx-no-bind
onChange = { this._onSelectHideShareAudioHelper } />
</div>
</Dialog>
);
}
}
/**
* Maps part of the Redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
*/
function _mapStateToProps(state: Object): $Shape<Props> {
return {
_shouldHideShareAudioHelper: shouldHideShareAudioHelper(state)
};
}
export default translate(connect(_mapStateToProps)(ShareAudioDialog));

View File

@ -0,0 +1,105 @@
// @flow
import React, { Component } from 'react';
import type { Dispatch } from 'redux';
import { Dialog } from '../../base/dialog';
import { translate } from '../../base/i18n';
import { connect } from '../../base/redux';
import { toggleScreensharing } from '../../base/tracks';
export type Props = {
/**
* The redux {@code dispatch} function.
*/
dispatch: Dispatch<any>,
/**
* Whether or not the dialog was opened for the audio screen sharing flow or the normal one.
*/
_isAudioScreenShareWarning: Boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
}
/**
* Component that displays the share audio helper dialog.
*/
class ShareScreenWarningDialog extends Component<Props> {
/**
* Instantiates a new component.
*
* @inheritdoc
*/
constructor(props) {
super(props);
this._onStopSharing = this._onStopSharing.bind(this);
}
_onStopSharing: () => boolean;
/**
* Stop current screen sharing session.
*
* @returns {boolean}
*/
_onStopSharing() {
// Depending on the context from which this dialog is opened we'll either be toggling off an audio only
// share session or a normal screen sharing one, this is indicated by the _isAudioScreenShareWarning prop.
this.props.dispatch(toggleScreensharing(undefined,
!this.props._isAudioScreenShareWarning));
return true;
}
/**
* Implements {@Component#render}.
*§
* @inheritdoc
*/
render() {
const { t } = this.props;
let description1, description2, header1, header2, stopSharing, title;
if (this.props._isAudioScreenShareWarning) {
header1 = 'dialog.shareAudioWarningH1';
header2 = 'dialog.shareMediaWarningGenericH2';
description1 = 'dialog.shareAudioWarningD1';
description2 = 'dialog.shareAudioWarningD2';
title = 'dialog.shareAudioWarningTitle';
stopSharing = 'toolbar.stopScreenSharing';
} else {
header1 = 'dialog.shareScreenWarningTitle';
header2 = 'dialog.shareMediaWarningGenericH2';
description1 = 'dialog.shareScreenWarningD1';
description2 = 'dialog.shareScreenWarningD2';
title = 'dialog.shareScreenWarningTitle';
stopSharing = 'toolbar.stopAudioSharing';
}
return (<Dialog
hideCancelButton = { false }
okKey = { t(stopSharing) }
onSubmit = { this._onStopSharing }
titleKey = { t(title) }
width = { 'small' }>
<div className = 'share-screen-warn-dialog'>
<p className = 'header'> { t(header1) } </p>
<p className = 'description' > { t(description1) } </p>
<div className = 'separator-line' />
<p className = 'header' > { t(header2) } </p>
<p className = 'description' > { t(description2) } </p>
</div>
</Dialog>);
}
}
export default translate(connect()(ShareScreenWarningDialog));

View File

@ -0,0 +1,2 @@
export { default as ShareAudioButton } from './ShareAudioButton';
export { default as ShareAudioDialog } from './ShareAudioDialog';

View File

@ -1,8 +1,20 @@
// @flow
import { isWindows } from '../base/environment';
import { isMobileBrowser } from '../base/environment/utils';
import { browser } from '../base/lib-jitsi-meet';
import { VIDEO_TYPE } from '../base/media';
import { getLocalVideoTrack } from '../base/tracks';
/**
* Is the current screen sharing session audio only.
*
* @param {Object} state - The state of the application.
* @returns {boolean}
*/
export function isAudioOnlySharing(state: Object) {
return isScreenAudioShared(state) && !isScreenVideoShared(state);
}
/**
* State of audio sharing.
@ -21,5 +33,28 @@ export function isScreenAudioShared(state: Object) {
* @returns {boolean}
*/
export function isScreenAudioSupported() {
return browser.isChrome() || (browser.isElectron() && isWindows());
return (!isMobileBrowser() && browser.isChrome()) || (browser.isElectron() && isWindows());
}
/**
* Is any screen media currently being shared, audio or video.
*
* @param {Object} state - The state of the application.
* @returns {boolean}
*/
export function isScreenMediaShared(state: Object) {
return isScreenAudioShared(state) || isScreenVideoShared(state);
}
/**
* Is screen sharing currently active.
*
* @param {Object} state - The state of the application.
* @returns {boolean}
*/
export function isScreenVideoShared(state: Object) {
const localVideo = getLocalVideoTrack(state['features/base/tracks']);
// $FlowFixMe - No support for optional chain method calls in flow atm.
return localVideo?.jitsiTrack?.getVideoType() === VIDEO_TYPE.DESKTOP;
}

View File

@ -1,4 +1,6 @@
export * from './actions';
export * from './actionTypes';
export * from './components';
export * from './functions';

View File

@ -25,7 +25,6 @@ import {
IconPresentation,
IconRaisedHand,
IconRec,
IconShareAudio,
IconShareDesktop
} from '../../../base/icons';
import JitsiMeetJS from '../../../base/lib-jitsi-meet';
@ -36,7 +35,7 @@ import {
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import { OverflowMenuItem } from '../../../base/toolbox/components';
import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
import { getLocalVideoTrack } from '../../../base/tracks';
import { isVpaasMeeting } from '../../../billing-counter/functions';
import { ChatCounter, toggleChat } from '../../../chat';
import { EmbedMeetingDialog } from '../../../embed-meeting';
@ -53,7 +52,12 @@ import {
LiveStreamButton,
RecordButton
} from '../../../recording';
import { isScreenAudioShared, isScreenAudioSupported } from '../../../screen-share/';
import {
isScreenAudioSupported,
isScreenVideoShared,
ShareAudioButton,
startScreenShareFlow
} from '../../../screen-share/';
import SecurityDialogButton from '../../../security/components/security-dialog/SecurityDialogButton';
import {
SETTINGS_TABS,
@ -287,7 +291,6 @@ class Toolbox extends Component<Props> {
this._onToolbarToggleProfile = this._onToolbarToggleProfile.bind(this);
this._onToolbarToggleRaiseHand = this._onToolbarToggleRaiseHand.bind(this);
this._onToolbarToggleScreenshare = this._onToolbarToggleScreenshare.bind(this);
this._onToolbarToggleShareAudio = this._onToolbarToggleShareAudio.bind(this);
this._onToolbarOpenLocalRecordingInfoDialog = this._onToolbarOpenLocalRecordingInfoDialog.bind(this);
this._onShortcutToggleTileView = this._onShortcutToggleTileView.bind(this);
this._onEscKey = this._onEscKey.bind(this);
@ -535,9 +538,9 @@ class Toolbox extends Component<Props> {
* @param {boolean} audioOnly - Only share system audio.
* @returns {void}
*/
_doToggleScreenshare(enabled, audioOnly = false) {
_doToggleScreenshare() {
if (this.props._desktopSharingEnabled) {
this.props.dispatch(toggleScreensharing(enabled, audioOnly));
this.props.dispatch(startScreenShareFlow());
}
}
@ -725,15 +728,13 @@ class Toolbox extends Component<Props> {
* @returns {void}
*/
_onShortcutToggleScreenshare() {
const enable = !this.props._screensharing;
sendAnalytics(createToolbarEvent(
'screen.sharing',
{
enable
enable: !this.props._screensharing
}));
this._doToggleScreenshare(enable);
this._doToggleScreenshare();
}
_onTabIn: () => void;
@ -940,29 +941,13 @@ class Toolbox extends Component<Props> {
return;
}
const enable = !this.props._screensharing;
sendAnalytics(createShortcutEvent(
'toggle.screen.sharing',
ACTION_SHORTCUT_TRIGGERED,
{ enable }));
{ enable: !this.props._screensharing }));
this._closeOverflowMenuIfOpen();
this._doToggleScreenshare(enable);
}
_onToolbarToggleShareAudio: () => void;
/**
* Handles toggle share audio action.
*
* @returns {void}
*/
_onToolbarToggleShareAudio() {
const enable = !this.props._screensharing;
this._closeOverflowMenuIfOpen();
this._doToggleScreenshare(enable, true);
this._doToggleScreenshare();
}
_onToolbarOpenLocalRecordingInfoDialog: () => void;
@ -1095,12 +1080,9 @@ class Toolbox extends Component<Props> {
this.props._shouldShowButton('shareaudio')
&& _desktopSharingEnabled
&& isScreenAudioSupported()
&& <OverflowMenuItem
accessibilityLabel = { t('toolbar.accessibilityLabel.shareaudio') }
icon = { IconShareAudio }
&& <ShareAudioButton
key = 'shareaudio'
onClick = { this._onToolbarToggleShareAudio }
text = { t('toolbar.shareaudio') } />,
showLabel = { true } />,
this.props._shouldShowButton('etherpad')
&& <SharedDocumentButton
key = 'etherpad'
@ -1442,7 +1424,7 @@ function _mapStateToProps(state) {
_overflowMenuVisible: overflowMenuVisible,
_participantsPaneOpen: getParticipantsPaneOpen(state),
_raisedHand: localParticipant.raisedHand,
_screensharing: (localVideo && localVideo.videoType === 'desktop') || isScreenAudioShared(state),
_screensharing: isScreenVideoShared(state),
_shouldShowButton: buttonName => isToolbarButtonEnabled(buttonName)(state),
_visible: isToolboxVisible(state),
_visibleButtons: getToolbarButtons(state)