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.

DesktopPicker.js 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import Tabs from '@atlaskit/tabs';
  2. import React, { Component } from 'react';
  3. import { connect } from 'react-redux';
  4. import { Dialog, hideDialog } from '../../base/dialog';
  5. import { translate } from '../../base/i18n';
  6. import { obtainDesktopSources, resetDesktopSources } from '../actions';
  7. import DesktopPickerPane from './DesktopPickerPane';
  8. const THUMBNAIL_SIZE = {
  9. height: 300,
  10. width: 300
  11. };
  12. const UPDATE_INTERVAL = 1000;
  13. const TAB_CONFIGURATIONS = [
  14. {
  15. /**
  16. * The indicator which determines whether this tab configuration is
  17. * selected by default.
  18. *
  19. * @type {boolean}
  20. */
  21. defaultSelected: true,
  22. label: 'dialog.yourEntireScreen',
  23. type: 'screen'
  24. },
  25. {
  26. label: 'dialog.applicationWindow',
  27. type: 'window'
  28. }
  29. ];
  30. const VALID_TYPES = TAB_CONFIGURATIONS.map(c => c.type);
  31. /**
  32. * React component for DesktopPicker.
  33. *
  34. * @extends Component
  35. */
  36. class DesktopPicker extends Component {
  37. /**
  38. * DesktopPicker component's property types.
  39. *
  40. * @static
  41. */
  42. static propTypes = {
  43. /**
  44. * Used to request DesktopCapturerSources.
  45. */
  46. dispatch: React.PropTypes.func,
  47. /**
  48. * The callback to be invoked when the component is closed or when
  49. * a DesktopCapturerSource has been chosen.
  50. */
  51. onSourceChoose: React.PropTypes.func,
  52. /**
  53. * An object with options related to desktop sharing.
  54. */
  55. options: React.PropTypes.object,
  56. /**
  57. * An object with arrays of DesktopCapturerSources. The key should be
  58. * the source type.
  59. */
  60. sources: React.PropTypes.object,
  61. /**
  62. * Used to obtain translations.
  63. */
  64. t: React.PropTypes.func
  65. };
  66. /**
  67. * Initializes a new DesktopPicker instance.
  68. *
  69. * @param {Object} props - The read-only properties with which the new
  70. * instance is to be initialized.
  71. */
  72. constructor(props) {
  73. super(props);
  74. this.state = {
  75. selectedSource: {},
  76. tabsToPopulate: [],
  77. typesToFetch: []
  78. };
  79. this._poller = null;
  80. this._onCloseModal = this._onCloseModal.bind(this);
  81. this._onPreviewClick = this._onPreviewClick.bind(this);
  82. this._onSubmit = this._onSubmit.bind(this);
  83. this._updateSources = this._updateSources.bind(this);
  84. }
  85. /**
  86. * Perform an immediate update request for DesktopCapturerSources and begin
  87. * requesting updates at an interval.
  88. *
  89. * @inheritdoc
  90. */
  91. componentWillMount() {
  92. const options = this.props.options || {};
  93. this._onSourceTypesConfigChanged(
  94. options.desktopSharingSources);
  95. this._updateSources();
  96. this._startPolling();
  97. }
  98. /**
  99. * Notifies this mounted React Component that it will receive new props.
  100. * Sets a default selected source if one is not already set.
  101. *
  102. * @inheritdoc
  103. * @param {Object} nextProps - The read-only React Component props that this
  104. * instance will receive.
  105. * @returns {void}
  106. */
  107. componentWillReceiveProps(nextProps) {
  108. if (!this.state.selectedSource.id
  109. && nextProps.sources.screen.length) {
  110. this.setState({
  111. selectedSource: {
  112. id: nextProps.sources.screen[0].id,
  113. type: 'screen'
  114. }
  115. });
  116. }
  117. const options = this.props.options || {};
  118. this._onSourceTypesConfigChanged(
  119. options.desktopSharingSources);
  120. }
  121. /**
  122. * Clean up component and DesktopCapturerSource store state.
  123. *
  124. * @inheritdoc
  125. */
  126. componentWillUnmount() {
  127. this._stopPolling();
  128. this.props.dispatch(resetDesktopSources());
  129. }
  130. /**
  131. * Implements React's {@link Component#render()}.
  132. *
  133. * @inheritdoc
  134. */
  135. render() {
  136. return (
  137. <Dialog
  138. isModal = { false }
  139. okTitleKey = 'dialog.Share'
  140. onCancel = { this._onCloseModal }
  141. onSubmit = { this._onSubmit }
  142. titleKey = 'dialog.shareYourScreen'
  143. width = 'medium' >
  144. { this._renderTabs() }
  145. </Dialog>
  146. );
  147. }
  148. /**
  149. * Dispatches an action to hide the DesktopPicker and invokes the passed in
  150. * callback with a selectedSource, if any.
  151. *
  152. * @param {string} id - The id of the DesktopCapturerSource to pass into the
  153. * onSourceChoose callback.
  154. * @param {string} type - The type of the DesktopCapturerSource to pass into
  155. * the onSourceChoose callback.
  156. * @returns {void}
  157. */
  158. _onCloseModal(id = '', type) {
  159. this.props.onSourceChoose(id, type);
  160. this.props.dispatch(hideDialog());
  161. }
  162. /**
  163. * Sets the currently selected DesktopCapturerSource.
  164. *
  165. * @param {string} id - The id of DesktopCapturerSource.
  166. * @param {string} type - The type of DesktopCapturerSource.
  167. * @returns {void}
  168. */
  169. _onPreviewClick(id, type) {
  170. this.setState({
  171. selectedSource: {
  172. id,
  173. type
  174. }
  175. });
  176. }
  177. /**
  178. * Request to close the modal and execute callbacks with the selected source
  179. * id.
  180. *
  181. * @returns {void}
  182. */
  183. _onSubmit() {
  184. const { id, type } = this.state.selectedSource;
  185. this._onCloseModal(id, type);
  186. }
  187. /**
  188. * Configures and renders the tabs for display.
  189. *
  190. * @private
  191. * @returns {ReactElement}
  192. */
  193. _renderTabs() {
  194. const { selectedSource } = this.state;
  195. const { sources, t } = this.props;
  196. const tabs
  197. = this.state.tabsToPopulate.map(
  198. ({ defaultSelected, label, type }) => {
  199. return {
  200. content: <DesktopPickerPane
  201. key = { type }
  202. onClick = { this._onPreviewClick }
  203. onDoubleClick = { this._onCloseModal }
  204. selectedSourceId = { selectedSource.id }
  205. sources = { sources[type] || [] }
  206. type = { type } />,
  207. defaultSelected,
  208. label: t(label)
  209. };
  210. });
  211. return <Tabs tabs = { tabs } />;
  212. }
  213. /**
  214. * Create an interval to update knwon available DesktopCapturerSources.
  215. *
  216. * @private
  217. * @returns {void}
  218. */
  219. _startPolling() {
  220. this._stopPolling();
  221. this._poller = window.setInterval(this._updateSources, UPDATE_INTERVAL);
  222. }
  223. /**
  224. * Cancels the interval to update DesktopCapturerSources.
  225. *
  226. * @private
  227. * @returns {void}
  228. */
  229. _stopPolling() {
  230. window.clearInterval(this._poller);
  231. this._poller = null;
  232. }
  233. /**
  234. * Handles changing of allowed desktop sharing source types.
  235. *
  236. * @param {Array<string>} desktopSharingSourceTypes - The types that will be
  237. * fetched and displayed.
  238. * @returns {void}
  239. */
  240. _onSourceTypesConfigChanged(desktopSharingSourceTypes = []) {
  241. const tabsToPopulate = TAB_CONFIGURATIONS.filter(
  242. c => desktopSharingSourceTypes.includes(c.type)
  243. && VALID_TYPES.includes(c.type)
  244. );
  245. this.setState({
  246. tabsToPopulate,
  247. typesToFetch: tabsToPopulate.map(c => c.type)
  248. });
  249. }
  250. /**
  251. * Dispatches an action to get currently available DesktopCapturerSources.
  252. *
  253. * @private
  254. * @returns {void}
  255. */
  256. _updateSources() {
  257. this.props.dispatch(obtainDesktopSources(
  258. this.state.typesToFetch,
  259. {
  260. THUMBNAIL_SIZE
  261. }
  262. ));
  263. }
  264. }
  265. /**
  266. * Maps (parts of) the Redux state to the associated DesktopPicker's props.
  267. *
  268. * @param {Object} state - Redux state.
  269. * @private
  270. * @returns {{
  271. * sources: Object
  272. * }}
  273. */
  274. function _mapStateToProps(state) {
  275. return {
  276. sources: state['features/desktop-picker']
  277. };
  278. }
  279. export default translate(connect(_mapStateToProps)(DesktopPicker));