diff --git a/conference.js b/conference.js index 73a3efe83..8a91e9874 100644 --- a/conference.js +++ b/conference.js @@ -2320,45 +2320,39 @@ export default { * @private */ _initDeviceList() { - JitsiMeetJS.mediaDevices.isDeviceListAvailable() - .then(isDeviceListAvailable => { - if (isDeviceListAvailable - && JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) { - JitsiMeetJS.mediaDevices.enumerateDevices(devices => { - // Ugly way to synchronize real device IDs with local - // storage and settings menu. This is a workaround until - // getConstraints() method will be implemented - // in browsers. - const { dispatch } = APP.store; + if (JitsiMeetJS.mediaDevices.isDeviceListAvailable() + && JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) { + JitsiMeetJS.mediaDevices.enumerateDevices(devices => { + // Ugly way to synchronize real device IDs with local + // storage and settings menu. This is a workaround until + // getConstraints() method will be implemented + // in browsers. + const { dispatch } = APP.store; - if (this.localAudio) { - dispatch(updateSettings({ - micDeviceId: this.localAudio.getDeviceId() - })); - } - - if (this.localVideo) { - dispatch(updateSettings({ - cameraDeviceId: this.localVideo.getDeviceId() - })); - } - - mediaDeviceHelper.setCurrentMediaDevices(devices); - APP.UI.onAvailableDevicesChanged(devices); - APP.store.dispatch(updateDeviceList(devices)); - }); - - this.deviceChangeListener = devices => - window.setTimeout( - () => this._onDeviceListChanged(devices), 0); - JitsiMeetJS.mediaDevices.addEventListener( - JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED, - this.deviceChangeListener); + if (this.localAudio) { + dispatch(updateSettings({ + micDeviceId: this.localAudio.getDeviceId() + })); } - }) - .catch(error => { - logger.warn(`Error getting device list: ${error}`); + + if (this.localVideo) { + dispatch(updateSettings({ + cameraDeviceId: this.localVideo.getDeviceId() + })); + } + + mediaDeviceHelper.setCurrentMediaDevices(devices); + APP.UI.onAvailableDevicesChanged(devices); + APP.store.dispatch(updateDeviceList(devices)); }); + + this.deviceChangeListener = devices => + window.setTimeout( + () => this._onDeviceListChanged(devices), 0); + JitsiMeetJS.mediaDevices.addEventListener( + JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED, + this.deviceChangeListener); + } }, /** diff --git a/modules/URL/ConferenceUrl.js b/modules/URL/ConferenceUrl.js deleted file mode 100644 index c34de391c..000000000 --- a/modules/URL/ConferenceUrl.js +++ /dev/null @@ -1,32 +0,0 @@ -const logger = require('jitsi-meet-logger').getLogger(__filename); - -/** - * The modules stores information about the URL used to start the conference and - * provides utility methods for dealing with conference URL and reloads. - */ -export default class ConferenceUrl { - /** - * Initializes the module. - * - * @param location an object which stores provides the info about conference - * URL(would be 'window.location' for the Web app). The params below are - * described based on the following example URL: - * - * https://example.com:8888/SomeConference1245?opt=1#somehash - * - * @param location.href full URL with all parameters, would be the whole URL - * from the example string above. - * @param location.host the host part of the URL, 'example.com' from - * the sample URL above. - * @param location.pathname the path part of the URL, would be - * '/SomeConference1245' from the example above. - * @param location.protocol the protocol part of the URL, would be 'https:' - * from the sample URL. - */ - constructor(location) { - logger.info(`Stored original conference URL: ${location.href}`); - logger.info( - `Conference URL for invites: ${location.protocol}//${ - location.host}${location.pathname}`); - } -} diff --git a/react/features/app/actions.js b/react/features/app/actions.js index 54ec122b2..cd3e75615 100644 --- a/react/features/app/actions.js +++ b/react/features/app/actions.js @@ -77,32 +77,25 @@ function _appNavigateToMandatoryLocation( * @returns {void} */ function loadConfigSettled(error, config) { - let promise; - // Due to the asynchronous nature of the loading, the specified config // may or may not be required by the time the notification arrives. // If we receive the config for a location we are no longer interested // in, "ignore" it - deliver it to the external API, for example, but do // not proceed with the appNavigate procedure/process. if (getState()['features/base/config'].locationURL === locationURL) { - promise = dispatch(setLocationURL(locationURL)); + dispatch(setLocationURL(locationURL)); + dispatch(setConfig(config)); } else { // eslint-disable-next-line no-param-reassign error || (error = new Error('Config no longer needed!')); - promise = Promise.resolve(); + + // XXX The failure could be, for example, because of a + // certificate-related error. In which case the connection will + // fail later in Strophe anyway. + dispatch(loadConfigError(error, locationURL)); + + throw error; } - - return promise.then(() => { - if (error) { - // XXX The failure could be, for example, because of a - // certificate-related error. In which case the connection will - // fail later in Strophe anyway. - dispatch(loadConfigError(error, locationURL)); - throw error; - } - - return dispatch(setConfig(config)); - }); } } diff --git a/react/features/app/components/AbstractApp.js b/react/features/app/components/AbstractApp.js index 5b07b41f4..1893b4f0b 100644 --- a/react/features/app/components/AbstractApp.js +++ b/react/features/app/components/AbstractApp.js @@ -1,5 +1,6 @@ /* global APP */ +import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component, Fragment } from 'react'; import { I18nextProvider } from 'react-i18next'; @@ -9,7 +10,6 @@ import Thunk from 'redux-thunk'; import { i18next } from '../../base/i18n'; import { localParticipantLeft } from '../../base/participants'; -import { RouteRegistry } from '../../base/react'; import { MiddlewareRegistry, ReducerRegistry, @@ -19,7 +19,6 @@ import { SoundCollection } from '../../base/sounds'; import { PersistenceRegistry } from '../../base/storage'; import { toURLString } from '../../base/util'; import { OverlayContainer } from '../../overlay'; -import { BlankPage } from '../../welcome'; import { appNavigate, appWillMount, appWillUnmount } from '../actions'; @@ -84,7 +83,7 @@ export class AbstractApp extends Component { * * @type {Route} */ - route: undefined, + route: {}, /** * The state of the »possible« async initialization of @@ -114,7 +113,6 @@ export class AbstractApp extends Component { .catch(() => { /* AbstractApp should always initialize! */ }) .then(() => this.setState({ - route: undefined, store: this._maybeCreateStore(props) })); } @@ -242,7 +240,7 @@ export class AbstractApp extends Component { */ render() { const { appAsyncInitialized, route } = this.state; - const component = (route && route.component) || BlankPage; + const { component } = route; if (appAsyncInitialized && component) { return ( @@ -421,33 +419,16 @@ export class AbstractApp extends Component { * @returns {Promise} */ _navigate(route) { - if (RouteRegistry.areRoutesEqual(this.state.route, route)) { + if (_.isEqual(route, this.state.route)) { return Promise.resolve(); } - let nextState = { - route - }; + if (route.href) { + // This navigation requires loading a new URL in the browser. + window.location.href = route.href; - // The Web App was using react-router so it utilized react-router's - // onEnter. During the removal of react-router, modifications were - // minimized by preserving the onEnter interface: - // (1) Router would provide its nextState to the Route's onEnter. As the - // role of Router is now this AbstractApp and we use redux, provide the - // redux store instead. - // (2) A replace function would be provided to the Route in case it - // chose to redirect to another path. - route && this._onRouteEnter(route, this._getStore(), pathname => { - if (pathname) { - this._openURL(pathname); - - // Do not proceed with the route because it chose to redirect to - // another path. - nextState = undefined; - } else { - nextState.route = undefined; - } - }); + return Promise.resolve(); + } // XXX React's setState is asynchronous which means that the value of // this.state.route above may not even be correct. If the check is @@ -455,28 +436,10 @@ export class AbstractApp extends Component { // expected route. In order to mitigate the problem, _navigate was // changed to return a Promise. return new Promise(resolve => { - if (nextState) { - this.setState(nextState, resolve); - } else { - resolve(); - } + this.setState({ route }, resolve); }); } - /** - * Notifies this {@code App} that a specific Route is about to be rendered. - * - * @param {Route} route - The Route that is about to be rendered. - * @private - * @returns {void} - */ - _onRouteEnter(route, ...args) { - // Notify the route that it is about to be entered. - const { onEnter } = route; - - typeof onEnter === 'function' && onEnter(...args); - } - /** * Navigates this {@code AbstractApp} to (i.e. opens) a specific URL. * diff --git a/react/features/app/components/App.web.js b/react/features/app/components/App.web.js index aa3dfcc46..e1e281cb1 100644 --- a/react/features/app/components/App.web.js +++ b/react/features/app/components/App.web.js @@ -2,7 +2,6 @@ import { AtlasKitThemeProvider } from '@atlaskit/theme'; import React from 'react'; import '../../base/responsive-ui'; -import { getLocationContextRoot } from '../../base/util'; import '../../chat'; import '../../room-lock'; import '../../video-layout'; @@ -22,27 +21,6 @@ export class App extends AbstractApp { */ static propTypes = AbstractApp.propTypes; - /** - * Initializes a new App instance. - * - * @param {Object} props - The read-only React Component props with which - * the new instance is to be initialized. - */ - constructor(props) { - super(props); - - this.state = { - ...this.state, - - /** - * The context root of window.location i.e. this Web App. - * - * @type {string} - */ - windowLocationContextRoot: this._getWindowLocationContextRoot() - }; - } - /** * Overrides the parent method to inject {@link AtlasKitThemeProvider} as * the top most component. @@ -66,79 +44,4 @@ export class App extends AbstractApp { getWindowLocation() { return window.location; } - - /** - * Gets the context root of this Web App from window.location. - * - * @private - * @returns {string} The context root of window.location i.e. this Web App. - */ - _getWindowLocationContextRoot() { - return getLocationContextRoot(this.getWindowLocation()); - } - - /** - * Navigates to a specific Route (via platform-specific means). - * - * @param {Route} route - The Route to which to navigate. - * @protected - * @returns {void} - */ - _navigate(route) { - let path; - - if (route) { - path = route.path; - - const store = this._getStore(); - - // The syntax :room bellow is defined by react-router. It "matches a - // URL segment up to the next /, ?, or #. The matched string is - // called a param." - path - = path.replace( - /:room/g, - store.getState()['features/base/conference'].room); - path = this._routePath2WindowLocationPathname(path); - } - - // Navigate to the specified Route. - const windowLocation = this.getWindowLocation(); - let promise; - - if (!route || windowLocation.pathname === path) { - // The browser is at the specified path already and what remains is - // to make this App instance aware of the route to be rendered at - // the current location. - - // XXX Refer to the super's _navigate for an explanation why a - // Promise is returned. - promise = super._navigate(route); - } else { - // The browser must go to the specified location. Once the specified - // location becomes current, the App will be made aware of the route - // to be rendered at it. - windowLocation.pathname = path; - } - - return promise || Promise.resolve(); - } - - /** - * Converts a specific Route path to a window.location.pathname. - * - * @param {string} path - A Route path to be converted to/represeted as a - * window.location.pathname. - * @private - * @returns {string} A window.location.pathname-compatible representation of - * the specified Route path. - */ - _routePath2WindowLocationPathname(path) { - let pathname = this.state.windowLocationContextRoot; - - pathname.endsWith('/') || (pathname += '/'); - pathname += path.startsWith('/') ? path.substring(1) : path; - - return pathname; - } } diff --git a/react/features/app/functions.native.js b/react/features/app/functions.native.js index 0da77a8f1..5387f67a4 100644 --- a/react/features/app/functions.native.js +++ b/react/features/app/functions.native.js @@ -3,7 +3,7 @@ import { NativeModules } from 'react-native'; export * from './functions.any'; -export * from './getRouteToRender'; +export * from './router'; /** * Returns application name. diff --git a/react/features/app/functions.web.js b/react/features/app/functions.web.js index 15f8eff7b..5daf84694 100644 --- a/react/features/app/functions.web.js +++ b/react/features/app/functions.web.js @@ -1,89 +1,9 @@ // @flow -import { toState } from '../base/redux'; -import { getDeepLinkingPage } from '../deep-linking'; -import { UnsupportedDesktopBrowser } from '../unsupported-browser'; - -import { - // eslint-disable-next-line camelcase - _getRouteToRender as _super_getRouteToRender -} from './getRouteToRender'; - -declare var APP: Object; -declare var interfaceConfig: Object; -declare var loggingConfig: Object; - -/** - * Array of rules defining whether we should {@link _interceptComponent} to - * render. - * - * @private - * @param {Object} state - Object containing current redux state. - * @returns {Promise|void} - * @type {Function[]} - */ -const _INTERCEPT_COMPONENT_RULES = [ - getDeepLinkingPage, - state => { - const { webRTCReady } = state['features/base/lib-jitsi-meet']; - - if (webRTCReady === false) { - return Promise.resolve(UnsupportedDesktopBrowser); - } - - return Promise.resolve(); - } -]; - export * from './functions.any'; +export * from './router'; -/** - * Determines which route is to be rendered in order to depict a specific redux - * store. - * - * @param {(Object|Function)} stateOrGetState - The redux state or - * {@link getState} function. - * @returns {Promise} - */ -export function _getRouteToRender(stateOrGetState: Object | Function): Object { - const route = _super_getRouteToRender(stateOrGetState); - - // Intercepts route components if any of component interceptor rules is - // satisfied. - return _interceptComponent(stateOrGetState, route.component).then( - (component: React$Element<*>) => { - route.component = component; - - return route; - }, () => Promise.resolve(route)); -} - -/** - * Intercepts route components based on a {@link _INTERCEPT_COMPONENT_RULES}. - * - * @param {Object|Function} stateOrGetState - The redux state or - * {@link getState} function. - * @param {ReactElement} component - Current route component to render. - * @private - * @returns {Promise} If any of the pre-defined rules is - * satisfied, returns intercepted component. - */ -function _interceptComponent( - stateOrGetState: Object | Function, - component: React$Element<*>) { - const state = toState(stateOrGetState); - - const promises = []; - - _INTERCEPT_COMPONENT_RULES.forEach(rule => { - promises.push(rule(state)); - }); - - return Promise.all(promises).then( - results => - results.find(result => typeof result !== 'undefined') || component, - () => Promise.resolve(component)); -} +declare var interfaceConfig: Object; /** * Returns application name. diff --git a/react/features/app/getRouteToRender.js b/react/features/app/getRouteToRender.js deleted file mode 100644 index 155931350..000000000 --- a/react/features/app/getRouteToRender.js +++ /dev/null @@ -1,22 +0,0 @@ -/* @flow */ - -import { isRoomValid } from '../base/conference'; -import { RouteRegistry } from '../base/react'; -import { toState } from '../base/redux'; -import { Conference } from '../conference'; -import { WelcomePage } from '../welcome'; - -/** - * Determines which route is to be rendered in order to depict a specific Redux - * store. - * - * @param {(Object|Function)} stateOrGetState - Redux state or Regux getState() - * method. - * @returns {Route} - */ -export function _getRouteToRender(stateOrGetState: Object | Function) { - const { room } = toState(stateOrGetState)['features/base/conference']; - const component = isRoomValid(room) ? Conference : WelcomePage; - - return RouteRegistry.getRouteByComponent(component); -} diff --git a/react/features/app/middleware.js b/react/features/app/middleware.js index 380083334..faf3ae7e9 100644 --- a/react/features/app/middleware.js +++ b/react/features/app/middleware.js @@ -3,21 +3,17 @@ import { SET_ROOM } from '../base/conference'; import { CONNECTION_ESTABLISHED, - getURLWithoutParams, - SET_LOCATION_URL + getURLWithoutParams } from '../base/connection'; import { MiddlewareRegistry } from '../base/redux'; -import { _getRouteToRender } from './functions'; +import { getRouteToRender } from './router'; MiddlewareRegistry.register(store => next => action => { switch (action.type) { case CONNECTION_ESTABLISHED: return _connectionEstablished(store, next, action); - case SET_LOCATION_URL: - return _setLocationURL(store, next, action); - case SET_ROOM: return _setRoom(store, next, action); } @@ -77,40 +73,8 @@ function _connectionEstablished(store, next, action) { function _navigate({ getState }) { const state = getState(); const { app } = state['features/app']; - const routeToRender = _getRouteToRender(state); - // XXX Web changed _getRouteToRender to return Promsie instead of Route. - // Unfortunately, the commit left mobile to return Route. - let routeToRenderPromise; - - if (routeToRender && typeof routeToRender.then === 'function') { - routeToRenderPromise = routeToRender; - } - if (!routeToRenderPromise) { - routeToRenderPromise = Promise.resolve(routeToRender); - } - - routeToRenderPromise.then(app._navigate.bind(app)); -} - -/** - * Notifies the feature app that the action {@link SET_LOCATION_URL} is being - * dispatched within a specific redux {@code store}. - * - * @param {Store} store - The redux store in which the specified {@code action} - * is being dispatched. - * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the - * specified {@code action} to the specified {@code store}. - * @param {Action} action - The redux action, {@code SET_LOCATION_URL}, which is - * being dispatched in the specified {@code store}. - * @private - * @returns {Object} The new state that is the result of the reduction of the - * specified {@code action}. - */ -function _setLocationURL({ getState }, next, action) { - return ( - getState()['features/app'].app._navigate(undefined) - .then(() => next(action))); + getRouteToRender(state).then(route => app._navigate(route)); } /** diff --git a/react/features/app/router.js b/react/features/app/router.js new file mode 100644 index 000000000..52e7415eb --- /dev/null +++ b/react/features/app/router.js @@ -0,0 +1,109 @@ +// @flow +import type { Component } from 'react'; + +import { isRoomValid } from '../base/conference'; +import JitsiMeetJS from '../base/lib-jitsi-meet'; +import { Platform } from '../base/react'; +import { toState } from '../base/redux'; +import { Conference } from '../conference'; +import { getDeepLinkingPage } from '../deep-linking'; +import { UnsupportedDesktopBrowser } from '../unsupported-browser'; +import { + BlankPage, + WelcomePage, + generateRoomWithoutSeparator, + isWelcomePageAppEnabled, + isWelcomePageUserEnabled +} from '../welcome'; + +declare var interfaceConfig: Object; + +/** + * Object describing application route. + * + * @typedef {Object} Route + * @property {Component} component - React Component constructor. + * @property {string|undefined} href - New location, in case navigation involves + * a location change. + */ +export type Route = { + component: Class>, + href: ?string +}; + +/** + * Determines which route is to be rendered in order to depict a specific Redux + * store. + * + * @param {(Object|Function)} stateful - Redux state or Regux getState() + * method. + * @returns {Promise} + */ +export function getRouteToRender(stateful: Object | Function): Promise { + const state = toState(stateful); + const { room } = state['features/base/conference']; + const isMobileApp = navigator.product === 'ReactNative'; + const isMobileBrowser + = !isMobileApp && (Platform.OS === 'android' || Platform.OS === 'ios'); + const route: Route = { + component: BlankPage, + href: undefined + }; + + return new Promise(resolve => { + // First check if the current endpoint supports WebRTC. We are + // intentionally not performing the check for mobile browsers because: + // - the welcome page is mobile ready + // - if the URL points to a conference, getDeepLinkingPage will take + // care of it + if (!isMobileBrowser && !JitsiMeetJS.isWebRtcSupported()) { + route.component = UnsupportedDesktopBrowser; + resolve(route); + + return; + } + + if (isRoomValid(room)) { + if (isMobileApp) { + route.component = Conference; + resolve(route); + } else { + // Update the location if it doesn't match. This happens when a + // room is joined from the welcome page. The reason for doing + // this instead of using the history API is that we want to + // load the config.js which takes the room into account. + const { locationURL } = state['features/base/connection']; + + // eslint-disable-next-line no-negated-condition + if (window.location.href !== locationURL.href) { + route.href = locationURL.href; + resolve(route); + } else { + // Maybe show deep-linking, otherwise go to Conference. + getDeepLinkingPage(state).then(component => { + route.component = component || Conference; + resolve(route); + }); + } + } + + return; + } + + if (!isWelcomePageUserEnabled(state)) { + // Web: if the welcome page is disabled, go directly to a + // random room. + + let href = window.location.href; + + href.endsWith('/') || (href += '/'); + route.href = href + generateRoomWithoutSeparator(); + } else if (isWelcomePageAppEnabled(state)) { + // Mobile: only go to the welcome page if enabled. + + route.component = WelcomePage; + } + + resolve(route); + }); +} diff --git a/react/features/base/conference/reducer.js b/react/features/base/conference/reducer.js index 2204761c6..e3beaec72 100644 --- a/react/features/base/conference/reducer.js +++ b/react/features/base/conference/reducer.js @@ -1,6 +1,6 @@ // @flow -import { CONNECTION_WILL_CONNECT } from '../connection'; +import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from '../connection'; import { JitsiConferenceErrors } from '../lib-jitsi-meet'; import { assign, ReducerRegistry, set } from '../redux'; import { LOCKED_LOCALLY, LOCKED_REMOTELY } from '../../room-lock'; @@ -66,6 +66,9 @@ ReducerRegistry.register('features/base/conference', (state = {}, action) => { case SET_FOLLOW_ME: return set(state, 'followMeEnabled', action.enabled); + case SET_LOCATION_URL: + return set(state, 'room', undefined); + case SET_PASSWORD: return _setPassword(state, action); diff --git a/react/features/base/connection/actions.web.js b/react/features/base/connection/actions.web.js index 157e29b3c..5ee29aafb 100644 --- a/react/features/base/connection/actions.web.js +++ b/react/features/base/connection/actions.web.js @@ -2,8 +2,6 @@ import type { Dispatch } from 'redux'; -import { libInitError, WEBRTC_NOT_SUPPORTED } from '../lib-jitsi-meet'; - declare var APP: Object; declare var config: Object; @@ -26,24 +24,14 @@ export function connect() { // XXX Lib-jitsi-meet does not accept uppercase letters. const room = state['features/base/conference'].room.toLowerCase(); - const { initPromise } = state['features/base/lib-jitsi-meet']; // XXX For web based version we use conference initialization logic // from the old app (at the moment of writing). - return initPromise.then(() => APP.conference.init({ + return APP.conference.init({ roomName: room - })).catch(error => { + }).catch(error => { APP.API.notifyConferenceLeft(APP.conference.roomName); logger.error(error); - - // TODO The following are in fact Errors raised by - // JitsiMeetJS.init() which should be taken care of in - // features/base/lib-jitsi-meet but we are not there yet on the - // Web at the time of this writing. - switch (error.name) { - case WEBRTC_NOT_SUPPORTED: - dispatch(libInitError(error)); - } }); }; } diff --git a/react/features/base/lib-jitsi-meet/actionTypes.js b/react/features/base/lib-jitsi-meet/actionTypes.js index 39a0cca35..1fd814788 100644 --- a/react/features/base/lib-jitsi-meet/actionTypes.js +++ b/react/features/base/lib-jitsi-meet/actionTypes.js @@ -27,16 +27,6 @@ export const LIB_DID_INIT = Symbol('LIB_DID_INIT'); */ export const LIB_INIT_ERROR = Symbol('LIB_INIT_ERROR'); -/** - * Action to dispatch the promise returned by JitsiMeetJS.init. - * - * { - * type: LIB_INIT_PROMISE_CREATED, - * initPromise: Promise - * } - */ -export const LIB_INIT_PROMISE_CREATED = Symbol('LIB_INIT_PROMISE_CREATED'); - /** * The type of Redux action which signals that {@link JitsiMeetJS} will be * disposed. @@ -56,13 +46,3 @@ export const LIB_WILL_DISPOSE = Symbol('LIB_WILL_DISPOSE'); * } */ export const LIB_WILL_INIT = Symbol('LIB_WILL_INIT'); - -/** - * The type of Redux action which indicates whether WebRTC is ready. - * - * { - * type: SET_WEBRTC_READY, - * webRTCReady: boolean | Promise - * } - */ -export const SET_WEBRTC_READY = Symbol('SET_WEBRTC_READY'); diff --git a/react/features/base/lib-jitsi-meet/actions.js b/react/features/base/lib-jitsi-meet/actions.js index 7afe60851..2db316beb 100644 --- a/react/features/base/lib-jitsi-meet/actions.js +++ b/react/features/base/lib-jitsi-meet/actions.js @@ -7,10 +7,8 @@ import { LIB_DID_DISPOSE, LIB_DID_INIT, LIB_INIT_ERROR, - LIB_INIT_PROMISE_CREATED, LIB_WILL_DISPOSE, - LIB_WILL_INIT, - SET_WEBRTC_READY + LIB_WILL_INIT } from './actionTypes'; import { isAnalyticsEnabled } from './functions'; @@ -38,7 +36,7 @@ export function disposeLib() { * @returns {Function} */ export function initLib() { - return (dispatch: Dispatch<*>, getState: Function): Promise => { + return (dispatch: Dispatch<*>, getState: Function): void => { const config = getState()['features/base/config']; if (!config) { @@ -47,30 +45,15 @@ export function initLib() { dispatch({ type: LIB_WILL_INIT }); - const initPromise = JitsiMeetJS.init({ - enableAnalyticsLogging: isAnalyticsEnabled(getState), - ...config - }); - - dispatch({ - type: LIB_INIT_PROMISE_CREATED, - initPromise - }); - - return ( - initPromise - .then(() => dispatch({ type: LIB_DID_INIT })) - .catch(error => { - // TODO: See the comment in the connect action in - // base/connection/actions.web.js. - if (typeof APP === 'undefined') { - dispatch(libInitError(error)); - } - - // TODO Handle LIB_INIT_ERROR error somewhere instead. - console.error('lib-jitsi-meet failed to init:', error); - throw error; - })); + try { + JitsiMeetJS.init({ + enableAnalyticsLogging: isAnalyticsEnabled(getState), + ...config + }); + dispatch({ type: LIB_DID_INIT }); + } catch (error) { + dispatch(libInitError(error)); + } }; } @@ -89,22 +72,3 @@ export function libInitError(error: Error) { error }; } - -/** - * Sets the indicator which determines whether WebRTC is ready. - * - * @param {boolean} webRTCReady - The indicator which determines - * whether WebRTC is ready. - * @returns {Function} - */ -export function setWebRTCReady(webRTCReady: boolean) { - return (dispatch: Function, getState: Function) => { - if (getState()['features/base/lib-jitsi-meet'].webRTCReady - !== webRTCReady) { - dispatch({ - type: SET_WEBRTC_READY, - webRTCReady - }); - } - }; -} diff --git a/react/features/base/lib-jitsi-meet/constants.js b/react/features/base/lib-jitsi-meet/constants.js deleted file mode 100644 index 5be09329b..000000000 --- a/react/features/base/lib-jitsi-meet/constants.js +++ /dev/null @@ -1,5 +0,0 @@ -/** - * The name of the Error thrown by {@link JitsiMeetJS.init()} which indicates - * that WebRTC is not supported by the execution environment. - */ -export const WEBRTC_NOT_SUPPORTED = 'WEBRTC_NOT_SUPPORTED'; diff --git a/react/features/base/lib-jitsi-meet/index.js b/react/features/base/lib-jitsi-meet/index.js index 616b075c9..a6bea339b 100644 --- a/react/features/base/lib-jitsi-meet/index.js +++ b/react/features/base/lib-jitsi-meet/index.js @@ -24,7 +24,6 @@ export const JitsiTrackEvents = JitsiMeetJS.events.track; export * from './actions'; export * from './actionTypes'; -export * from './constants'; export * from './functions'; import './middleware'; diff --git a/react/features/base/lib-jitsi-meet/middleware.js b/react/features/base/lib-jitsi-meet/middleware.js index cec7434fd..bc83b192c 100644 --- a/react/features/base/lib-jitsi-meet/middleware.js +++ b/react/features/base/lib-jitsi-meet/middleware.js @@ -6,9 +6,8 @@ import { PARTICIPANT_LEFT } from '../participants'; import { MiddlewareRegistry } from '../redux'; import JitsiMeetJS from './_'; -import { disposeLib, initLib, setWebRTCReady } from './actions'; -import { LIB_DID_INIT, LIB_INIT_ERROR, LIB_WILL_INIT } from './actionTypes'; -import { WEBRTC_NOT_SUPPORTED } from './constants'; +import { disposeLib, initLib } from './actions'; +import { LIB_WILL_INIT } from './actionTypes'; declare var APP: Object; @@ -31,18 +30,6 @@ MiddlewareRegistry.register(store => next => action => { _setErrorHandlers(); } break; - case LIB_DID_INIT: - // FIXME: The web version doesn't need this action during initialization - // because it is still using the old logic from conference.js. We still - // have to reactify the old logic from conference.js and then maybe - // we'll need this action for web too. - if (typeof APP === 'undefined') { - store.dispatch(setWebRTCReady(true)); - } - break; - - case LIB_INIT_ERROR: - return _libInitError(store, next, action); case PARTICIPANT_LEFT: action.participant.local && store.dispatch(disposeLib()); @@ -55,32 +42,6 @@ MiddlewareRegistry.register(store => next => action => { return next(action); }); -/** - * Notifies the feature base/lib-jitsi-meet that the action LIB_INIT_ERROR is - * being dispatched within a specific Redux store. - * - * @param {Store} store - The Redux store in which the specified action is being - * dispatched. - * @param {Dispatch} next - The Redux dispatch function to dispatch the - * specified action to the specified store. - * @param {Action} action - The Redux action LIB_INIT_ERROR which is being - * dispatched in the specified store. - * @private - * @returns {Object} The new state that is the result of the reduction of the - * specified action. - */ -function _libInitError(store, next, action) { - const nextState = next(action); - - const { error } = action; - - if (error && error.name === WEBRTC_NOT_SUPPORTED) { - store.dispatch(setWebRTCReady(false)); - } - - return nextState; -} - /** * Notifies the feature base/lib-jitsi-meet that the action SET_CONFIG is being * dispatched within a specific Redux store. diff --git a/react/features/base/lib-jitsi-meet/reducer.js b/react/features/base/lib-jitsi-meet/reducer.js index 184b99593..3b17397aa 100644 --- a/react/features/base/lib-jitsi-meet/reducer.js +++ b/react/features/base/lib-jitsi-meet/reducer.js @@ -5,9 +5,7 @@ import { ReducerRegistry } from '../redux'; import { LIB_DID_DISPOSE, LIB_DID_INIT, - LIB_INIT_ERROR, - LIB_INIT_PROMISE_CREATED, - SET_WEBRTC_READY + LIB_INIT_ERROR } from './actionTypes'; /** @@ -35,20 +33,7 @@ ReducerRegistry.register( return { ...state, initError: action.error, - initialized: false, - initPromise: undefined - }; - - case LIB_INIT_PROMISE_CREATED: - return { - ...state, - initPromise: action.initPromise - }; - - case SET_WEBRTC_READY: - return { - ...state, - webRTCReady: action.webRTCReady + initialized: false }; default: diff --git a/react/features/base/react/RouteRegistry.js b/react/features/base/react/RouteRegistry.js deleted file mode 100644 index b768027a4..000000000 --- a/react/features/base/react/RouteRegistry.js +++ /dev/null @@ -1,119 +0,0 @@ -/* @flow */ - -import { Component } from 'react'; - -/** - * Object describing application route. - * - * @typedef {Object} Route - * @property {Component} component - React Component constructor. - * @property {string} path - URL route, required for web routing. - */ -type Route = { - component: Class>, // eslint-disable-line no-undef - path: string -}; - -/** - * A registry for Navigator routes, allowing features to register themselves - * without needing to create additional inter-feature dependencies. - */ -class RouteRegistry { - _elements: Array; - - /** - * Initializes a new RouteRegistry instance. - */ - constructor() { - /** - * The set of registered routes. - * - * @private - * @type {Route[]} - */ - this._elements = []; - } - - /** - * Determines whether two specific Routes are equal i.e. they describe one - * and the same abstract route. - * - * @param {Object} a - The Route to compare to b. - * @param {Object} b - The Route to compare to a. - * @returns {boolean} True if the specified a and b describe one and the - * same abstract route; otherwise, false. - */ - areRoutesEqual(a: Route, b: Route) { - if (a === b) { // reflexive - return true; - } - if (!a) { - return !b; - } - if (!b) { - return !a; - } - - const aKeys = Object.keys(a); - const bKeys = Object.keys(b); - - return ( - aKeys.length === bKeys.length /* symmetric */ - && aKeys.every(key => a[key] === b[key])); - } - - /** - * Returns all registered routes. - * - * @returns {Route[]} - */ - getRoutes() { - // We use the destructuring operator to 'clone' the route object to - // prevent modifications from outside (e.g. React Native's Navigator - // extends it with additional properties). - return this._elements.map(r => { - return { ...r }; - }); - } - - /* eslint-disable no-undef */ - - /** - * Returns registered route by name if any. - * - * @param {Component} component - The React Component (class) of the route - * to retrieve. - * @returns {Route|null} - */ - getRouteByComponent(component: Class>) { - - /* eslint-enable no-undef */ - - const route = this._elements.find(r => r.component === component); - - // We use destructuring operator to 'clone' route object to prevent - // modifications from outside (e.g. React Native's Navigator extends - // it with some additional properties). - return route ? { ...route } : null; - } - - /** - * Adds a route to this registry. - * - * @param {Route} route - Route definition object. - * @returns {void} - */ - register(route: Route) { - if (this._elements.includes(route)) { - throw new Error( - `Route ${String(route.component)} is registered already!`); - } - - this._elements.push(route); - } -} - -/** - * The public singleton instance of the RouteRegistry class. - */ -export default new RouteRegistry(); diff --git a/react/features/base/react/index.js b/react/features/base/react/index.js index 6464d31ef..fff596561 100644 --- a/react/features/base/react/index.js +++ b/react/features/base/react/index.js @@ -1,3 +1,2 @@ export * from './components'; export { default as Platform } from './Platform'; -export { default as RouteRegistry } from './RouteRegistry'; diff --git a/react/features/conference/components/Conference.native.js b/react/features/conference/components/Conference.native.js index 35678d9a0..a4954f11a 100644 --- a/react/features/conference/components/Conference.native.js +++ b/react/features/conference/components/Conference.native.js @@ -37,6 +37,13 @@ type Props = { */ _connecting: boolean, + /** + * Current conference's full URL. + * + * @private + */ + _locationURL: URL, + /** * The handler which dispatches the (redux) action connect. * @@ -77,6 +84,13 @@ type Props = { */ _reducedUI: boolean, + /** + * The current conference room name. + * + * @private + */ + _room: string, + /** * The handler which dispatches the (redux) action setToolboxVisible to * show/hide the Toolbox. @@ -163,15 +177,30 @@ class Conference extends Component { * participant count. * * @inheritdoc - * @param {Object} nextProps - The read-only React {@code Component} props + * @param {Props} nextProps - The read-only React {@code Component} props * that this instance will receive. * @returns {void} */ - componentWillReceiveProps({ _participantCount: newParticipantCount }) { + componentWillReceiveProps(nextProps: Props) { const { + _locationURL: oldLocationURL, + _onConnect, + _onDisconnect, _participantCount: oldParticipantCount, + _room: oldRoom, _setToolboxVisible } = this.props; + const { + _locationURL: newLocationURL, + _participantCount: newParticipantCount, + _room: newRoom + } = nextProps; + + // If the location URL changes we need to reconnect. + oldLocationURL !== newLocationURL && _onDisconnect(); + + // Start the connection process when there is a (valid) room. + oldRoom !== newRoom && newRoom && _onConnect(); if (oldParticipantCount === 1) { newParticipantCount > 1 && _setToolboxVisible(false); @@ -389,15 +418,23 @@ function _mapDispatchToProps(dispatch) { * @private * @returns {{ * _connecting: boolean, + * _locationURL: URL, * _participantCount: number, * _reducedUI: boolean, + * _room: string, * _toolboxVisible: boolean, * _toolboxAlwaysVisible: boolean * }} */ function _mapStateToProps(state) { - const { connecting, connection } = state['features/base/connection']; - const { conference, joining, leaving } = state['features/base/conference']; + const { connecting, connection, locationURL } + = state['features/base/connection']; + const { + conference, + joining, + leaving, + room + } = state['features/base/conference']; const { reducedUI } = state['features/base/responsive-ui']; const { alwaysVisible, visible } = state['features/toolbox']; @@ -425,6 +462,14 @@ function _mapStateToProps(state) { */ _connecting: Boolean(connecting_), + /** + * Current conference's full URL. + * + * @private + * @type {URL} + */ + _locationURL: locationURL, + /** * The number of participants in the conference. * @@ -442,6 +487,14 @@ function _mapStateToProps(state) { */ _reducedUI: reducedUI, + /** + * The current conference room name. + * + * @private + * @type {string} + */ + _room: room, + /** * The indicator which determines whether the Toolbox is visible. * diff --git a/react/features/conference/components/Conference.web.js b/react/features/conference/components/Conference.web.js index c07d21503..6edaf432a 100644 --- a/react/features/conference/components/Conference.web.js +++ b/react/features/conference/components/Conference.web.js @@ -4,6 +4,7 @@ import _ from 'lodash'; import React, { Component } from 'react'; import { connect as reactReduxConnect } from 'react-redux'; +import { obtainConfig } from '../../base/config'; import { connect, disconnect } from '../../base/connection'; import { DialogContainer } from '../../base/dialog'; import { translate } from '../../base/i18n'; @@ -22,8 +23,29 @@ import { import { maybeShowSuboptimalExperienceNotification } from '../functions'; declare var APP: Object; +declare var config: Object; declare var interfaceConfig: Object; +const logger = require('jitsi-meet-logger').getLogger(__filename); + +/** + * Promise wrapper on obtain config method. When HttpConfigFetch will be moved + * to React app it's better to use load config instead. + * + * @param {string} location - URL of the domain from which the config is to be + * obtained. + * @param {string} room - Room name. + * @private + * @returns {Promise} + */ +function _obtainConfig(location: string, room: string) { + return new Promise((resolve, reject) => + obtainConfig(location, room, (success, error) => { + success ? resolve() : reject(error); + }) + ); +} + /** * DOM events for when full screen mode has changed. Different browsers need * different vendor prefixes. @@ -47,6 +69,11 @@ type Props = { */ _iAmRecorder: boolean, + /** + * Conference room name. + */ + _room: string, + dispatch: Function, t: Function } @@ -84,29 +111,35 @@ class Conference extends Component { } /** - * Until we don't rewrite UI using react components - * we use UI.start from old app. Also method translates - * component right after it has been mounted. + * Start the connection and get the UI ready for the conference. * * @inheritdoc */ componentDidMount() { - APP.UI.start(); + const { configLocation } = config; - APP.UI.registerListeners(); - APP.UI.bindEvents(); + if (configLocation) { + _obtainConfig(configLocation, this.props._room) + .then(() => { + const now = window.performance.now(); - FULL_SCREEN_EVENTS.forEach(name => - document.addEventListener(name, this._onFullScreenChange)); + APP.connectionTimes['configuration.fetched'] = now; + logger.log('(TIME) configuration fetched:\t', now); - const { dispatch, t } = this.props; + this._start(); + }) + .catch(err => { + logger.log(err); - dispatch(connect()); - - maybeShowSuboptimalExperienceNotification(dispatch, t); - - interfaceConfig.filmStripOnly - && dispatch(setToolboxAlwaysVisible(true)); + // Show obtain config error. + APP.UI.messageHandler.showError({ + titleKey: 'connection.CONNFAIL', + descriptionKey: 'dialog.connectError' + }); + }); + } else { + this._start(); + } } /** @@ -185,6 +218,32 @@ class Conference extends Component { _onShowToolbar() { this.props.dispatch(showToolbox()); } + + /** + * Until we don't rewrite UI using react components + * we use UI.start from old app. Also method translates + * component right after it has been mounted. + * + * @inheritdoc + */ + _start() { + APP.UI.start(); + + APP.UI.registerListeners(); + APP.UI.bindEvents(); + + FULL_SCREEN_EVENTS.forEach(name => + document.addEventListener(name, this._onFullScreenChange)); + + const { dispatch, t } = this.props; + + dispatch(connect()); + + maybeShowSuboptimalExperienceNotification(dispatch, t); + + interfaceConfig.filmStripOnly + && dispatch(setToolboxAlwaysVisible(true)); + } } /** @@ -198,6 +257,7 @@ class Conference extends Component { * }} */ function _mapStateToProps(state) { + const { room } = state['features/base/conference']; const { iAmRecorder } = state['features/base/config']; return { @@ -206,7 +266,12 @@ function _mapStateToProps(state) { * * @private */ - _iAmRecorder: iAmRecorder + _iAmRecorder: iAmRecorder, + + /** + * Conference room name. + */ + _room: room }; } diff --git a/react/features/conference/index.js b/react/features/conference/index.js index 7115963a1..7ce19e0e6 100644 --- a/react/features/conference/index.js +++ b/react/features/conference/index.js @@ -1,4 +1,3 @@ export * from './components'; import './middleware'; -import './route'; diff --git a/react/features/conference/route.js b/react/features/conference/route.js deleted file mode 100644 index bf4c5e188..000000000 --- a/react/features/conference/route.js +++ /dev/null @@ -1,105 +0,0 @@ -// @flow - -import ConferenceUrl from '../../../modules/URL/ConferenceUrl'; - -import { obtainConfig } from '../base/config'; -import { RouteRegistry } from '../base/react'; - -import { Conference } from './components'; - -declare var APP: Object; -declare var config: Object; - -const logger = require('jitsi-meet-logger').getLogger(__filename); - -/** - * Register route for Conference (page). - */ -RouteRegistry.register({ - component: Conference, - onEnter: () => { - // XXX If config or jwt are set by hash or query parameters - // Getting raw URL before stripping it. - _obtainConfigAndInit(); - }, - path: '/:room' -}); - -/** - * Initialization of the app. - * - * @private - * @returns {void} - */ -function _initConference() { - APP.ConferenceUrl = new ConferenceUrl(window.location); -} - -/** - * Promise wrapper on obtain config method. When HttpConfigFetch will be moved - * to React app it's better to use load config instead. - * - * @param {string} location - URL of the domain from which the config is to be - * obtained. - * @param {string} room - Room name. - * @private - * @returns {Promise} - */ -function _obtainConfig(location: string, room: string) { - return new Promise((resolve, reject) => - obtainConfig(location, room, (success, error) => { - success ? resolve() : reject(error); - }) - ); -} - -/** - * If we have an HTTP endpoint for getting config.json configured we're going to - * read it and override properties from config.js and interfaceConfig.js. If - * there is no endpoint we'll just continue with initialization. Keep in mind - * that if the endpoint has been configured and we fail to obtain the config for - * any reason then the conference won't start and error message will be - * displayed to the user. - * - * @private - * @returns {void} - */ -function _obtainConfigAndInit() { - // Skip initialization if conference is initialized already. - if (typeof APP !== 'undefined' && !APP.ConferenceUrl) { - const location = config.configLocation; - const room = APP.conference.roomName; - - if (location) { - _obtainConfig(location, room) - .then(() => { - _obtainConfigHandler(); - _initConference(); - }) - .catch(err => { - logger.log(err); - - // Show obtain config error. - APP.UI.messageHandler.showError({ - titleKey: 'connection.CONNFAIL', - descriptionKey: 'dialog.connectError' - }); - }); - } else { - _initConference(); - } - } -} - -/** - * Obtain config handler. - * - * @private - * @returns {Promise} - */ -function _obtainConfigHandler() { - const now = window.performance.now(); - - APP.connectionTimes['configuration.fetched'] = now; - logger.log('(TIME) configuration fetched:\t', now); -} diff --git a/react/features/deep-linking/components/DeepLinkingDesktopPage.native.js b/react/features/deep-linking/components/DeepLinkingDesktopPage.native.js new file mode 100644 index 000000000..e69de29bb diff --git a/react/features/deep-linking/components/DeepLinkingDesktopPage.js b/react/features/deep-linking/components/DeepLinkingDesktopPage.web.js similarity index 100% rename from react/features/deep-linking/components/DeepLinkingDesktopPage.js rename to react/features/deep-linking/components/DeepLinkingDesktopPage.web.js diff --git a/react/features/deep-linking/components/DeepLinkingMobilePage.native.js b/react/features/deep-linking/components/DeepLinkingMobilePage.native.js new file mode 100644 index 000000000..e69de29bb diff --git a/react/features/deep-linking/components/DeepLinkingMobilePage.js b/react/features/deep-linking/components/DeepLinkingMobilePage.web.js similarity index 100% rename from react/features/deep-linking/components/DeepLinkingMobilePage.js rename to react/features/deep-linking/components/DeepLinkingMobilePage.web.js diff --git a/react/features/deep-linking/components/NoMobileApp.native.js b/react/features/deep-linking/components/NoMobileApp.native.js new file mode 100644 index 000000000..e69de29bb diff --git a/react/features/deep-linking/components/NoMobileApp.js b/react/features/deep-linking/components/NoMobileApp.web.js similarity index 100% rename from react/features/deep-linking/components/NoMobileApp.js rename to react/features/deep-linking/components/NoMobileApp.web.js diff --git a/react/features/device-selection/actions.js b/react/features/device-selection/actions.js index beb201f06..07408dc4c 100644 --- a/react/features/device-selection/actions.js +++ b/react/features/device-selection/actions.js @@ -94,10 +94,7 @@ function _processRequest(dispatch, getState, request, responseCallback) { // esl switch (request.name) { case 'isDeviceListAvailable': - JitsiMeetJS.mediaDevices.isDeviceListAvailable() - .then(isDeviceListAvailable => - responseCallback(isDeviceListAvailable)) - .catch(e => responseCallback(null, e)); + responseCallback(JitsiMeetJS.mediaDevices.isDeviceListAvailable()); break; case 'isDeviceChangeAvailable': responseCallback( diff --git a/react/features/settings/popup.js b/react/features/settings/popup.js index 47be76576..19b365e88 100644 --- a/react/features/settings/popup.js +++ b/react/features/settings/popup.js @@ -8,9 +8,8 @@ import DeviceSelectionPopup from './DeviceSelectionPopup'; let deviceSelectionPopup; window.init = i18next => { - JitsiMeetJS.init({}).then(() => { - deviceSelectionPopup = new DeviceSelectionPopup(i18next); - }); + JitsiMeetJS.init(); + deviceSelectionPopup = new DeviceSelectionPopup(i18next); }; window.addEventListener('beforeunload', () => deviceSelectionPopup.close()); diff --git a/react/features/unsupported-browser/index.js b/react/features/unsupported-browser/index.js index 7ce19e0e6..07635cbbc 100644 --- a/react/features/unsupported-browser/index.js +++ b/react/features/unsupported-browser/index.js @@ -1,3 +1 @@ export * from './components'; - -import './middleware'; diff --git a/react/features/unsupported-browser/middleware.js b/react/features/unsupported-browser/middleware.js deleted file mode 100644 index 4b726dd10..000000000 --- a/react/features/unsupported-browser/middleware.js +++ /dev/null @@ -1,54 +0,0 @@ -// @flow - -import { appNavigate } from '../app'; -import { SET_WEBRTC_READY } from '../base/lib-jitsi-meet'; -import { MiddlewareRegistry } from '../base/redux'; - -/** - * Middleware that dispatches appNavigate when WebRTC readiness changes. - * - * @param {Store} store - The Redux store. - * @returns {Function} - * @private - */ -MiddlewareRegistry.register(store => next => action => { - switch (action.type) { - case SET_WEBRTC_READY: - return _setWebRTCReady(store, next, action); - } - - return next(action); -}); - -/** - * Notifies the feature unsupported-browser that the action SET_WEBRTC_READY is - * being dispatched within a specific Redux store. - * - * @param {Store} store - The Redux store in which the specified action is being - * dispatched. - * @param {Dispatch} next - The Redux dispatch function to dispatch the - * specified action to the specified store. - * @param {Action} action - The Redux action SET_WEBRTC_READY which is being - * dispatched in the specified store. - * @private - * @returns {Object} The new state that is the result of the reduction of the - * specified action. - */ -function _setWebRTCReady({ dispatch, getState }, next, action) { - const result = next(action); - - // FIXME The feature unsupported-browser needs to notify the app that it may - // need to render a different Component at its current location because the - // execution enviroment has changed. The current location is not necessarily - // available through window.location (e.g. on mobile) but the following - // works at the time of this writing. - const windowLocation = getState()['features/app'].app.getWindowLocation(); - - if (windowLocation) { - const { href } = windowLocation; - - href && dispatch(appNavigate(href)); - } - - return result; -} diff --git a/react/features/welcome/components/BlankPage.native.js b/react/features/welcome/components/BlankPage.native.js index fea2508e9..2c3b0f04f 100644 --- a/react/features/welcome/components/BlankPage.native.js +++ b/react/features/welcome/components/BlankPage.native.js @@ -1,38 +1,27 @@ -/* @flow */ +// @flow -import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; +import type { Dispatch } from 'redux'; import { destroyLocalTracks } from '../../base/tracks'; import { NetworkActivityIndicator } from '../../mobile/network-activity'; -import { isWelcomePageAppEnabled } from '../functions'; import LocalVideoTrackUnderlay from './LocalVideoTrackUnderlay'; +/** + * {@code BlankPage} React {@code Component}'s prop types. + */ +type Props = { + dispatch: Dispatch<*> +} + /** * The React {@code Component} displayed by {@code AbstractApp} when it has no * {@code Route} to render. Renders a progress indicator when there are ongoing * network requests. */ -class BlankPage extends Component<*> { - /** - * {@code BlankPage} React {@code Component}'s prop types. - * - * @static - */ - static propTypes = { - /** - * The indicator which determines whether {@code WelcomePage} is (to - * be) rendered. - * - * @private - */ - _welcomePageEnabled: PropTypes.bool, - - dispatch: PropTypes.func - }; - +class BlankPage extends Component { /** * Destroys the local tracks (if any) since no media is desired when this * component is rendered. @@ -41,8 +30,7 @@ class BlankPage extends Component<*> { * @returns {void} */ componentWillMount() { - this.props._welcomePageEnabled - || this.props.dispatch(destroyLocalTracks()); + this.props.dispatch(destroyLocalTracks()); } /** @@ -60,20 +48,4 @@ class BlankPage extends Component<*> { } } -/** - * Maps (parts of) the redux state to the React {@code Component} props of - * {@code BlankPage}. - * - * @param {Object} state - The redux state. - * @private - * @returns {{ - * _welcomePageEnabled: boolean - * }} - */ -function _mapStateToProps(state) { - return { - _welcomePageEnabled: isWelcomePageAppEnabled(state) - }; -} - -export default connect(_mapStateToProps)(BlankPage); +export default connect()(BlankPage); diff --git a/react/features/welcome/functions.js b/react/features/welcome/functions.js index 47e761ca0..1a5d7990e 100644 --- a/react/features/welcome/functions.js +++ b/react/features/welcome/functions.js @@ -19,8 +19,6 @@ export * from './roomnameGenerator'; * {@code true}; otherwise, {@code false}. */ export function isWelcomePageAppEnabled(stateful: Function | Object) { - let b; - if (navigator.product === 'ReactNative') { // We introduced the welcomePageEnabled prop on App in Jitsi Meet SDK // for Android and iOS. There isn't a strong reason not to introduce it @@ -29,12 +27,10 @@ export function isWelcomePageAppEnabled(stateful: Function | Object) { // - Enabling/disabling the Welcome page on Web historically // automatically redirects to a random room and that does not make sense // on mobile (right now). - b = Boolean(getAppProp(stateful, 'welcomePageEnabled')); - } else { - b = true; + return Boolean(getAppProp(stateful, 'welcomePageEnabled')); } - return b; + return true; } /** diff --git a/react/features/welcome/index.js b/react/features/welcome/index.js index f77620716..076f379b7 100644 --- a/react/features/welcome/index.js +++ b/react/features/welcome/index.js @@ -2,4 +2,3 @@ export * from './components'; export * from './functions'; import './reducer'; -import './route'; diff --git a/react/features/welcome/route.js b/react/features/welcome/route.js deleted file mode 100644 index 1cf42c4a3..000000000 --- a/react/features/welcome/route.js +++ /dev/null @@ -1,35 +0,0 @@ -/* @flow */ - -import { RouteRegistry } from '../base/react'; - -import { WelcomePage } from './components'; -import { - generateRoomWithoutSeparator, - isWelcomePageAppEnabled, - isWelcomePageUserEnabled -} from './functions'; - -/** - * Register route for {@code WelcomePage}. - */ -RouteRegistry.register({ - component: WelcomePage, - onEnter, - path: '/' -}); - -/** - * Skips the {@code WelcomePage} if it is disabled (by the app or the user). - * - * @param {Object} store - The redux store. - * @param {Function} replace - The function to redirect to another path. - * @returns {void} - */ -function onEnter({ getState }, replace) { - if (isWelcomePageAppEnabled(getState)) { - isWelcomePageUserEnabled(getState) - || replace(`/${generateRoomWithoutSeparator()}`); - } else { - replace(undefined); - } -}