You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RemoteVideoMenuTriggerButton.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { Icon, IconMenuThumb } from '../../../base/icons';
  4. import { getLocalParticipant, PARTICIPANT_ROLE } from '../../../base/participants';
  5. import { Popover } from '../../../base/popover';
  6. import { connect } from '../../../base/redux';
  7. import {
  8. GrantModeratorButton,
  9. MuteButton,
  10. MuteEveryoneElseButton,
  11. KickButton,
  12. PrivateMessageMenuButton,
  13. RemoteControlButton,
  14. RemoteVideoMenu,
  15. VolumeSlider
  16. } from './';
  17. declare var $: Object;
  18. declare var interfaceConfig: Object;
  19. /**
  20. * The type of the React {@code Component} props of
  21. * {@link RemoteVideoMenuTriggerButton}.
  22. */
  23. type Props = {
  24. /**
  25. * Whether or not to display the kick button.
  26. */
  27. _disableKick: boolean,
  28. /**
  29. * Whether or not to display the remote mute buttons.
  30. */
  31. _disableRemoteMute: Boolean,
  32. /**
  33. * Whether or not the participant is a conference moderator.
  34. */
  35. _isModerator: boolean,
  36. /**
  37. * A value between 0 and 1 indicating the volume of the participant's
  38. * audio element.
  39. */
  40. initialVolumeValue: number,
  41. /**
  42. * Whether or not the participant is currently muted.
  43. */
  44. isAudioMuted: boolean,
  45. /**
  46. * Callback to invoke when the popover has been displayed.
  47. */
  48. onMenuDisplay: Function,
  49. /**
  50. * Callback to invoke choosing to start a remote control session with
  51. * the participant.
  52. */
  53. onRemoteControlToggle: Function,
  54. /**
  55. * Callback to invoke when changing the level of the participant's
  56. * audio element.
  57. */
  58. onVolumeChange: Function,
  59. /**
  60. * The position relative to the trigger the remote menu should display
  61. * from. Valid values are those supported by AtlasKit
  62. * {@code InlineDialog}.
  63. */
  64. menuPosition: string,
  65. /**
  66. * The ID for the participant on which the remote video menu will act.
  67. */
  68. participantID: string,
  69. /**
  70. * The current state of the participant's remote control session.
  71. */
  72. remoteControlState: number
  73. };
  74. /**
  75. * React {@code Component} for displaying an icon associated with opening the
  76. * the {@code RemoteVideoMenu}.
  77. *
  78. * @extends {Component}
  79. */
  80. class RemoteVideoMenuTriggerButton extends Component<Props> {
  81. /**
  82. * The internal reference to topmost DOM/HTML element backing the React
  83. * {@code Component}. Accessed directly for associating an element as
  84. * the trigger for a popover.
  85. *
  86. * @private
  87. * @type {HTMLDivElement}
  88. */
  89. _rootElement = null;
  90. /**
  91. * Initializes a new {#@code RemoteVideoMenuTriggerButton} instance.
  92. *
  93. * @param {Object} props - The read-only properties with which the new
  94. * instance is to be initialized.
  95. */
  96. constructor(props: Object) {
  97. super(props);
  98. // Bind event handler so it is only bound once for every instance.
  99. this._onShowRemoteMenu = this._onShowRemoteMenu.bind(this);
  100. }
  101. /**
  102. * Implements React's {@link Component#render()}.
  103. *
  104. * @inheritdoc
  105. * @returns {ReactElement}
  106. */
  107. render() {
  108. const content = this._renderRemoteVideoMenu();
  109. if (!content) {
  110. return null;
  111. }
  112. return (
  113. <Popover
  114. content = { content }
  115. onPopoverOpen = { this._onShowRemoteMenu }
  116. position = { this.props.menuPosition }>
  117. <span
  118. className = 'popover-trigger remote-video-menu-trigger'>
  119. <Icon
  120. size = '1em'
  121. src = { IconMenuThumb }
  122. title = 'Remote user controls' />
  123. </span>
  124. </Popover>
  125. );
  126. }
  127. _onShowRemoteMenu: () => void;
  128. /**
  129. * Opens the {@code RemoteVideoMenu}.
  130. *
  131. * @private
  132. * @returns {void}
  133. */
  134. _onShowRemoteMenu() {
  135. this.props.onMenuDisplay();
  136. }
  137. /**
  138. * Creates a new {@code RemoteVideoMenu} with buttons for interacting with
  139. * the remote participant.
  140. *
  141. * @private
  142. * @returns {ReactElement}
  143. */
  144. _renderRemoteVideoMenu() {
  145. const {
  146. _disableKick,
  147. _disableRemoteMute,
  148. _isModerator,
  149. initialVolumeValue,
  150. isAudioMuted,
  151. onRemoteControlToggle,
  152. onVolumeChange,
  153. remoteControlState,
  154. participantID
  155. } = this.props;
  156. const buttons = [];
  157. if (_isModerator) {
  158. if (!_disableRemoteMute) {
  159. buttons.push(
  160. <MuteButton
  161. isAudioMuted = { isAudioMuted }
  162. key = 'mute'
  163. participantID = { participantID } />
  164. );
  165. buttons.push(
  166. <MuteEveryoneElseButton
  167. key = 'mute-others'
  168. participantID = { participantID } />
  169. );
  170. }
  171. buttons.push(
  172. <GrantModeratorButton
  173. key = 'grant-moderator'
  174. participantID = { participantID } />
  175. );
  176. if (!_disableKick) {
  177. buttons.push(
  178. <KickButton
  179. key = 'kick'
  180. participantID = { participantID } />
  181. );
  182. }
  183. }
  184. if (remoteControlState) {
  185. buttons.push(
  186. <RemoteControlButton
  187. key = 'remote-control'
  188. onClick = { onRemoteControlToggle }
  189. participantID = { participantID }
  190. remoteControlState = { remoteControlState } />
  191. );
  192. }
  193. buttons.push(
  194. <PrivateMessageMenuButton
  195. key = 'privateMessage'
  196. participantID = { participantID } />
  197. );
  198. if (onVolumeChange) {
  199. buttons.push(
  200. <VolumeSlider
  201. initialValue = { initialVolumeValue }
  202. key = 'volume-slider'
  203. onChange = { onVolumeChange } />
  204. );
  205. }
  206. if (buttons.length > 0) {
  207. return (
  208. <RemoteVideoMenu id = { participantID }>
  209. { buttons }
  210. </RemoteVideoMenu>
  211. );
  212. }
  213. return null;
  214. }
  215. }
  216. /**
  217. * Maps (parts of) the Redux state to the associated {@code RemoteVideoMenuTriggerButton}'s props.
  218. *
  219. * @param {Object} state - The Redux state.
  220. * @param {Object} ownProps - The own props of the component.
  221. * @private
  222. * @returns {{
  223. * _isModerator: boolean
  224. * }}
  225. */
  226. function _mapStateToProps(state) {
  227. const participant = getLocalParticipant(state);
  228. const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
  229. const { disableKick } = remoteVideoMenu;
  230. return {
  231. _isModerator: Boolean(participant?.role === PARTICIPANT_ROLE.MODERATOR),
  232. _disableKick: Boolean(disableKick),
  233. _disableRemoteMute: Boolean(disableRemoteMute)
  234. };
  235. }
  236. export default connect(_mapStateToProps)(RemoteVideoMenuTriggerButton);