2017-11-16 18:26:14 +00:00
|
|
|
/* global APP */
|
|
|
|
|
core: refactor routing
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
2018-06-29 07:58:31 +00:00
|
|
|
import _ from 'lodash';
|
2017-08-15 21:44:29 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2018-05-22 14:22:16 +00:00
|
|
|
import React, { Component, Fragment } from 'react';
|
2017-03-01 02:55:12 +00:00
|
|
|
import { I18nextProvider } from 'react-i18next';
|
2017-01-16 00:28:02 +00:00
|
|
|
import { Provider } from 'react-redux';
|
2017-01-26 21:29:28 +00:00
|
|
|
import { compose, createStore } from 'redux';
|
|
|
|
import Thunk from 'redux-thunk';
|
2016-10-05 14:36:59 +00:00
|
|
|
|
2017-03-01 02:55:12 +00:00
|
|
|
import { i18next } from '../../base/i18n';
|
2018-05-22 03:44:00 +00:00
|
|
|
import {
|
|
|
|
MiddlewareRegistry,
|
|
|
|
ReducerRegistry,
|
|
|
|
StateListenerRegistry
|
|
|
|
} from '../../base/redux';
|
2018-02-26 19:37:12 +00:00
|
|
|
import { SoundCollection } from '../../base/sounds';
|
2018-02-02 19:35:49 +00:00
|
|
|
import { PersistenceRegistry } from '../../base/storage';
|
2017-07-26 19:27:29 +00:00
|
|
|
import { toURLString } from '../../base/util';
|
2017-11-23 17:03:33 +00:00
|
|
|
import { OverlayContainer } from '../../overlay';
|
2016-10-05 14:36:59 +00:00
|
|
|
|
2017-07-26 19:40:34 +00:00
|
|
|
import { appNavigate, appWillMount, appWillUnmount } from '../actions';
|
2018-07-11 08:57:07 +00:00
|
|
|
import { getDefaultURL } from '../functions';
|
2017-06-09 10:26:21 +00:00
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
|
|
|
* Base (abstract) class for main App component.
|
|
|
|
*
|
|
|
|
* @abstract
|
|
|
|
*/
|
|
|
|
export class AbstractApp extends Component {
|
2016-12-01 01:52:39 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* {@code AbstractApp} component's property types.
|
2016-12-01 01:52:39 +00:00
|
|
|
*
|
|
|
|
* @static
|
|
|
|
*/
|
|
|
|
static propTypes = {
|
2017-06-09 10:26:21 +00:00
|
|
|
/**
|
2017-06-09 19:09:23 +00:00
|
|
|
* The default URL {@code AbstractApp} is to open when not in any
|
|
|
|
* conference/room.
|
2017-06-09 10:26:21 +00:00
|
|
|
*/
|
2017-08-15 21:44:29 +00:00
|
|
|
defaultURL: PropTypes.string,
|
2017-06-09 10:26:21 +00:00
|
|
|
|
2017-08-15 22:21:58 +00:00
|
|
|
// XXX Refer to the implementation of loadURLObject: in
|
|
|
|
// ios/sdk/src/JitsiMeetView.m for further information.
|
|
|
|
timestamp: PropTypes.any,
|
|
|
|
|
2016-12-01 01:52:39 +00:00
|
|
|
/**
|
|
|
|
* The URL, if any, with which the app was launched.
|
|
|
|
*/
|
2017-08-15 21:44:29 +00:00
|
|
|
url: PropTypes.oneOfType([
|
|
|
|
PropTypes.object,
|
|
|
|
PropTypes.string
|
2017-07-26 19:27:29 +00:00
|
|
|
])
|
2017-06-02 02:01:50 +00:00
|
|
|
};
|
2016-12-01 01:52:39 +00:00
|
|
|
|
2017-01-16 00:28:02 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Initializes a new {@code AbstractApp} instance.
|
2017-01-16 00:28:02 +00:00
|
|
|
*
|
2017-07-26 19:40:34 +00:00
|
|
|
* @param {Object} props - The read-only React {@code Component} props with
|
|
|
|
* which the new instance is to be initialized.
|
2017-01-16 00:28:02 +00:00
|
|
|
*/
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
2017-12-14 17:02:32 +00:00
|
|
|
|
2018-07-12 03:57:44 +00:00
|
|
|
/**
|
2018-07-10 14:42:22 +00:00
|
|
|
* The state of the »possible« async initialization of the
|
|
|
|
* {@code AbstractApp}.
|
2018-07-12 03:57:44 +00:00
|
|
|
*/
|
|
|
|
appAsyncInitialized: false,
|
|
|
|
|
2017-01-16 00:28:02 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* The Route rendered by this {@code AbstractApp}.
|
2017-01-16 00:28:02 +00:00
|
|
|
*
|
|
|
|
* @type {Route}
|
|
|
|
*/
|
core: refactor routing
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
2018-06-29 07:58:31 +00:00
|
|
|
route: {},
|
2017-01-26 21:29:28 +00:00
|
|
|
|
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* The redux store used by this {@code AbstractApp}.
|
2017-01-26 21:29:28 +00:00
|
|
|
*
|
|
|
|
* @type {Store}
|
|
|
|
*/
|
2017-12-14 17:02:32 +00:00
|
|
|
store: undefined
|
2017-01-16 00:28:02 +00:00
|
|
|
};
|
2017-12-14 17:02:32 +00:00
|
|
|
|
|
|
|
/**
|
2018-02-05 21:26:01 +00:00
|
|
|
* Make the mobile {@code AbstractApp} wait until the
|
|
|
|
* {@code AsyncStorage} implementation of {@code Storage} initializes
|
|
|
|
* fully.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @see {@link #_initStorage}
|
|
|
|
* @type {Promise}
|
2017-12-14 17:02:32 +00:00
|
|
|
*/
|
2018-02-05 21:26:01 +00:00
|
|
|
this._init
|
|
|
|
= this._initStorage()
|
|
|
|
.catch(() => { /* AbstractApp should always initialize! */ })
|
|
|
|
.then(() =>
|
|
|
|
this.setState({
|
2018-07-10 14:42:22 +00:00
|
|
|
store: this._createStore()
|
2018-02-05 21:26:01 +00:00
|
|
|
}));
|
2017-01-16 00:28:02 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
2018-07-10 09:11:45 +00:00
|
|
|
* Initializes the app.
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
componentWillMount() {
|
2018-02-05 21:26:01 +00:00
|
|
|
this._init.then(() => {
|
2018-07-10 14:42:22 +00:00
|
|
|
const { dispatch } = this.state.store;
|
2017-12-14 17:02:32 +00:00
|
|
|
|
|
|
|
dispatch(appWillMount(this));
|
|
|
|
|
2018-05-22 14:22:16 +00:00
|
|
|
// We set the initialized state here and not in the constructor to
|
2018-07-10 14:42:22 +00:00
|
|
|
// make sure that {@code componentWillMount} gets invoked before the
|
|
|
|
// app tries to render the actual app content.
|
2017-12-14 17:02:32 +00:00
|
|
|
this.setState({
|
|
|
|
appAsyncInitialized: true
|
|
|
|
});
|
|
|
|
|
2018-07-10 14:42:22 +00:00
|
|
|
// If a URL was explicitly specified to this React Component, then
|
|
|
|
// open it; otherwise, use a default.
|
2017-12-14 17:02:32 +00:00
|
|
|
this._openURL(toURLString(this.props.url) || this._getDefaultURL());
|
|
|
|
});
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-26 21:29:28 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Notifies this mounted React {@code Component} that it will receive new
|
|
|
|
* props. Makes sure that this {@code AbstractApp} has a redux store to use.
|
2017-01-26 21:29:28 +00:00
|
|
|
*
|
|
|
|
* @inheritdoc
|
2017-07-26 19:40:34 +00:00
|
|
|
* @param {Object} nextProps - The read-only React {@code Component} props
|
|
|
|
* that this instance will receive.
|
2017-01-26 21:29:28 +00:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
componentWillReceiveProps(nextProps) {
|
2018-01-18 21:28:25 +00:00
|
|
|
const { props } = this;
|
2018-01-08 11:00:31 +00:00
|
|
|
|
2018-02-05 21:26:01 +00:00
|
|
|
this._init.then(() => {
|
2017-12-14 17:02:32 +00:00
|
|
|
// Deal with URL changes.
|
|
|
|
let { url } = nextProps;
|
2017-07-06 18:27:00 +00:00
|
|
|
|
2017-12-14 17:02:32 +00:00
|
|
|
url = toURLString(url);
|
2018-01-18 21:28:25 +00:00
|
|
|
if (toURLString(props.url) !== url
|
2017-08-15 22:21:58 +00:00
|
|
|
|
2017-12-14 17:02:32 +00:00
|
|
|
// XXX Refer to the implementation of loadURLObject: in
|
|
|
|
// ios/sdk/src/JitsiMeetView.m for further information.
|
2018-01-18 21:28:25 +00:00
|
|
|
|| props.timestamp !== nextProps.timestamp) {
|
2017-12-14 17:02:32 +00:00
|
|
|
this._openURL(url || this._getDefaultURL());
|
|
|
|
}
|
|
|
|
});
|
2017-01-26 21:29:28 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
2018-07-10 09:11:45 +00:00
|
|
|
* De-initializes the app.
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
*/
|
|
|
|
componentWillUnmount() {
|
2018-07-10 14:42:22 +00:00
|
|
|
this.state.store.dispatch(appWillUnmount(this));
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
|
2017-03-02 03:33:49 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Gets a {@code Location} object from the window with information about the
|
|
|
|
* current location of the document. Explicitly defined to allow extenders
|
|
|
|
* to override because React Native does not usually have a location
|
|
|
|
* property on its window unless debugging remotely in which case the
|
|
|
|
* browser that is the remote debugger will provide a location property on
|
|
|
|
* the window.
|
2017-03-02 03:33:49 +00:00
|
|
|
*
|
|
|
|
* @public
|
2017-07-26 19:40:34 +00:00
|
|
|
* @returns {Location} A {@code Location} object with information about the
|
|
|
|
* current location of the document.
|
2017-03-02 03:33:49 +00:00
|
|
|
*/
|
|
|
|
getWindowLocation() {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2017-12-14 17:02:32 +00:00
|
|
|
/**
|
2018-02-05 21:26:01 +00:00
|
|
|
* Delays this {@code AbstractApp}'s startup until the {@code Storage}
|
|
|
|
* implementation of {@code localStorage} initializes. While the
|
|
|
|
* initialization is instantaneous on Web (with Web Storage API), it is
|
|
|
|
* asynchronous on mobile/react-native.
|
2017-12-14 17:02:32 +00:00
|
|
|
*
|
|
|
|
* @private
|
2018-02-05 21:26:01 +00:00
|
|
|
* @returns {Promise}
|
2017-12-14 17:02:32 +00:00
|
|
|
*/
|
|
|
|
_initStorage() {
|
2018-02-05 21:26:01 +00:00
|
|
|
const localStorageInitializing = window.localStorage._initializing;
|
2018-01-16 15:21:20 +00:00
|
|
|
|
2018-02-05 21:26:01 +00:00
|
|
|
return (
|
|
|
|
typeof localStorageInitializing === 'undefined'
|
|
|
|
? Promise.resolve()
|
|
|
|
: localStorageInitializing);
|
2017-12-14 17:02:32 +00:00
|
|
|
}
|
|
|
|
|
2017-01-16 00:28:02 +00:00
|
|
|
/**
|
|
|
|
* Implements React's {@link Component#render()}.
|
|
|
|
*
|
|
|
|
* @inheritdoc
|
|
|
|
* @returns {ReactElement}
|
|
|
|
*/
|
|
|
|
render() {
|
2018-07-10 14:42:22 +00:00
|
|
|
const { appAsyncInitialized, route, store } = this.state;
|
|
|
|
const { component } = route;
|
2017-01-16 00:28:02 +00:00
|
|
|
|
2017-12-14 17:02:32 +00:00
|
|
|
if (appAsyncInitialized && component) {
|
2017-01-16 00:28:02 +00:00
|
|
|
return (
|
2017-03-01 02:55:12 +00:00
|
|
|
<I18nextProvider i18n = { i18next }>
|
2018-07-10 14:42:22 +00:00
|
|
|
<Provider store = { store }>
|
2017-11-23 17:03:33 +00:00
|
|
|
<Fragment>
|
|
|
|
{ this._createElement(component) }
|
2018-02-26 19:37:12 +00:00
|
|
|
<SoundCollection />
|
2017-11-23 17:03:33 +00:00
|
|
|
<OverlayContainer />
|
|
|
|
</Fragment>
|
2017-02-22 19:49:39 +00:00
|
|
|
</Provider>
|
|
|
|
</I18nextProvider>
|
2017-01-16 00:28:02 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Creates a {@link ReactElement} from the specified component, the
|
|
|
|
* specified props and the props of this {@code AbstractApp} which are
|
|
|
|
* suitable for propagation to the children of this {@code Component}.
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
2017-07-26 19:40:34 +00:00
|
|
|
* @param {Component} component - The component from which the
|
|
|
|
* {@code ReactElement} is to be created.
|
|
|
|
* @param {Object} props - The read-only React {@code Component} props with
|
|
|
|
* which the {@code ReactElement} is to be initialized.
|
2016-10-05 14:36:59 +00:00
|
|
|
* @returns {ReactElement}
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
_createElement(component, props) {
|
2017-06-09 19:09:23 +00:00
|
|
|
/* eslint-disable no-unused-vars */
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
const {
|
2017-06-09 19:09:23 +00:00
|
|
|
// The following props were introduced to be consumed entirely by
|
|
|
|
// AbstractApp:
|
|
|
|
defaultURL,
|
2018-07-10 14:42:22 +00:00
|
|
|
timestamp,
|
2016-10-05 14:36:59 +00:00
|
|
|
url,
|
2017-06-09 19:09:23 +00:00
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
// The remaining props, if any, are considered suitable for
|
|
|
|
// propagation to the children of this Component.
|
|
|
|
...thisProps
|
|
|
|
} = this.props;
|
|
|
|
|
2017-06-09 19:09:23 +00:00
|
|
|
/* eslint-enable no-unused-vars */
|
|
|
|
|
|
|
|
return React.createElement(component, {
|
|
|
|
...thisProps,
|
|
|
|
...props
|
|
|
|
});
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
|
2017-01-26 21:29:28 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Initializes a new redux store instance suitable for use by this
|
|
|
|
* {@code AbstractApp}.
|
2017-01-26 21:29:28 +00:00
|
|
|
*
|
|
|
|
* @private
|
2018-07-10 14:42:22 +00:00
|
|
|
* @returns {Store} - A new redux store instance suitable for use by this
|
|
|
|
* {@code AbstractApp}.
|
2017-01-26 21:29:28 +00:00
|
|
|
*/
|
|
|
|
_createStore() {
|
|
|
|
// Create combined reducer from all reducers in ReducerRegistry.
|
|
|
|
const reducer = ReducerRegistry.combineReducers();
|
|
|
|
|
|
|
|
// Apply all registered middleware from the MiddlewareRegistry and
|
|
|
|
// additional 3rd party middleware:
|
|
|
|
// - Thunk - allows us to dispatch async actions easily. For more info
|
|
|
|
// @see https://github.com/gaearon/redux-thunk.
|
|
|
|
let middleware = MiddlewareRegistry.applyMiddleware(Thunk);
|
|
|
|
|
|
|
|
// Try to enable Redux DevTools Chrome extension in order to make it
|
|
|
|
// available for the purposes of facilitating development.
|
|
|
|
let devToolsExtension;
|
|
|
|
|
|
|
|
if (typeof window === 'object'
|
|
|
|
&& (devToolsExtension = window.devToolsExtension)) {
|
|
|
|
middleware = compose(middleware, devToolsExtension());
|
|
|
|
}
|
|
|
|
|
2018-07-10 14:42:22 +00:00
|
|
|
const store
|
|
|
|
= createStore(
|
2018-01-29 22:20:38 +00:00
|
|
|
reducer,
|
2018-02-02 19:35:49 +00:00
|
|
|
PersistenceRegistry.getPersistedState(),
|
2018-07-10 14:42:22 +00:00
|
|
|
middleware);
|
|
|
|
|
|
|
|
// StateListenerRegistry
|
|
|
|
StateListenerRegistry.subscribe(store);
|
|
|
|
|
|
|
|
// This is temporary workaround to be able to dispatch actions from
|
|
|
|
// non-reactified parts of the code (conference.js for example).
|
|
|
|
// Don't use in the react code!!!
|
|
|
|
// FIXME: remove when the reactification is finished!
|
|
|
|
if (typeof APP !== 'undefined') {
|
|
|
|
APP.store = store;
|
|
|
|
}
|
|
|
|
|
|
|
|
return store;
|
2017-01-26 21:29:28 +00:00
|
|
|
}
|
|
|
|
|
2017-01-15 19:05:17 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Gets the default URL to be opened when this {@code App} mounts.
|
2017-01-15 19:05:17 +00:00
|
|
|
*
|
2017-02-18 16:02:31 +00:00
|
|
|
* @protected
|
2017-07-26 19:40:34 +00:00
|
|
|
* @returns {string} The default URL to be opened when this {@code App}
|
|
|
|
* mounts.
|
2017-01-15 19:05:17 +00:00
|
|
|
*/
|
|
|
|
_getDefaultURL() {
|
2018-07-11 08:57:07 +00:00
|
|
|
return getDefaultURL(this.state.store);
|
2017-01-15 19:05:17 +00:00
|
|
|
}
|
|
|
|
|
2017-01-16 00:28:02 +00:00
|
|
|
/**
|
|
|
|
* Navigates to a specific Route.
|
|
|
|
*
|
|
|
|
* @param {Route} route - The Route to which to navigate.
|
2017-08-01 00:34:19 +00:00
|
|
|
* @returns {Promise}
|
2017-01-16 00:28:02 +00:00
|
|
|
*/
|
|
|
|
_navigate(route) {
|
core: refactor routing
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
2018-06-29 07:58:31 +00:00
|
|
|
if (_.isEqual(route, this.state.route)) {
|
2017-08-01 00:34:19 +00:00
|
|
|
return Promise.resolve();
|
2017-01-19 15:47:22 +00:00
|
|
|
}
|
2017-01-25 22:11:44 +00:00
|
|
|
|
core: refactor routing
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
2018-06-29 07:58:31 +00:00
|
|
|
if (route.href) {
|
|
|
|
// This navigation requires loading a new URL in the browser.
|
|
|
|
window.location.href = route.href;
|
2017-01-25 22:11:44 +00:00
|
|
|
|
core: refactor routing
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
2018-06-29 07:58:31 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
2017-01-25 22:11:44 +00:00
|
|
|
|
2017-08-01 00:34:19 +00:00
|
|
|
// 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
|
|
|
|
// performed before setState completes, the app may not navigate to the
|
|
|
|
// expected route. In order to mitigate the problem, _navigate was
|
|
|
|
// changed to return a Promise.
|
2018-07-12 03:57:44 +00:00
|
|
|
return new Promise(resolve => this.setState({ route }, resolve));
|
2017-01-16 00:28:02 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
2017-07-26 19:40:34 +00:00
|
|
|
* Navigates this {@code AbstractApp} to (i.e. opens) a specific URL.
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
2018-02-26 19:37:12 +00:00
|
|
|
* @param {Object|string} url - The URL to navigate this {@code AbstractApp}
|
2017-07-26 19:40:34 +00:00
|
|
|
* to (i.e. the URL to open).
|
2016-10-05 14:36:59 +00:00
|
|
|
* @protected
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
_openURL(url) {
|
2018-07-10 14:42:22 +00:00
|
|
|
this.state.store.dispatch(appNavigate(toURLString(url)));
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
|
|
|
}
|