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

Conference.web.js 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // @flow
  2. import _ from 'lodash';
  3. import React, { Component } from 'react';
  4. import { connect as reactReduxConnect } from 'react-redux';
  5. import VideoLayout from '../../../../modules/UI/videolayout/VideoLayout';
  6. import { obtainConfig } from '../../base/config';
  7. import { connect, disconnect } from '../../base/connection';
  8. import { DialogContainer } from '../../base/dialog';
  9. import { translate } from '../../base/i18n';
  10. import { Filmstrip } from '../../filmstrip';
  11. import { CalleeInfoContainer } from '../../invite';
  12. import { LargeVideo } from '../../large-video';
  13. import { NotificationsContainer } from '../../notifications';
  14. import { SidePanel } from '../../side-panel';
  15. import {
  16. LAYOUTS,
  17. getCurrentLayout,
  18. shouldDisplayTileView
  19. } from '../../video-layout';
  20. import { default as Notice } from './Notice';
  21. import {
  22. Toolbox,
  23. fullScreenChanged,
  24. setToolboxAlwaysVisible,
  25. showToolbox
  26. } from '../../toolbox';
  27. import { maybeShowSuboptimalExperienceNotification } from '../functions';
  28. declare var APP: Object;
  29. declare var config: Object;
  30. declare var interfaceConfig: Object;
  31. const logger = require('jitsi-meet-logger').getLogger(__filename);
  32. /**
  33. * DOM events for when full screen mode has changed. Different browsers need
  34. * different vendor prefixes.
  35. *
  36. * @private
  37. * @type {Array<string>}
  38. */
  39. const FULL_SCREEN_EVENTS = [
  40. 'webkitfullscreenchange',
  41. 'mozfullscreenchange',
  42. 'fullscreenchange'
  43. ];
  44. /**
  45. * The CSS class to apply to the root element of the conference so CSS can
  46. * modify the app layout.
  47. *
  48. * @private
  49. * @type {Object}
  50. */
  51. const LAYOUT_CLASSNAMES = {
  52. [LAYOUTS.HORIZONTAL_FILMSTRIP_VIEW]: 'horizontal-filmstrip',
  53. [LAYOUTS.TILE_VIEW]: 'tile-view',
  54. [LAYOUTS.VERTICAL_FILMSTRIP_VIEW]: 'vertical-filmstrip'
  55. };
  56. /**
  57. * The type of the React {@code Component} props of {@link Conference}.
  58. */
  59. type Props = {
  60. /**
  61. * Whether the local participant is recording the conference.
  62. */
  63. _iAmRecorder: boolean,
  64. /**
  65. * The CSS class to apply to the root of {@link Conference} to modify the
  66. * application layout.
  67. */
  68. _layoutClassName: string,
  69. /**
  70. * Conference room name.
  71. */
  72. _room: string,
  73. /**
  74. * Whether or not the current UI layout should be in tile view.
  75. */
  76. _shouldDisplayTileView: boolean,
  77. dispatch: Function,
  78. t: Function
  79. }
  80. /**
  81. * The conference page of the Web application.
  82. */
  83. class Conference extends Component<Props> {
  84. _onFullScreenChange: Function;
  85. _onShowToolbar: Function;
  86. _originalOnShowToolbar: Function;
  87. /**
  88. * Initializes a new Conference instance.
  89. *
  90. * @param {Object} props - The read-only properties with which the new
  91. * instance is to be initialized.
  92. */
  93. constructor(props) {
  94. super(props);
  95. // Throttle and bind this component's mousemove handler to prevent it
  96. // from firing too often.
  97. this._originalOnShowToolbar = this._onShowToolbar;
  98. this._onShowToolbar = _.throttle(
  99. () => this._originalOnShowToolbar(),
  100. 100,
  101. {
  102. leading: true,
  103. trailing: false
  104. });
  105. // Bind event handler so it is only bound once for every instance.
  106. this._onFullScreenChange = this._onFullScreenChange.bind(this);
  107. }
  108. /**
  109. * Start the connection and get the UI ready for the conference.
  110. *
  111. * @inheritdoc
  112. */
  113. componentDidMount() {
  114. const { configLocation } = config;
  115. if (configLocation) {
  116. obtainConfig(configLocation, this.props._room)
  117. .then(() => {
  118. const now = window.performance.now();
  119. APP.connectionTimes['configuration.fetched'] = now;
  120. logger.log('(TIME) configuration fetched:\t', now);
  121. this._start();
  122. })
  123. .catch(err => {
  124. logger.log(err);
  125. // Show obtain config error.
  126. APP.UI.messageHandler.showError({
  127. descriptionKey: 'dialog.connectError',
  128. titleKey: 'connection.CONNFAIL'
  129. });
  130. });
  131. } else {
  132. this._start();
  133. }
  134. }
  135. /**
  136. * Calls into legacy UI to update the application layout, if necessary.
  137. *
  138. * @inheritdoc
  139. * returns {void}
  140. */
  141. componentDidUpdate(prevProps) {
  142. if (this.props._shouldDisplayTileView
  143. === prevProps._shouldDisplayTileView) {
  144. return;
  145. }
  146. // TODO: For now VideoLayout is being called as LargeVideo and Filmstrip
  147. // sizing logic is still handled outside of React. Once all components
  148. // are in react they should calculate size on their own as much as
  149. // possible and pass down sizings.
  150. VideoLayout.refreshLayout();
  151. }
  152. /**
  153. * Disconnect from the conference when component will be
  154. * unmounted.
  155. *
  156. * @inheritdoc
  157. */
  158. componentWillUnmount() {
  159. APP.UI.unregisterListeners();
  160. APP.UI.unbindEvents();
  161. FULL_SCREEN_EVENTS.forEach(name =>
  162. document.removeEventListener(name, this._onFullScreenChange));
  163. APP.conference.isJoined() && this.props.dispatch(disconnect());
  164. }
  165. /**
  166. * Implements React's {@link Component#render()}.
  167. *
  168. * @inheritdoc
  169. * @returns {ReactElement}
  170. */
  171. render() {
  172. const {
  173. VIDEO_QUALITY_LABEL_DISABLED,
  174. // XXX The character casing of the name filmStripOnly utilized by
  175. // interfaceConfig is obsolete but legacy support is required.
  176. filmStripOnly: filmstripOnly
  177. } = interfaceConfig;
  178. const hideVideoQualityLabel
  179. = filmstripOnly
  180. || VIDEO_QUALITY_LABEL_DISABLED
  181. || this.props._iAmRecorder;
  182. return (
  183. <div
  184. className = { this.props._layoutClassName }
  185. id = 'videoconference_page'
  186. onMouseMove = { this._onShowToolbar }>
  187. <Notice />
  188. <div id = 'videospace'>
  189. <LargeVideo
  190. hideVideoQualityLabel = { hideVideoQualityLabel } />
  191. <Filmstrip filmstripOnly = { filmstripOnly } />
  192. </div>
  193. { filmstripOnly || <Toolbox /> }
  194. { filmstripOnly || <SidePanel /> }
  195. <DialogContainer />
  196. <NotificationsContainer />
  197. <CalleeInfoContainer />
  198. </div>
  199. );
  200. }
  201. /**
  202. * Updates the Redux state when full screen mode has been enabled or
  203. * disabled.
  204. *
  205. * @private
  206. * @returns {void}
  207. */
  208. _onFullScreenChange() {
  209. this.props.dispatch(fullScreenChanged(APP.UI.isFullScreen()));
  210. }
  211. /**
  212. * Displays the toolbar.
  213. *
  214. * @private
  215. * @returns {void}
  216. */
  217. _onShowToolbar() {
  218. this.props.dispatch(showToolbox());
  219. }
  220. /**
  221. * Until we don't rewrite UI using react components
  222. * we use UI.start from old app. Also method translates
  223. * component right after it has been mounted.
  224. *
  225. * @inheritdoc
  226. */
  227. _start() {
  228. APP.UI.start();
  229. APP.UI.registerListeners();
  230. APP.UI.bindEvents();
  231. FULL_SCREEN_EVENTS.forEach(name =>
  232. document.addEventListener(name, this._onFullScreenChange));
  233. const { dispatch, t } = this.props;
  234. dispatch(connect());
  235. maybeShowSuboptimalExperienceNotification(dispatch, t);
  236. interfaceConfig.filmStripOnly
  237. && dispatch(setToolboxAlwaysVisible(true));
  238. }
  239. }
  240. /**
  241. * Maps (parts of) the Redux state to the associated props for the
  242. * {@code Conference} component.
  243. *
  244. * @param {Object} state - The Redux state.
  245. * @private
  246. * @returns {{
  247. * _iAmRecorder: boolean,
  248. * _layoutClassName: string,
  249. * _room: ?string,
  250. * _shouldDisplayTileView: boolean
  251. * }}
  252. */
  253. function _mapStateToProps(state) {
  254. const currentLayout = getCurrentLayout(state);
  255. return {
  256. _iAmRecorder: state['features/base/config'].iAmRecorder,
  257. _layoutClassName: LAYOUT_CLASSNAMES[currentLayout],
  258. _room: state['features/base/conference'].room,
  259. _shouldDisplayTileView: shouldDisplayTileView(state)
  260. };
  261. }
  262. export default reactReduxConnect(_mapStateToProps)(translate(Conference));