import Tabs from '@atlaskit/tabs'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Dialog, hideDialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; import { obtainDesktopSources, resetDesktopSources } from '../actions'; import DesktopPickerPane from './DesktopPickerPane'; const THUMBNAIL_SIZE = { height: 300, width: 300 }; const UPDATE_INTERVAL = 1000; const TAB_CONFIGURATIONS = [ { /** * The indicator which determines whether this tab configuration is * selected by default. * * @type {boolean} */ defaultSelected: true, label: 'dialog.yourEntireScreen', type: 'screen' }, { label: 'dialog.applicationWindow', type: 'window' } ]; const VALID_TYPES = TAB_CONFIGURATIONS.map(c => c.type); /** * React component for DesktopPicker. * * @extends Component */ class DesktopPicker extends Component { /** * Default values for DesktopPicker component's properties. * * @static */ static defaultProps = { options: {} }; /** * DesktopPicker component's property types. * * @static */ static propTypes = { /** * Used to request DesktopCapturerSources. */ dispatch: React.PropTypes.func, /** * The callback to be invoked when the component is closed or when * a DesktopCapturerSource has been chosen. */ onSourceChoose: React.PropTypes.func, /** * An object with options related to desktop sharing. */ options: React.PropTypes.object, /** * An object with arrays of DesktopCapturerSources. The key should be * the source type. */ sources: React.PropTypes.object, /** * Used to obtain translations. */ t: React.PropTypes.func }; /** * Initializes a new DesktopPicker instance. * * @param {Object} props - The read-only properties with which the new * instance is to be initialized. */ constructor(props) { super(props); this.state = { selectedSource: {}, tabsToPopulate: [], typesToFetch: [] }; this._poller = null; this._onCloseModal = this._onCloseModal.bind(this); this._onPreviewClick = this._onPreviewClick.bind(this); this._onSubmit = this._onSubmit.bind(this); this._updateSources = this._updateSources.bind(this); } /** * Perform an immediate update request for DesktopCapturerSources and begin * requesting updates at an interval. * * @inheritdoc */ componentWillMount() { const { desktopSharingSources } = this.props.options; this._onSourceTypesConfigChanged( desktopSharingSources); this._updateSources(); this._startPolling(); } /** * Notifies this mounted React Component that it will receive new props. * Sets a default selected source if one is not already set. * * @inheritdoc * @param {Object} nextProps - The read-only React Component props that this * instance will receive. * @returns {void} */ componentWillReceiveProps(nextProps) { if (!this.state.selectedSource.id && nextProps.sources.screen.length) { this.setState({ selectedSource: { id: nextProps.sources.screen[0].id, type: 'screen' } }); } const { desktopSharingSources } = this.props.options; this._onSourceTypesConfigChanged( desktopSharingSources); } /** * Clean up component and DesktopCapturerSource store state. * * @inheritdoc */ componentWillUnmount() { this._stopPolling(); this.props.dispatch(resetDesktopSources()); } /** * Implements React's {@link Component#render()}. * * @inheritdoc */ render() { return ( { this._renderTabs() } ); } /** * Dispatches an action to hide the DesktopPicker and invokes the passed in * callback with a selectedSource, if any. * * @param {string} id - The id of the DesktopCapturerSource to pass into the * onSourceChoose callback. * @param {string} type - The type of the DesktopCapturerSource to pass into * the onSourceChoose callback. * @returns {void} */ _onCloseModal(id = '', type) { this.props.onSourceChoose(id, type); this.props.dispatch(hideDialog()); } /** * Sets the currently selected DesktopCapturerSource. * * @param {string} id - The id of DesktopCapturerSource. * @param {string} type - The type of DesktopCapturerSource. * @returns {void} */ _onPreviewClick(id, type) { this.setState({ selectedSource: { id, type } }); } /** * Request to close the modal and execute callbacks with the selected source * id. * * @returns {void} */ _onSubmit() { const { id, type } = this.state.selectedSource; this._onCloseModal(id, type); } /** * Configures and renders the tabs for display. * * @private * @returns {ReactElement} */ _renderTabs() { const { selectedSource } = this.state; const { sources, t } = this.props; const tabs = this.state.tabsToPopulate.map( ({ defaultSelected, label, type }) => { return { content: , defaultSelected, label: t(label) }; }); return ; } /** * Create an interval to update knwon available DesktopCapturerSources. * * @private * @returns {void} */ _startPolling() { this._stopPolling(); this._poller = window.setInterval(this._updateSources, UPDATE_INTERVAL); } /** * Cancels the interval to update DesktopCapturerSources. * * @private * @returns {void} */ _stopPolling() { window.clearInterval(this._poller); this._poller = null; } /** * Handles changing of allowed desktop sharing source types. * * @param {Array} desktopSharingSourceTypes - The types that will be * fetched and displayed. * @returns {void} */ _onSourceTypesConfigChanged(desktopSharingSourceTypes = []) { const tabsToPopulate = TAB_CONFIGURATIONS.filter( c => desktopSharingSourceTypes.includes(c.type) && VALID_TYPES.includes(c.type) ); this.setState({ tabsToPopulate, typesToFetch: tabsToPopulate.map(c => c.type) }); } /** * Dispatches an action to get currently available DesktopCapturerSources. * * @private * @returns {void} */ _updateSources() { this.props.dispatch(obtainDesktopSources( this.state.typesToFetch, { THUMBNAIL_SIZE } )); } } /** * Maps (parts of) the Redux state to the associated DesktopPicker's props. * * @param {Object} state - Redux state. * @private * @returns {{ * sources: Object * }} */ function _mapStateToProps(state) { return { sources: state['features/desktop-picker'] }; } export default translate(connect(_mapStateToProps)(DesktopPicker));