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.

RemoteVideoMenu.js 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import React, { PureComponent } from 'react';
  2. import { Text, View } from 'react-native';
  3. import { Divider } from 'react-native-paper';
  4. import { Avatar } from '../../../base/avatar';
  5. import { BottomSheet, hideSheet } from '../../../base/dialog';
  6. import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
  7. import { KICK_OUT_ENABLED, getFeatureFlag } from '../../../base/flags';
  8. import { translate } from '../../../base/i18n';
  9. import {
  10. getParticipantById,
  11. getParticipantDisplayName,
  12. isLocalParticipantModerator
  13. } from '../../../base/participants';
  14. import { connect } from '../../../base/redux';
  15. import { getBreakoutRooms, getCurrentRoomId } from '../../../breakout-rooms/functions';
  16. import PrivateMessageButton from '../../../chat/components/native/PrivateMessageButton';
  17. import ConnectionStatusButton from '../native/ConnectionStatusButton';
  18. import AskUnmuteButton from './AskUnmuteButton';
  19. import GrantModeratorButton from './GrantModeratorButton';
  20. import KickButton from './KickButton';
  21. import MuteButton from './MuteButton';
  22. import MuteEveryoneElseButton from './MuteEveryoneElseButton';
  23. import MuteVideoButton from './MuteVideoButton';
  24. import PinButton from './PinButton';
  25. import SendToBreakoutRoom from './SendToBreakoutRoom';
  26. import styles from './styles';
  27. // import VolumeSlider from './VolumeSlider';
  28. /**
  29. * Size of the rendered avatar in the menu.
  30. */
  31. const AVATAR_SIZE = 24;
  32. type Props = {
  33. /**
  34. * The Redux dispatch function.
  35. */
  36. dispatch: Function,
  37. /**
  38. * The ID of the participant for which this menu opened for.
  39. */
  40. participantId: String,
  41. /**
  42. * The id of the current room.
  43. */
  44. _currentRoomId: String,
  45. /**
  46. * Whether or not to display the kick button.
  47. */
  48. _disableKick: boolean,
  49. /**
  50. * Whether or not to display the send private message button.
  51. */
  52. _disablePrivateChat: Boolean,
  53. /**
  54. * Whether or not to display the remote mute buttons.
  55. */
  56. _disableRemoteMute: boolean,
  57. /**
  58. * Whether or not to display the grant moderator button.
  59. */
  60. _disableGrantModerator: Boolean,
  61. /**
  62. * Whether the participant is present in the room or not.
  63. */
  64. _isParticipantAvailable?: boolean,
  65. /**
  66. * Whether the local participant is moderator or not.
  67. */
  68. _moderator: boolean,
  69. /**
  70. * Display name of the participant retrieved from Redux.
  71. */
  72. _participantDisplayName: string,
  73. /**
  74. * Array containing the breakout rooms.
  75. */
  76. _rooms: Array<Object>,
  77. /**
  78. * Translation function.
  79. */
  80. t: Function
  81. }
  82. /**
  83. * Class to implement a popup menu that opens upon long pressing a thumbnail.
  84. */
  85. class RemoteVideoMenu extends PureComponent<Props> {
  86. /**
  87. * Constructor of the component.
  88. *
  89. * @inheritdoc
  90. */
  91. constructor(props: Props) {
  92. super(props);
  93. this._onCancel = this._onCancel.bind(this);
  94. this._renderMenuHeader = this._renderMenuHeader.bind(this);
  95. }
  96. /**
  97. * Implements {@code Component#render}.
  98. *
  99. * @inheritdoc
  100. */
  101. render() {
  102. const {
  103. _disableKick,
  104. _disablePrivateChat,
  105. _disableRemoteMute,
  106. _disableGrantModerator,
  107. _isParticipantAvailable,
  108. _moderator,
  109. _rooms,
  110. _currentRoomId,
  111. participantId,
  112. t
  113. } = this.props;
  114. const buttonProps = {
  115. afterClick: this._onCancel,
  116. showLabel: true,
  117. participantID: participantId,
  118. styles: bottomSheetStyles.buttons
  119. };
  120. return (
  121. <BottomSheet
  122. renderHeader = { this._renderMenuHeader }
  123. showSlidingView = { _isParticipantAvailable }>
  124. <AskUnmuteButton { ...buttonProps } />
  125. { !_disableRemoteMute && <MuteButton { ...buttonProps } /> }
  126. <MuteEveryoneElseButton { ...buttonProps } />
  127. { !_disableRemoteMute && <MuteVideoButton { ...buttonProps } /> }
  128. <Divider style = { styles.divider } />
  129. { !_disableKick && <KickButton { ...buttonProps } /> }
  130. { !_disableGrantModerator && <GrantModeratorButton { ...buttonProps } /> }
  131. <PinButton { ...buttonProps } />
  132. { !_disablePrivateChat && <PrivateMessageButton { ...buttonProps } /> }
  133. <ConnectionStatusButton
  134. { ...buttonProps }
  135. afterClick = { undefined } />
  136. {_moderator && _rooms.length > 1 && <>
  137. <Divider style = { styles.divider } />
  138. <View style = { styles.contextMenuItem }>
  139. <Text style = { styles.contextMenuItemText }>
  140. {t('breakoutRooms.actions.sendToBreakoutRoom')}
  141. </Text>
  142. </View>
  143. {_rooms.map(room => _currentRoomId !== room.id && (<SendToBreakoutRoom
  144. key = { room.id }
  145. room = { room }
  146. { ...buttonProps } />))}
  147. </>}
  148. {/* <VolumeSlider participantID = { participantId } />*/}
  149. </BottomSheet>
  150. );
  151. }
  152. /**
  153. * Callback to hide the {@code RemoteVideoMenu}.
  154. *
  155. * @private
  156. * @returns {boolean}
  157. */
  158. _onCancel() {
  159. this.props.dispatch(hideSheet());
  160. }
  161. /**
  162. * Function to render the menu's header.
  163. *
  164. * @returns {React$Element}
  165. */
  166. _renderMenuHeader() {
  167. const { participantId } = this.props;
  168. return (
  169. <View
  170. style = { [
  171. bottomSheetStyles.sheet,
  172. styles.participantNameContainer ] }>
  173. <Avatar
  174. participantId = { participantId }
  175. size = { AVATAR_SIZE } />
  176. <Text style = { styles.participantNameLabel }>
  177. { this.props._participantDisplayName }
  178. </Text>
  179. </View>
  180. );
  181. }
  182. }
  183. /**
  184. * Function that maps parts of Redux state tree into component props.
  185. *
  186. * @param {Object} state - Redux state.
  187. * @param {Object} ownProps - Properties of component.
  188. * @private
  189. * @returns {Props}
  190. */
  191. function _mapStateToProps(state, ownProps) {
  192. const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true);
  193. const { participantId } = ownProps;
  194. const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
  195. const isParticipantAvailable = getParticipantById(state, participantId);
  196. const { disableKick, disablePrivateChat } = remoteVideoMenu;
  197. const _rooms = Object.values(getBreakoutRooms(state));
  198. const _currentRoomId = getCurrentRoomId(state);
  199. const shouldDisableKick = disableKick || !kickOutEnabled;
  200. const moderator = isLocalParticipantModerator(state);
  201. return {
  202. _currentRoomId,
  203. _disableKick: Boolean(shouldDisableKick),
  204. _disableRemoteMute: Boolean(disableRemoteMute),
  205. _disablePrivateChat: Boolean(disablePrivateChat),
  206. _isParticipantAvailable: Boolean(isParticipantAvailable),
  207. _moderator: moderator,
  208. _participantDisplayName: getParticipantDisplayName(state, participantId),
  209. _rooms
  210. };
  211. }
  212. export default translate(connect(_mapStateToProps)(RemoteVideoMenu));