[RN] Refactor Toolbox
Create standalone components for each feature and move all state to them. Toolbars are now dummy containers.
This commit is contained in:
parent
450400b768
commit
a2834a2495
|
@ -74,6 +74,7 @@
|
|||
"toolbar": {
|
||||
"addPeople": "Add people to your call",
|
||||
"audioonly": "Enable / Disable audio only mode (saves bandwidth)",
|
||||
"audioRoute": "Select the audio route",
|
||||
"callQuality": "Manage call quality",
|
||||
"enterFullScreen": "View full screen",
|
||||
"exitFullScreen": "Exit full screen",
|
||||
|
@ -87,6 +88,7 @@
|
|||
"etherpad": "Open / Close shared document",
|
||||
"documentOpen": "Open shared document",
|
||||
"documentClose": "Close shared document",
|
||||
"shareRoom": "Share room",
|
||||
"sharedvideo": "Share a YouTube video",
|
||||
"stopSharedVideo": "Stop YouTube video",
|
||||
"fullscreen": "View / Exit full screen",
|
||||
|
@ -102,6 +104,7 @@
|
|||
"cameraDisabled": "Camera is not available",
|
||||
"micDisabled": "Microphone is not available",
|
||||
"filmstrip": "Show / Hide videos",
|
||||
"pip": "Enter Picture-in-Picture mode",
|
||||
"profile": "Edit your profile",
|
||||
"raiseHand": "Raise / Lower your hand",
|
||||
"shortcuts": "View shortcuts",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
export { default as AddPeopleDialog } from './AddPeopleDialog';
|
||||
export { default as InfoDialogButton } from './InfoDialogButton';
|
||||
export { default as InviteButton } from './InviteButton';
|
||||
export { DialInSummary } from './dial-in-summary';
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getAppProp } from '../../../app';
|
||||
import { ToolbarButton } from '../../../toolbox';
|
||||
|
||||
import { enterPictureInPicture } from '../actions';
|
||||
|
||||
/**
|
||||
* The type of {@link EnterPictureInPictureToobarButton}'s React
|
||||
* {@code Component} props.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Enters (or rather initiates entering) picture-in-picture.
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
_onEnterPictureInPicture: Function,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether Picture-in-Picture is enabled.
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
_pictureInPictureEnabled: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a {@link ToolbarButton} to enter Picture-in-Picture.
|
||||
*/
|
||||
class EnterPictureInPictureToolbarButton extends Component<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_onEnterPictureInPicture,
|
||||
_pictureInPictureEnabled,
|
||||
...props
|
||||
} = this.props;
|
||||
|
||||
if (!_pictureInPictureEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ToolbarButton
|
||||
iconName = { 'menu-down' }
|
||||
onClick = { _onEnterPictureInPicture }
|
||||
{ ...props } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps redux actions to {@link EnterPictureInPictureToolbarButton}'s React
|
||||
* {@code Component} props.
|
||||
*
|
||||
* @param {Function} dispatch - The redux action {@code dispatch} function.
|
||||
* @returns {{
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
function _mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* Requests Picture-in-Picture mode.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
_onEnterPictureInPicture() {
|
||||
dispatch(enterPictureInPicture());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to
|
||||
* {@link EnterPictureInPictureToolbarButton}'s React {@code Component} props.
|
||||
*
|
||||
* @param {Object} state - The redux store/state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* The indicator which determines whether Picture-in-Picture is enabled.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_pictureInPictureEnabled:
|
||||
Boolean(getAppProp(state, 'pictureInPictureEnabled'))
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps, _mapDispatchToProps)(
|
||||
EnterPictureInPictureToolbarButton);
|
|
@ -1,2 +0,0 @@
|
|||
export { default as EnterPictureInPictureToolbarButton }
|
||||
from './EnterPictureInPictureToolbarButton';
|
|
@ -1,3 +1,2 @@
|
|||
export * from './actions';
|
||||
export * from './actionTypes';
|
||||
export * from './components';
|
||||
|
|
|
@ -4,91 +4,75 @@ import React, { Component } from 'react';
|
|||
import { View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { toggleAudioOnly } from '../../base/conference';
|
||||
import {
|
||||
MEDIA_TYPE,
|
||||
toggleCameraFacingMode
|
||||
} from '../../base/media';
|
||||
import { Container } from '../../base/react';
|
||||
import {
|
||||
isNarrowAspectRatio,
|
||||
makeAspectRatioAware
|
||||
} from '../../base/responsive-ui';
|
||||
import { ColorPalette } from '../../base/styles';
|
||||
import { InviteButton } from '../../invite';
|
||||
import {
|
||||
EnterPictureInPictureToolbarButton
|
||||
} from '../../mobile/picture-in-picture';
|
||||
import { beginRoomLockRequest } from '../../room-lock';
|
||||
|
||||
import {
|
||||
abstractMapDispatchToProps,
|
||||
abstractMapStateToProps
|
||||
} from '../functions';
|
||||
|
||||
import AudioRouteButton from './AudioRouteButton';
|
||||
import styles from './styles';
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
|
||||
import { AudioMuteButton, HangupButton, VideoMuteButton } from './buttons';
|
||||
import {
|
||||
AudioMuteButton,
|
||||
AudioOnlyButton,
|
||||
AudioRouteButton,
|
||||
HangupButton,
|
||||
PictureInPictureButton,
|
||||
RoomLockButton,
|
||||
InviteButton,
|
||||
ToggleCameraButton,
|
||||
VideoMuteButton
|
||||
} from './buttons';
|
||||
|
||||
/**
|
||||
* Styles for the hangup button.
|
||||
*/
|
||||
const hangupButtonStyles = {
|
||||
iconStyle: styles.whitePrimaryToolbarButtonIcon,
|
||||
style: styles.hangup,
|
||||
underlayColor: ColorPalette.buttonUnderlay
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles for buttons in the primary toolbar.
|
||||
*/
|
||||
const primaryToolbarButtonStyles = {
|
||||
iconStyle: styles.primaryToolbarButtonIcon,
|
||||
style: styles.primaryToolbarButton
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles for buttons in the primary toolbar.
|
||||
*/
|
||||
const primaryToolbarToggledButtonStyles = {
|
||||
iconStyle: styles.whitePrimaryToolbarButtonIcon,
|
||||
style: styles.whitePrimaryToolbarButton
|
||||
};
|
||||
|
||||
/**
|
||||
* Styles for buttons in the secondary toolbar.
|
||||
*/
|
||||
const secondaryToolbarButtonStyles = {
|
||||
iconStyle: styles.secondaryToolbarButtonIcon,
|
||||
style: styles.secondaryToolbarButton,
|
||||
underlayColor: 'transparent'
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of {@link Toolbox}'s React {@code Component} props.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Flag showing that audio is muted.
|
||||
*/
|
||||
_audioMuted: boolean,
|
||||
|
||||
/**
|
||||
* Flag showing whether the audio-only mode is in use.
|
||||
*/
|
||||
_audioOnly: boolean,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the toolbox is enabled.
|
||||
*/
|
||||
_enabled: boolean,
|
||||
|
||||
/**
|
||||
* Flag showing whether room is locked.
|
||||
*/
|
||||
_locked: boolean,
|
||||
|
||||
/**
|
||||
* Handler for hangup.
|
||||
*/
|
||||
_onHangup: Function,
|
||||
|
||||
/**
|
||||
* Sets the lock i.e. password protection of the conference/room.
|
||||
*/
|
||||
_onRoomLock: Function,
|
||||
|
||||
/**
|
||||
* Toggles the audio-only flag of the conference.
|
||||
*/
|
||||
_onToggleAudioOnly: Function,
|
||||
|
||||
/**
|
||||
* Switches between the front/user-facing and back/environment-facing
|
||||
* cameras.
|
||||
*/
|
||||
_onToggleCameraFacingMode: Function,
|
||||
|
||||
/**
|
||||
* Flag showing whether video is muted.
|
||||
*/
|
||||
_videoMuted: boolean,
|
||||
|
||||
/**
|
||||
* Flag showing whether toolbar is visible.
|
||||
*/
|
||||
_visible: boolean,
|
||||
|
||||
dispatch: Function
|
||||
_visible: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -120,36 +104,6 @@ class Toolbox extends Component<Props> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the styles for a button that toggles the mute state of a specific
|
||||
* media type.
|
||||
*
|
||||
* @param {string} mediaType - The {@link MEDIA_TYPE} associated with the
|
||||
* button to get styles for.
|
||||
* @protected
|
||||
* @returns {{
|
||||
* iconStyle: Object,
|
||||
* style: Object
|
||||
* }}
|
||||
*/
|
||||
_getMuteButtonStyles(mediaType) {
|
||||
let iconStyle;
|
||||
let style;
|
||||
|
||||
if (this.props[`_${mediaType}Muted`]) {
|
||||
iconStyle = styles.whitePrimaryToolbarButtonIcon;
|
||||
style = styles.whitePrimaryToolbarButton;
|
||||
} else {
|
||||
iconStyle = styles.primaryToolbarButtonIcon;
|
||||
style = styles.primaryToolbarButton;
|
||||
}
|
||||
|
||||
return {
|
||||
iconStyle,
|
||||
style
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the toolbar which contains the primary buttons such as hangup,
|
||||
* audio and video mute.
|
||||
|
@ -158,28 +112,20 @@ class Toolbox extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderPrimaryToolbar() {
|
||||
const audioButtonStyles = this._getMuteButtonStyles(MEDIA_TYPE.AUDIO);
|
||||
const videoButtonStyles = this._getMuteButtonStyles(MEDIA_TYPE.VIDEO);
|
||||
const hangupButtonStyles = {
|
||||
iconStyle: styles.whitePrimaryToolbarButtonIcon,
|
||||
style: styles.hangup,
|
||||
underlayColor: ColorPalette.buttonUnderlay
|
||||
};
|
||||
|
||||
/* eslint-disable react/jsx-handler-names */
|
||||
|
||||
return (
|
||||
<View
|
||||
key = 'primaryToolbar'
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.primaryToolbar }>
|
||||
<AudioMuteButton styles = { audioButtonStyles } />
|
||||
<AudioMuteButton
|
||||
styles = { primaryToolbarButtonStyles }
|
||||
toggledStyles = { primaryToolbarToggledButtonStyles } />
|
||||
<HangupButton styles = { hangupButtonStyles } />
|
||||
<VideoMuteButton styles = { videoButtonStyles } />
|
||||
<VideoMuteButton
|
||||
styles = { primaryToolbarButtonStyles }
|
||||
toggledStyles = { primaryToolbarToggledButtonStyles } />
|
||||
</View>
|
||||
);
|
||||
|
||||
/* eslint-enable react/jsx-handler-names */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -190,62 +136,20 @@ class Toolbox extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSecondaryToolbar() {
|
||||
const iconStyle = styles.secondaryToolbarButtonIcon;
|
||||
const style = styles.secondaryToolbarButton;
|
||||
const underlayColor = 'transparent';
|
||||
const {
|
||||
_audioOnly: audioOnly,
|
||||
_videoMuted: videoMuted
|
||||
} = this.props;
|
||||
|
||||
/* eslint-disable react/jsx-curly-spacing,react/jsx-handler-names */
|
||||
|
||||
return (
|
||||
<View
|
||||
key = 'secondaryToolbar'
|
||||
pointerEvents = 'box-none'
|
||||
style = { styles.secondaryToolbar }>
|
||||
{
|
||||
AudioRouteButton
|
||||
&& <AudioRouteButton
|
||||
iconName = { 'volume' }
|
||||
iconStyle = { iconStyle }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
}
|
||||
<ToolbarButton
|
||||
disabled = { audioOnly || videoMuted }
|
||||
iconName = 'switch-camera'
|
||||
iconStyle = { iconStyle }
|
||||
onClick = { this.props._onToggleCameraFacingMode }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
<ToolbarButton
|
||||
iconName = { audioOnly ? 'visibility-off' : 'visibility' }
|
||||
iconStyle = { iconStyle }
|
||||
onClick = { this.props._onToggleAudioOnly }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
<ToolbarButton
|
||||
iconName = {
|
||||
this.props._locked ? 'security-locked' : 'security'
|
||||
}
|
||||
iconStyle = { iconStyle }
|
||||
onClick = { this.props._onRoomLock }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
<InviteButton
|
||||
iconStyle = { iconStyle }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
<EnterPictureInPictureToolbarButton
|
||||
iconStyle = { iconStyle }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
<AudioRouteButton styles = { secondaryToolbarButtonStyles } />
|
||||
<ToggleCameraButton styles = { secondaryToolbarButtonStyles } />
|
||||
<AudioOnlyButton styles = { secondaryToolbarButtonStyles } />
|
||||
<RoomLockButton styles = { secondaryToolbarButtonStyles } />
|
||||
<InviteButton styles = { secondaryToolbarButtonStyles } />
|
||||
<PictureInPictureButton
|
||||
styles = { secondaryToolbarButtonStyles } />
|
||||
</View>
|
||||
);
|
||||
|
||||
/* eslint-enable react/jsx-curly-spacing,react/jsx-handler-names */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,84 +167,21 @@ class Toolbox extends Component<Props> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Maps redux actions to {@link Toolbox}'s React {@code Component} props.
|
||||
*
|
||||
* @param {Function} dispatch - The redux action {@code dispatch} function.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _onRoomLock: Function,
|
||||
* _onToggleAudioOnly: Function,
|
||||
* _onToggleCameraFacingMode: Function,
|
||||
* }}
|
||||
*/
|
||||
function _mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
...abstractMapDispatchToProps(dispatch),
|
||||
|
||||
/**
|
||||
* Sets the lock i.e. password protection of the conference/room.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
_onRoomLock() {
|
||||
dispatch(beginRoomLockRequest());
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the audio-only flag of the conference.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
_onToggleAudioOnly() {
|
||||
dispatch(toggleAudioOnly());
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches between the front/user-facing and back/environment-facing
|
||||
* cameras.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
_onToggleCameraFacingMode() {
|
||||
dispatch(toggleCameraFacingMode());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to {@link Toolbox}'s React {@code Component}
|
||||
* Maps parts of the redux state to {@link Toolbox} (React {@code Component})
|
||||
* props.
|
||||
*
|
||||
* @param {Object} state - The redux store/state.
|
||||
* @private
|
||||
* @param {Object} state - The redux state of which parts are to be mapped to
|
||||
* {@code Toolbox} props.
|
||||
* @protected
|
||||
* @returns {{
|
||||
* _audioOnly: boolean,
|
||||
* _enabled: boolean,
|
||||
* _locked: boolean
|
||||
* _visible: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const conference = state['features/base/conference'];
|
||||
const { enabled } = state['features/toolbox'];
|
||||
function _mapStateToProps(state: Object): Object {
|
||||
const { enabled, visible } = state['features/toolbox'];
|
||||
|
||||
return {
|
||||
...abstractMapStateToProps(state),
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the conference is in
|
||||
* audio-only mode.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_audioOnly: Boolean(conference.audioOnly),
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the toolbox is enabled.
|
||||
*
|
||||
|
@ -350,15 +191,13 @@ function _mapStateToProps(state) {
|
|||
_enabled: enabled,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the conference is
|
||||
* locked/password-protected.
|
||||
* Flag showing whether toolbox is visible.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_locked: Boolean(conference.locked)
|
||||
_visible: visible
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(_mapStateToProps, _mapDispatchToProps)(
|
||||
makeAspectRatioAware(Toolbox));
|
||||
export default connect(_mapStateToProps)(makeAspectRatioAware(Toolbox));
|
||||
|
|
|
@ -37,7 +37,7 @@ export type Props = {
|
|||
/**
|
||||
* An abstract implementation of a button.
|
||||
*/
|
||||
export default class AbstractButton<P: Props, S : *> extends Component<P, S> {
|
||||
export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
|
||||
static defaultProps = {
|
||||
showLabel: false,
|
||||
styles: undefined,
|
||||
|
@ -173,9 +173,9 @@ export default class AbstractButton<P: Props, S : *> extends Component<P, S> {
|
|||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
render() {
|
||||
render(): React$Node {
|
||||
const props = {
|
||||
...this.props,
|
||||
accessibilityLabel: this.accessibilityLabel,
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { toggleAudioOnly } from '../../../../base/conference';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* Whether the current conference is in audio only mode or not.
|
||||
*/
|
||||
_audioOnly: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for toggling the audio-only mode.
|
||||
*/
|
||||
class AudioOnlyButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Audio only mode';
|
||||
iconName = 'visibility';
|
||||
label = 'toolbar.audioonly';
|
||||
toggledIconName = 'visibility-off';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
this.props.dispatch(toggleAudioOnly());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is in toggled state or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isToggled() {
|
||||
return this.props._audioOnly;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code AudioOnlyButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _audioOnly: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
const { audioOnly } = state['features/base/conference'];
|
||||
|
||||
return {
|
||||
_audioOnly: Boolean(audioOnly)
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(AudioOnlyButton));
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
findNodeHandle,
|
||||
NativeModules,
|
||||
|
@ -9,10 +9,13 @@ import {
|
|||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { openDialog } from '../../base/dialog';
|
||||
import { AudioRoutePickerDialog } from '../../mobile/audio-mode';
|
||||
import { openDialog } from '../../../../base/dialog';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { AudioRoutePickerDialog } from '../../../../mobile/audio-mode';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
import ToolbarButton from './ToolbarButton';
|
||||
|
||||
/**
|
||||
* The {@code MPVolumeView} React {@code Component}. It will only be available
|
||||
|
@ -28,48 +31,32 @@ const MPVolumeView
|
|||
*/
|
||||
const HIDE_VIEW_STYLE = { display: 'none' };
|
||||
|
||||
type Props = {
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function used to open/show the
|
||||
* {@code AudioRoutePickerDialog}.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* The name of the Icon of this {@code AudioRouteButton}.
|
||||
*/
|
||||
iconName: string,
|
||||
|
||||
/**
|
||||
* The style of the Icon of this {@code AudioRouteButton}.
|
||||
*/
|
||||
iconStyle: Object,
|
||||
|
||||
/**
|
||||
* The style(s) of {@code AudioRouteButton}.
|
||||
*/
|
||||
style: Array<*> | Object,
|
||||
|
||||
/**
|
||||
* The color underlaying the button.
|
||||
*/
|
||||
underlayColor: string
|
||||
dispatch: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* A toolbar button which triggers an audio route picker when pressed.
|
||||
*/
|
||||
class AudioRouteButton extends Component<Props> {
|
||||
class AudioRouteButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Audio route';
|
||||
iconName = 'icon-volume';
|
||||
label = 'toolbar.audioRoute';
|
||||
|
||||
_volumeComponent: ?Object;
|
||||
|
||||
/**
|
||||
* Initializes a new {@code AudioRouteButton} instance.
|
||||
*
|
||||
* @param {Object} props - The React {@code Component} props to initialize
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new {@code AudioRouteButton} instance with.
|
||||
*/
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
|
@ -77,25 +64,21 @@ class AudioRouteButton extends Component<Props> {
|
|||
* showing the volume control view.
|
||||
*
|
||||
* @private
|
||||
* @type {ReactComponent}
|
||||
* @type {ReactElement}
|
||||
*/
|
||||
this._volumeComponent = null;
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._setVolumeComponent = this._setVolumeComponent.bind(this);
|
||||
}
|
||||
|
||||
_onClick: () => void;
|
||||
|
||||
/**
|
||||
* Handles clicking/pressing this {@code AudioRouteButton} by showing an
|
||||
* audio route picker.
|
||||
* Handles clicking / pressing the button, and opens the appropriate dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onClick() {
|
||||
_handleClick() {
|
||||
if (MPVolumeView) {
|
||||
NativeModules.MPVolumeViewManager.show(
|
||||
findNodeHandle(this._volumeComponent));
|
||||
|
@ -104,23 +87,49 @@ class AudioRouteButton extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
_setVolumeComponent: (?Object) => void;
|
||||
|
||||
/**
|
||||
* Sets the internal reference to the React Component wrapping the
|
||||
* {@code MPVolumeView} component.
|
||||
*
|
||||
* @param {ReactElement} component - React Component.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setVolumeComponent(component) {
|
||||
this._volumeComponent = component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
* @returns {?ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { iconName, iconStyle, style, underlayColor } = this.props;
|
||||
if (!MPVolumeView && !AudioRoutePickerDialog) {
|
||||
|
||||
// $FlowFixMe
|
||||
return null;
|
||||
}
|
||||
|
||||
const element = super.render();
|
||||
|
||||
return (
|
||||
<View>
|
||||
<ToolbarButton
|
||||
iconName = { iconName }
|
||||
iconStyle = { iconStyle }
|
||||
onClick = { this._onClick }
|
||||
style = { style }
|
||||
underlayColor = { underlayColor } />
|
||||
{ element }
|
||||
{
|
||||
MPVolumeView
|
||||
&& <MPVolumeView
|
||||
|
@ -130,21 +139,6 @@ class AudioRouteButton extends Component<Props> {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_setVolumeComponent: (?Object) => void;
|
||||
|
||||
/**
|
||||
* Sets the internal reference to the React Component wrapping the
|
||||
* {@code MPVolumeView} component.
|
||||
*
|
||||
* @param {ReactComponent} component - React Component.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setVolumeComponent(component) {
|
||||
this._volumeComponent = component;
|
||||
}
|
||||
}
|
||||
|
||||
export default (MPVolumeView || AudioRoutePickerDialog)
|
||||
&& connect()(AudioRouteButton);
|
||||
export default translate(connect()(AudioRouteButton));
|
|
@ -1,29 +1,18 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { beginShareRoom } from '../../share-room';
|
||||
import { ToolbarButton } from '../../toolbox';
|
||||
import {
|
||||
beginAddPeople,
|
||||
isAddPeopleEnabled,
|
||||
isDialOutEnabled
|
||||
} from '../../../../invite';
|
||||
import { beginShareRoom } from '../../../../share-room';
|
||||
|
||||
import { beginAddPeople } from '../actions';
|
||||
import { isAddPeopleEnabled, isDialOutEnabled } from '../functions';
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
/**
|
||||
* The indicator which determines (at bundle time) whether there should be a
|
||||
* {@code ToolbarButton} in {@code Toolbox} to expose the functionality of the
|
||||
* feature share-room in the user interface of the app.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
const _SHARE_ROOM_TOOLBAR_BUTTON = true;
|
||||
|
||||
/**
|
||||
* The type of {@link EnterPictureInPictureToobarButton}'s React
|
||||
* {@code Component} props.
|
||||
*/
|
||||
type Props = {
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* Whether or not the feature to directly invite people into the
|
||||
|
@ -50,45 +39,71 @@ type Props = {
|
|||
_onShareRoom: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* The indicator which determines (at bundle time) whether there should be a
|
||||
* button in {@code Toolbox} to expose the functionality of the feature
|
||||
* share-room in the user interface of the app.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
const _SHARE_ROOM_TOOLBAR_BUTTON = true;
|
||||
|
||||
/**
|
||||
* Implements a {@link ToolbarButton} to enter Picture-in-Picture.
|
||||
*/
|
||||
class InviteButton extends Component<Props> {
|
||||
class InviteButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Share room';
|
||||
iconName = 'icon-link';
|
||||
label = 'toolbar.shareRoom';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button, and opens the appropriate dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
const {
|
||||
_addPeopleEnabled,
|
||||
_dialOutEnabled,
|
||||
_onAddPeople,
|
||||
_onShareRoom
|
||||
} = this.props;
|
||||
|
||||
if (_addPeopleEnabled || _dialOutEnabled) {
|
||||
_onAddPeople();
|
||||
} else if (_SHARE_ROOM_TOOLBAR_BUTTON) {
|
||||
_onShareRoom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
* @returns {React$Node}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
_addPeopleEnabled,
|
||||
_dialOutEnabled,
|
||||
_onAddPeople,
|
||||
_onShareRoom,
|
||||
...props
|
||||
} = this.props;
|
||||
const { _addPeopleEnabled, _dialOutEnabled } = this.props;
|
||||
|
||||
if (_addPeopleEnabled || _dialOutEnabled) {
|
||||
return (
|
||||
<ToolbarButton
|
||||
iconName = { 'link' }
|
||||
onClick = { _onAddPeople }
|
||||
{ ...props } />
|
||||
);
|
||||
}
|
||||
|
||||
if (_SHARE_ROOM_TOOLBAR_BUTTON) {
|
||||
return (
|
||||
<ToolbarButton
|
||||
iconName = 'link'
|
||||
onClick = { _onShareRoom }
|
||||
{ ...props } />
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return (
|
||||
_SHARE_ROOM_TOOLBAR_BUTTON
|
||||
|| _addPeopleEnabled
|
||||
|| _dialOutEnabled
|
||||
? super.render()
|
||||
: null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { getAppProp } from '../../../../app';
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { enterPictureInPicture } from '../../../../mobile/picture-in-picture';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* Whether Picture-in-Picture is enabled or not.
|
||||
*/
|
||||
_enabled: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of a button for entering Picture-in-Picture mode.
|
||||
*/
|
||||
class PictureInPictureButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Picture in picture';
|
||||
iconName = 'icon-menu-down';
|
||||
label = 'toolbar.pip';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
this.props.dispatch(enterPictureInPicture());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {?ReactElement}
|
||||
*/
|
||||
render() {
|
||||
if (!this.props._enabled) {
|
||||
|
||||
// $FlowFixMe
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.render();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code PictureInPictureButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _enabled: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
return {
|
||||
_enabled: Boolean(getAppProp(state, 'pictureInPictureEnabled'))
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(PictureInPictureButton));
|
|
@ -0,0 +1,90 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { beginRoomLockRequest } from '../../../../room-lock';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The current conference.
|
||||
*/
|
||||
_conference: Object,
|
||||
|
||||
/**
|
||||
* Whether the current conference is locked or not.
|
||||
*/
|
||||
_locked: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for locking / unlocking a room.
|
||||
*/
|
||||
class RoomLockButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Room lock';
|
||||
iconName = 'security';
|
||||
label = 'toolbar.lock';
|
||||
toggledIconName = 'security-locked';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
this.props.dispatch(beginRoomLockRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return !this.props._conference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is in toggled state or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isToggled() {
|
||||
return this.props._locked;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code RoomLockButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _audioOnly: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
const { conference, locked } = state['features/base/conference'];
|
||||
|
||||
return {
|
||||
_conference: conference,
|
||||
_locked: Boolean(conference && locked)
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(RoomLockButton));
|
|
@ -0,0 +1,50 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { beginShareRoom } from '../../../../share-room';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for sharing a room using the native OS sharing
|
||||
* capabilities.
|
||||
*/
|
||||
class ShareRoomButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Share room';
|
||||
iconName = 'icon-link';
|
||||
label = 'toolbar.shareRoom';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button, and opens the appropriate dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
this.props.dispatch(beginShareRoom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect()(ShareRoomButton));
|
|
@ -0,0 +1,81 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { MEDIA_TYPE, toggleCameraFacingMode } from '../../../../base/media';
|
||||
import { isLocalTrackMuted } from '../../../../base/tracks';
|
||||
|
||||
import AbstractButton from '../AbstractButton';
|
||||
import type { Props as AbstractButtonProps } from '../AbstractButton';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* Whether the current conference is in audio only mode or not.
|
||||
*/
|
||||
_audioOnly: boolean,
|
||||
|
||||
/**
|
||||
* Whether video is currently muted or not.
|
||||
*/
|
||||
_videoMuted: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for toggling the camera facing mode.
|
||||
*/
|
||||
class ToggleCameraButton extends AbstractButton<Props, *> {
|
||||
accessibilityLabel = 'Share room';
|
||||
iconName = 'icon-switch-camera';
|
||||
label = 'toolbar.switchCamera';
|
||||
|
||||
/**
|
||||
* Handles clicking / pressing the button.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleClick() {
|
||||
this.props.dispatch(toggleCameraFacingMode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this button is disabled or not.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isDisabled() {
|
||||
return this.props._audioOnly || this.props._videoMuted;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated props for the
|
||||
* {@code ToggleCameraButton} component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _audioOnly: boolean,
|
||||
* _videoMuted: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
const { audioOnly } = state['features/base/conference'];
|
||||
const tracks = state['features/base/tracks'];
|
||||
|
||||
return {
|
||||
_audioOnly: Boolean(audioOnly),
|
||||
_videoMuted: isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO)
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(ToggleCameraButton));
|
|
@ -0,0 +1,6 @@
|
|||
export { default as AudioOnlyButton } from './AudioOnlyButton';
|
||||
export { default as AudioRouteButton } from './AudioRouteButton';
|
||||
export { default as InviteButton } from './InviteButton';
|
||||
export { default as PictureInPictureButton } from './PictureInPictureButton';
|
||||
export { default as RoomLockButton } from './RoomLockButton';
|
||||
export { default as ToggleCameraButton } from './ToggleCameraButton';
|
|
@ -80,6 +80,15 @@ export default createStyleSheet({
|
|||
backgroundColor: ColorPalette.red
|
||||
},
|
||||
|
||||
/**
|
||||
* The icon style of toolbar buttons in {@link #primaryToolbar} which
|
||||
* hangs the current conference up.
|
||||
*/
|
||||
hangupButtonIcon: {
|
||||
...primaryToolbarButtonIcon,
|
||||
color: ColorPalette.white
|
||||
},
|
||||
|
||||
/**
|
||||
* The style of the toolbar which contains the primary buttons such as
|
||||
* hangup, audio and video mute.
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { appNavigate } from '../app';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { isLocalTrackMuted } from '../base/tracks';
|
||||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
/**
|
||||
* Maps redux actions to {@link Toolbox} (React {@code Component}) props.
|
||||
*
|
||||
* @param {Function} dispatch - The redux {@code dispatch} function.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _onHangup: Function,
|
||||
* _onToggleAudio: Function,
|
||||
* _onToggleVideo: Function
|
||||
* }}
|
||||
*/
|
||||
export function abstractMapDispatchToProps(dispatch: Dispatch<*>): Object {
|
||||
return {
|
||||
// Inject {@code dispatch} into the React Component's props in case it
|
||||
// needs to dispatch an action in the redux store without
|
||||
// {@code mapDispatchToProps}.
|
||||
dispatch,
|
||||
|
||||
/**
|
||||
* Dispatches action to leave the current conference.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
_onHangup() {
|
||||
// XXX We don't know here which value is effectively/internally
|
||||
// used when there's no valid room name to join. It isn't our
|
||||
// business to know that anyway. The undefined value is our
|
||||
// expression of (1) the lack of knowledge & (2) the desire to no
|
||||
// longer have a valid room name to join.
|
||||
dispatch(appNavigate(undefined));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps parts of the redux state to {@link Toolbox} (React {@code Component})
|
||||
* props.
|
||||
*
|
||||
* @param {Object} state - The redux state of which parts are to be mapped to
|
||||
* {@code Toolbox} props.
|
||||
* @protected
|
||||
* @returns {{
|
||||
* _audioMuted: boolean,
|
||||
* _videoMuted: boolean,
|
||||
* _visible: boolean
|
||||
* }}
|
||||
*/
|
||||
export function abstractMapStateToProps(state: Object): Object {
|
||||
const tracks = state['features/base/tracks'];
|
||||
const { visible } = state['features/toolbox'];
|
||||
|
||||
return {
|
||||
/**
|
||||
* Flag showing whether audio is muted.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_audioMuted: isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO),
|
||||
|
||||
/**
|
||||
* Flag showing whether video is muted.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_videoMuted: isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO),
|
||||
|
||||
/**
|
||||
* Flag showing whether toolbox is visible.
|
||||
*
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
*/
|
||||
_visible: visible
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the button object corresponding to a specific {@code buttonName}.
|
||||
*
|
||||
* @param {string} buttonName - The name of the button.
|
||||
* @param {Object} state - The current state.
|
||||
* @returns {Object} - The button object.
|
||||
*/
|
||||
export function getButton(buttonName: string, state: Object) {
|
||||
const { primaryToolbarButtons, secondaryToolbarButtons }
|
||||
= state['features/toolbox'];
|
||||
|
||||
return primaryToolbarButtons.get(buttonName)
|
||||
|| secondaryToolbarButtons.get(buttonName);
|
||||
}
|
|
@ -2,12 +2,6 @@
|
|||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
export {
|
||||
abstractMapDispatchToProps,
|
||||
abstractMapStateToProps,
|
||||
getButton
|
||||
} from './functions.native';
|
||||
|
||||
/**
|
||||
* Helper for getting the height of the toolbox.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue