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 6.9KB

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