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.3KB

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