您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ParticipantsPane.js 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { ThemeProvider } from 'styled-components';
  4. import { openDialog } from '../../../base/dialog';
  5. import { translate } from '../../../base/i18n';
  6. import { isLocalParticipantModerator } from '../../../base/participants';
  7. import { connect } from '../../../base/redux';
  8. import { Drawer, JitsiPortal } from '../../../toolbox/components/web';
  9. import { showOverflowDrawer } from '../../../toolbox/functions';
  10. import { MuteEveryoneDialog } from '../../../video-menu/components/';
  11. import { close } from '../../actions';
  12. import { classList, findStyledAncestor, getParticipantsPaneOpen } from '../../functions';
  13. import theme from '../../theme.json';
  14. import { FooterContextMenu } from '../FooterContextMenu';
  15. import LobbyParticipants from './LobbyParticipants';
  16. import MeetingParticipants from './MeetingParticipants';
  17. import {
  18. AntiCollapse,
  19. Close,
  20. Container,
  21. Footer,
  22. FooterButton,
  23. FooterEllipsisButton,
  24. FooterEllipsisContainer,
  25. Header
  26. } from './styled';
  27. /**
  28. * The type of the React {@code Component} props of {@link ParticipantsPane}.
  29. */
  30. type Props = {
  31. /**
  32. * Whether to display the context menu as a drawer.
  33. */
  34. _overflowDrawer: boolean,
  35. /**
  36. * Is the participants pane open.
  37. */
  38. _paneOpen: boolean,
  39. /**
  40. * Whether to show the footer menu.
  41. */
  42. _showFooter: boolean,
  43. /**
  44. * The Redux dispatch function.
  45. */
  46. dispatch: Function,
  47. /**
  48. * The i18n translate function.
  49. */
  50. t: Function
  51. };
  52. /**
  53. * The type of the React {@code Component} state of {@link ParticipantsPane}.
  54. */
  55. type State = {
  56. /**
  57. * Indicates if the footer context menu is open.
  58. */
  59. contextOpen: boolean,
  60. };
  61. /**
  62. * Implements the participants list.
  63. */
  64. class ParticipantsPane extends Component<Props, State> {
  65. /**
  66. * Initializes a new {@code ParticipantsPane} instance.
  67. *
  68. * @inheritdoc
  69. */
  70. constructor(props) {
  71. super(props);
  72. this.state = {
  73. contextOpen: false
  74. };
  75. // Bind event handlers so they are only bound once per instance.
  76. this._onClosePane = this._onClosePane.bind(this);
  77. this._onDrawerClose = this._onDrawerClose.bind(this);
  78. this._onKeyPress = this._onKeyPress.bind(this);
  79. this._onMuteAll = this._onMuteAll.bind(this);
  80. this._onToggleContext = this._onToggleContext.bind(this);
  81. this._onWindowClickListener = this._onWindowClickListener.bind(this);
  82. }
  83. /**
  84. * Implements React's {@link Component#componentDidMount()}.
  85. *
  86. * @inheritdoc
  87. */
  88. componentDidMount() {
  89. window.addEventListener('click', this._onWindowClickListener);
  90. }
  91. /**
  92. * Implements React's {@link Component#componentWillUnmount()}.
  93. *
  94. * @inheritdoc
  95. */
  96. componentWillUnmount() {
  97. window.removeEventListener('click', this._onWindowClickListener);
  98. }
  99. /**
  100. * Implements React's {@link Component#render}.
  101. *
  102. * @inheritdoc
  103. */
  104. render() {
  105. const {
  106. _overflowDrawer,
  107. _paneOpen,
  108. _showFooter,
  109. t
  110. } = this.props;
  111. const { contextOpen } = this.state;
  112. // when the pane is not open optimize to not
  113. // execute the MeetingParticipantList render for large list of participants
  114. if (!_paneOpen) {
  115. return null;
  116. }
  117. return (
  118. <ThemeProvider theme = { theme }>
  119. <div className = { classList('participants_pane', !_paneOpen && 'participants_pane--closed') }>
  120. <div className = 'participants_pane-content'>
  121. <Header>
  122. <Close
  123. aria-label = { t('participantsPane.close', 'Close') }
  124. onClick = { this._onClosePane }
  125. onKeyPress = { this._onKeyPress }
  126. role = 'button'
  127. tabIndex = { 0 } />
  128. </Header>
  129. <Container>
  130. <LobbyParticipants />
  131. <AntiCollapse />
  132. <MeetingParticipants />
  133. </Container>
  134. {_showFooter && (
  135. <Footer>
  136. <FooterButton onClick = { this._onMuteAll }>
  137. {t('participantsPane.actions.muteAll')}
  138. </FooterButton>
  139. <FooterEllipsisContainer>
  140. <FooterEllipsisButton
  141. id = 'participants-pane-context-menu'
  142. onClick = { this._onToggleContext } />
  143. {this.state.contextOpen && !_overflowDrawer
  144. && <FooterContextMenu onMouseLeave = { this._onToggleContext } />}
  145. </FooterEllipsisContainer>
  146. </Footer>
  147. )}
  148. </div>
  149. <JitsiPortal>
  150. <Drawer
  151. isOpen = { contextOpen && _overflowDrawer }
  152. onClose = { this._onDrawerClose }>
  153. <FooterContextMenu inDrawer = { true } />
  154. </Drawer>
  155. </JitsiPortal>
  156. </div>
  157. </ThemeProvider>
  158. );
  159. }
  160. _onClosePane: () => void;
  161. /**
  162. * Callback for closing the participant pane.
  163. *
  164. * @private
  165. * @returns {void}
  166. */
  167. _onClosePane() {
  168. this.props.dispatch(close());
  169. }
  170. _onDrawerClose: () => void
  171. /**
  172. * Callback for closing the drawer.
  173. *
  174. * @private
  175. * @returns {void}
  176. */
  177. _onDrawerClose() {
  178. this.setState({
  179. contextOpen: false
  180. });
  181. }
  182. _onKeyPress: (Object) => void;
  183. /**
  184. * KeyPress handler for accessibility for closing the participants pane.
  185. *
  186. * @param {Object} e - The key event to handle.
  187. *
  188. * @returns {void}
  189. */
  190. _onKeyPress(e) {
  191. if (e.key === ' ' || e.key === 'Enter') {
  192. e.preventDefault();
  193. this._onClosePane();
  194. }
  195. }
  196. _onMuteAll: () => void;
  197. /**
  198. * The handler for clicking mute all button.
  199. *
  200. * @returns {void}
  201. */
  202. _onMuteAll() {
  203. this.props.dispatch(openDialog(MuteEveryoneDialog));
  204. }
  205. _onToggleContext: () => void;
  206. /**
  207. * Handler for toggling open/close of the footer context menu.
  208. *
  209. * @returns {void}
  210. */
  211. _onToggleContext() {
  212. this.setState({
  213. contextOpen: !this.state.contextOpen
  214. });
  215. }
  216. _onWindowClickListener: (event: Object) => void;
  217. /**
  218. * Window click event listener.
  219. *
  220. * @param {Event} e - The click event.
  221. * @returns {void}
  222. */
  223. _onWindowClickListener(e) {
  224. if (this.state.contextOpen && !findStyledAncestor(e.target, FooterEllipsisContainer)) {
  225. this.setState({
  226. contextOpen: false
  227. });
  228. }
  229. }
  230. }
  231. /**
  232. * Maps (parts of) the redux state to the React {@code Component} props of
  233. * {@code ParticipantsPane}.
  234. *
  235. * @param {Object} state - The redux state.
  236. * @protected
  237. * @returns {{
  238. * _paneOpen: boolean,
  239. * _showFooter: boolean
  240. * }}
  241. */
  242. function _mapStateToProps(state: Object) {
  243. const isPaneOpen = getParticipantsPaneOpen(state);
  244. return {
  245. _overflowDrawer: showOverflowDrawer(state),
  246. _paneOpen: isPaneOpen,
  247. _showFooter: isPaneOpen && isLocalParticipantModerator(state)
  248. };
  249. }
  250. export default translate(connect(_mapStateToProps)(ParticipantsPane));