2017-11-16 18:26:14 +00:00
|
|
|
// @flow
|
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
|
2019-08-30 16:39:06 +00:00
|
|
|
import { Icon, IconMenuThumb } from '../../../base/icons';
|
2020-02-18 16:31:04 +00:00
|
|
|
import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
|
2018-12-19 18:40:17 +00:00
|
|
|
import { Popover } from '../../../base/popover';
|
2020-02-18 16:31:04 +00:00
|
|
|
import { connect } from '../../../base/redux';
|
2017-09-27 21:23:31 +00:00
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
import {
|
2020-07-15 10:13:28 +00:00
|
|
|
GrantModeratorButton,
|
2017-08-14 15:02:58 +00:00
|
|
|
MuteButton,
|
2020-02-24 12:47:37 +00:00
|
|
|
MuteEveryoneElseButton,
|
2017-08-14 15:02:58 +00:00
|
|
|
KickButton,
|
2019-10-07 12:35:04 +00:00
|
|
|
PrivateMessageMenuButton,
|
2017-08-14 15:02:58 +00:00
|
|
|
RemoteControlButton,
|
|
|
|
RemoteVideoMenu,
|
|
|
|
VolumeSlider
|
|
|
|
} from './';
|
|
|
|
|
|
|
|
declare var $: Object;
|
|
|
|
declare var interfaceConfig: Object;
|
|
|
|
|
2018-07-23 21:18:20 +00:00
|
|
|
/**
|
|
|
|
* The type of the React {@code Component} props of
|
|
|
|
* {@link RemoteVideoMenuTriggerButton}.
|
|
|
|
*/
|
|
|
|
type Props = {
|
|
|
|
|
2020-03-25 21:28:31 +00:00
|
|
|
/**
|
|
|
|
* Whether or not to display the kick button.
|
|
|
|
*/
|
|
|
|
_disableKick: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not to display the remote mute buttons.
|
|
|
|
*/
|
|
|
|
_disableRemoteMute: Boolean,
|
|
|
|
|
2020-02-18 16:31:04 +00:00
|
|
|
/**
|
|
|
|
* Whether or not the participant is a conference moderator.
|
|
|
|
*/
|
|
|
|
_isModerator: boolean,
|
|
|
|
|
2018-07-23 21:18:20 +00:00
|
|
|
/**
|
|
|
|
* A value between 0 and 1 indicating the volume of the participant's
|
|
|
|
* audio element.
|
|
|
|
*/
|
|
|
|
initialVolumeValue: number,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not the participant is currently muted.
|
|
|
|
*/
|
|
|
|
isAudioMuted: boolean,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback to invoke when the popover has been displayed.
|
|
|
|
*/
|
|
|
|
onMenuDisplay: Function,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback to invoke choosing to start a remote control session with
|
|
|
|
* the participant.
|
|
|
|
*/
|
|
|
|
onRemoteControlToggle: Function,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback to invoke when changing the level of the participant's
|
|
|
|
* audio element.
|
|
|
|
*/
|
|
|
|
onVolumeChange: Function,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The position relative to the trigger the remote menu should display
|
|
|
|
* from. Valid values are those supported by AtlasKit
|
|
|
|
* {@code InlineDialog}.
|
|
|
|
*/
|
|
|
|
menuPosition: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The ID for the participant on which the remote video menu will act.
|
|
|
|
*/
|
|
|
|
participantID: string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The current state of the participant's remote control session.
|
|
|
|
*/
|
|
|
|
remoteControlState: number
|
|
|
|
};
|
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
/**
|
|
|
|
* React {@code Component} for displaying an icon associated with opening the
|
|
|
|
* the {@code RemoteVideoMenu}.
|
|
|
|
*
|
|
|
|
* @extends {Component}
|
|
|
|
*/
|
2018-07-23 21:18:20 +00:00
|
|
|
class RemoteVideoMenuTriggerButton extends Component<Props> {
|
2017-11-16 18:26:14 +00:00
|
|
|
/**
|
|
|
|
* The internal reference to topmost DOM/HTML element backing the React
|
|
|
|
* {@code Component}. Accessed directly for associating an element as
|
|
|
|
* the trigger for a popover.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @type {HTMLDivElement}
|
|
|
|
*/
|
|
|
|
_rootElement = null;
|
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
/**
|
|
|
|
* Initializes a new {#@code RemoteVideoMenuTriggerButton} instance.
|
|
|
|
*
|
|
|
|
* @param {Object} props - The read-only properties with which the new
|
|
|
|
* instance is to be initialized.
|
|
|
|
*/
|
2017-11-16 18:26:14 +00:00
|
|
|
constructor(props: Object) {
|
2017-08-14 15:02:58 +00:00
|
|
|
super(props);
|
|
|
|
|
2017-08-22 19:22:06 +00:00
|
|
|
// Bind event handler so it is only bound once for every instance.
|
2017-08-22 17:42:35 +00:00
|
|
|
this._onShowRemoteMenu = this._onShowRemoteMenu.bind(this);
|
2017-08-14 15:02:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#render()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
2017-08-17 16:43:22 +00:00
|
|
|
const content = this._renderRemoteVideoMenu();
|
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
return (
|
2017-08-22 19:22:06 +00:00
|
|
|
<Popover
|
|
|
|
content = { content }
|
|
|
|
onPopoverOpen = { this._onShowRemoteMenu }
|
2018-07-23 21:18:20 +00:00
|
|
|
position = { this.props.menuPosition }>
|
2017-08-22 19:22:06 +00:00
|
|
|
<span
|
|
|
|
className = 'popover-trigger remote-video-menu-trigger'>
|
2019-08-30 16:39:06 +00:00
|
|
|
<Icon
|
|
|
|
size = '1em'
|
|
|
|
src = { IconMenuThumb }
|
2017-08-22 19:22:06 +00:00
|
|
|
title = 'Remote user controls' />
|
|
|
|
</span>
|
|
|
|
</Popover>
|
2017-08-14 15:02:58 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-11-16 18:26:14 +00:00
|
|
|
_onShowRemoteMenu: () => void;
|
|
|
|
|
2017-08-14 15:02:58 +00:00
|
|
|
/**
|
2017-08-22 17:42:35 +00:00
|
|
|
* Opens the {@code RemoteVideoMenu}.
|
2017-08-14 15:02:58 +00:00
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2017-08-22 17:42:35 +00:00
|
|
|
_onShowRemoteMenu() {
|
|
|
|
this.props.onMenuDisplay();
|
2017-08-14 15:02:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new {@code RemoteVideoMenu} with buttons for interacting with
|
|
|
|
* the remote participant.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
_renderRemoteVideoMenu() {
|
|
|
|
const {
|
2020-03-25 21:28:31 +00:00
|
|
|
_disableKick,
|
|
|
|
_disableRemoteMute,
|
2020-02-18 16:31:04 +00:00
|
|
|
_isModerator,
|
2017-08-14 15:02:58 +00:00
|
|
|
initialVolumeValue,
|
|
|
|
isAudioMuted,
|
|
|
|
onRemoteControlToggle,
|
|
|
|
onVolumeChange,
|
|
|
|
remoteControlState,
|
|
|
|
participantID
|
|
|
|
} = this.props;
|
|
|
|
|
2017-08-17 16:43:22 +00:00
|
|
|
const buttons = [];
|
|
|
|
|
2020-02-18 16:31:04 +00:00
|
|
|
if (_isModerator) {
|
2020-03-25 21:28:31 +00:00
|
|
|
if (!_disableRemoteMute) {
|
|
|
|
buttons.push(
|
|
|
|
<MuteButton
|
|
|
|
isAudioMuted = { isAudioMuted }
|
|
|
|
key = 'mute'
|
|
|
|
participantID = { participantID } />
|
|
|
|
);
|
|
|
|
buttons.push(
|
|
|
|
<MuteEveryoneElseButton
|
|
|
|
key = 'mute-others'
|
|
|
|
participantID = { participantID } />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-07-15 10:13:28 +00:00
|
|
|
buttons.push(
|
|
|
|
<GrantModeratorButton
|
|
|
|
key = 'grant-moderator'
|
|
|
|
participantID = { participantID } />
|
|
|
|
);
|
|
|
|
|
2020-03-25 21:28:31 +00:00
|
|
|
if (!_disableKick) {
|
|
|
|
buttons.push(
|
|
|
|
<KickButton
|
|
|
|
key = 'kick'
|
|
|
|
participantID = { participantID } />
|
|
|
|
);
|
|
|
|
}
|
2017-08-17 16:43:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (remoteControlState) {
|
|
|
|
buttons.push(
|
|
|
|
<RemoteControlButton
|
|
|
|
key = 'remote-control'
|
|
|
|
onClick = { onRemoteControlToggle }
|
|
|
|
participantID = { participantID }
|
|
|
|
remoteControlState = { remoteControlState } />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-10-07 12:35:04 +00:00
|
|
|
buttons.push(
|
|
|
|
<PrivateMessageMenuButton
|
|
|
|
key = 'privateMessage'
|
|
|
|
participantID = { participantID } />
|
|
|
|
);
|
|
|
|
|
2017-11-15 01:56:48 +00:00
|
|
|
if (onVolumeChange) {
|
2017-08-17 16:43:22 +00:00
|
|
|
buttons.push(
|
|
|
|
<VolumeSlider
|
|
|
|
initialValue = { initialVolumeValue }
|
|
|
|
key = 'volume-slider'
|
|
|
|
onChange = { onVolumeChange } />
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buttons.length > 0) {
|
|
|
|
return (
|
2017-08-22 19:22:06 +00:00
|
|
|
<RemoteVideoMenu id = { participantID }>
|
|
|
|
{ buttons }
|
|
|
|
</RemoteVideoMenu>
|
2017-08-17 16:43:22 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
2017-08-14 15:02:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-18 16:31:04 +00:00
|
|
|
/**
|
|
|
|
* Maps (parts of) the Redux state to the associated {@code RemoteVideoMenuTriggerButton}'s props.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The Redux state.
|
|
|
|
* @param {Object} ownProps - The own props of the component.
|
|
|
|
* @private
|
|
|
|
* @returns {{
|
|
|
|
* _isModerator: boolean
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
function _mapStateToProps(state) {
|
|
|
|
const participant = getLocalParticipant(state);
|
2020-03-25 21:28:31 +00:00
|
|
|
const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
|
|
|
|
const { disableKick } = remoteVideoMenu;
|
2020-02-18 16:31:04 +00:00
|
|
|
|
|
|
|
return {
|
2020-03-25 21:28:31 +00:00
|
|
|
_isModerator: Boolean(participant?.role === PARTICIPANT_ROLE.MODERATOR),
|
|
|
|
_disableKick: Boolean(disableKick),
|
|
|
|
_disableRemoteMute: Boolean(disableRemoteMute)
|
2020-02-18 16:31:04 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export default connect(_mapStateToProps)(RemoteVideoMenuTriggerButton);
|