Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

RemoteVideoMenu.tsx 8.2KB

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