|
|
@@ -48,11 +48,6 @@ export class AbstractApp extends Component {
|
|
48
|
48
|
*/
|
|
49
|
49
|
defaultURL: PropTypes.string,
|
|
50
|
50
|
|
|
51
|
|
- /**
|
|
52
|
|
- * (Optional) redux store for this app.
|
|
53
|
|
- */
|
|
54
|
|
- store: PropTypes.object,
|
|
55
|
|
-
|
|
56
|
51
|
// XXX Refer to the implementation of loadURLObject: in
|
|
57
|
52
|
// ios/sdk/src/JitsiMeetView.m for further information.
|
|
58
|
53
|
timestamp: PropTypes.any,
|
|
|
@@ -78,8 +73,8 @@ export class AbstractApp extends Component {
|
|
78
|
73
|
this.state = {
|
|
79
|
74
|
|
|
80
|
75
|
/**
|
|
81
|
|
- * The state of the »possible« async initialization of
|
|
82
|
|
- * the {@code AbstractApp}.
|
|
|
76
|
+ * The state of the »possible« async initialization of the
|
|
|
77
|
+ * {@code AbstractApp}.
|
|
83
|
78
|
*/
|
|
84
|
79
|
appAsyncInitialized: false,
|
|
85
|
80
|
|
|
|
@@ -112,7 +107,7 @@ export class AbstractApp extends Component {
|
|
112
|
107
|
.catch(() => { /* AbstractApp should always initialize! */ })
|
|
113
|
108
|
.then(() =>
|
|
114
|
109
|
this.setState({
|
|
115
|
|
- store: this._maybeCreateStore(props)
|
|
|
110
|
+ store: this._createStore()
|
|
116
|
111
|
}));
|
|
117
|
112
|
}
|
|
118
|
113
|
|
|
|
@@ -123,19 +118,19 @@ export class AbstractApp extends Component {
|
|
123
|
118
|
*/
|
|
124
|
119
|
componentWillMount() {
|
|
125
|
120
|
this._init.then(() => {
|
|
126
|
|
- const { dispatch } = this._getStore();
|
|
|
121
|
+ const { dispatch } = this.state.store;
|
|
127
|
122
|
|
|
128
|
123
|
dispatch(appWillMount(this));
|
|
129
|
124
|
|
|
130
|
125
|
// We set the initialized state here and not in the constructor to
|
|
131
|
|
- // make sure that {@code componentWillMount} gets invoked before
|
|
132
|
|
- // the app tries to render the actual app content.
|
|
|
126
|
+ // make sure that {@code componentWillMount} gets invoked before the
|
|
|
127
|
+ // app tries to render the actual app content.
|
|
133
|
128
|
this.setState({
|
|
134
|
129
|
appAsyncInitialized: true
|
|
135
|
130
|
});
|
|
136
|
131
|
|
|
137
|
|
- // If a URL was explicitly specified to this React Component,
|
|
138
|
|
- // then open it; otherwise, use a default.
|
|
|
132
|
+ // If a URL was explicitly specified to this React Component, then
|
|
|
133
|
+ // open it; otherwise, use a default.
|
|
139
|
134
|
this._openURL(toURLString(this.props.url) || this._getDefaultURL());
|
|
140
|
135
|
});
|
|
141
|
136
|
}
|
|
|
@@ -153,21 +148,6 @@ export class AbstractApp extends Component {
|
|
153
|
148
|
const { props } = this;
|
|
154
|
149
|
|
|
155
|
150
|
this._init.then(() => {
|
|
156
|
|
- // The consumer of this AbstractApp did not provide a redux store.
|
|
157
|
|
- if (typeof nextProps.store === 'undefined'
|
|
158
|
|
-
|
|
159
|
|
- // The consumer of this AbstractApp did provide a redux
|
|
160
|
|
- // store before. Which means that the consumer changed
|
|
161
|
|
- // their mind. In such a case this instance should create
|
|
162
|
|
- // its own internal redux store. If the consumer did not
|
|
163
|
|
- // provide a redux store before, then this instance is
|
|
164
|
|
- // using its own internal redux store already.
|
|
165
|
|
- && typeof props.store !== 'undefined') {
|
|
166
|
|
- this.setState({
|
|
167
|
|
- store: this._maybeCreateStore(nextProps)
|
|
168
|
|
- });
|
|
169
|
|
- }
|
|
170
|
|
-
|
|
171
|
151
|
// Deal with URL changes.
|
|
172
|
152
|
let { url } = nextProps;
|
|
173
|
153
|
|
|
|
@@ -188,9 +168,7 @@ export class AbstractApp extends Component {
|
|
188
|
168
|
* @inheritdoc
|
|
189
|
169
|
*/
|
|
190
|
170
|
componentWillUnmount() {
|
|
191
|
|
- const { dispatch } = this._getStore();
|
|
192
|
|
-
|
|
193
|
|
- dispatch(appWillUnmount(this));
|
|
|
171
|
+ this.state.store.dispatch(appWillUnmount(this));
|
|
194
|
172
|
}
|
|
195
|
173
|
|
|
196
|
174
|
/**
|
|
|
@@ -234,12 +212,13 @@ export class AbstractApp extends Component {
|
|
234
|
212
|
* @returns {ReactElement}
|
|
235
|
213
|
*/
|
|
236
|
214
|
render() {
|
|
237
|
|
- const { appAsyncInitialized, route: { component } } = this.state;
|
|
|
215
|
+ const { appAsyncInitialized, route, store } = this.state;
|
|
|
216
|
+ const { component } = route;
|
|
238
|
217
|
|
|
239
|
218
|
if (appAsyncInitialized && component) {
|
|
240
|
219
|
return (
|
|
241
|
220
|
<I18nextProvider i18n = { i18next }>
|
|
242
|
|
- <Provider store = { this._getStore() }>
|
|
|
221
|
+ <Provider store = { store }>
|
|
243
|
222
|
<Fragment>
|
|
244
|
223
|
{ this._createElement(component) }
|
|
245
|
224
|
<SoundCollection />
|
|
|
@@ -269,15 +248,10 @@ export class AbstractApp extends Component {
|
|
269
|
248
|
/* eslint-disable no-unused-vars */
|
|
270
|
249
|
|
|
271
|
250
|
const {
|
|
272
|
|
- // Don't propagate the dispatch and store props because they usually
|
|
273
|
|
- // come from react-redux and programmers don't really expect them to
|
|
274
|
|
- // be inherited but rather explicitly connected.
|
|
275
|
|
- dispatch, // eslint-disable-line react/prop-types
|
|
276
|
|
- store,
|
|
277
|
|
-
|
|
278
|
251
|
// The following props were introduced to be consumed entirely by
|
|
279
|
252
|
// AbstractApp:
|
|
280
|
253
|
defaultURL,
|
|
|
254
|
+ timestamp,
|
|
281
|
255
|
url,
|
|
282
|
256
|
|
|
283
|
257
|
// The remaining props, if any, are considered suitable for
|
|
|
@@ -298,8 +272,8 @@ export class AbstractApp extends Component {
|
|
298
|
272
|
* {@code AbstractApp}.
|
|
299
|
273
|
*
|
|
300
|
274
|
* @private
|
|
301
|
|
- * @returns {Store} - A new redux store instance suitable for use by
|
|
302
|
|
- * this {@code AbstractApp}.
|
|
|
275
|
+ * @returns {Store} - A new redux store instance suitable for use by this
|
|
|
276
|
+ * {@code AbstractApp}.
|
|
303
|
277
|
*/
|
|
304
|
278
|
_createStore() {
|
|
305
|
279
|
// Create combined reducer from all reducers in ReducerRegistry.
|
|
|
@@ -320,11 +294,24 @@ export class AbstractApp extends Component {
|
|
320
|
294
|
middleware = compose(middleware, devToolsExtension());
|
|
321
|
295
|
}
|
|
322
|
296
|
|
|
323
|
|
- return (
|
|
324
|
|
- createStore(
|
|
|
297
|
+ const store
|
|
|
298
|
+ = createStore(
|
|
325
|
299
|
reducer,
|
|
326
|
300
|
PersistenceRegistry.getPersistedState(),
|
|
327
|
|
- middleware));
|
|
|
301
|
+ middleware);
|
|
|
302
|
+
|
|
|
303
|
+ // StateListenerRegistry
|
|
|
304
|
+ StateListenerRegistry.subscribe(store);
|
|
|
305
|
+
|
|
|
306
|
+ // This is temporary workaround to be able to dispatch actions from
|
|
|
307
|
+ // non-reactified parts of the code (conference.js for example).
|
|
|
308
|
+ // Don't use in the react code!!!
|
|
|
309
|
+ // FIXME: remove when the reactification is finished!
|
|
|
310
|
+ if (typeof APP !== 'undefined') {
|
|
|
311
|
+ APP.store = store;
|
|
|
312
|
+ }
|
|
|
313
|
+
|
|
|
314
|
+ return store;
|
|
328
|
315
|
}
|
|
329
|
316
|
|
|
330
|
317
|
/**
|
|
|
@@ -350,62 +337,11 @@ export class AbstractApp extends Component {
|
|
350
|
337
|
|
|
351
|
338
|
return (
|
|
352
|
339
|
this.props.defaultURL
|
|
353
|
|
- || this._getStore().getState()['features/base/settings']
|
|
|
340
|
+ || this.state.store.getState()['features/base/settings']
|
|
354
|
341
|
.serverURL
|
|
355
|
342
|
|| DEFAULT_URL);
|
|
356
|
343
|
}
|
|
357
|
344
|
|
|
358
|
|
- /**
|
|
359
|
|
- * Gets the redux store used by this {@code AbstractApp}.
|
|
360
|
|
- *
|
|
361
|
|
- * @protected
|
|
362
|
|
- * @returns {Store} - The redux store used by this {@code AbstractApp}.
|
|
363
|
|
- */
|
|
364
|
|
- _getStore() {
|
|
365
|
|
- let store = this.state.store;
|
|
366
|
|
-
|
|
367
|
|
- if (typeof store === 'undefined') {
|
|
368
|
|
- store = this.props.store;
|
|
369
|
|
- }
|
|
370
|
|
-
|
|
371
|
|
- return store;
|
|
372
|
|
- }
|
|
373
|
|
-
|
|
374
|
|
- /**
|
|
375
|
|
- * Creates a redux store to be used by this {@code AbstractApp} if such as a
|
|
376
|
|
- * store is not defined by the consumer of this {@code AbstractApp} through
|
|
377
|
|
- * its read-only React {@code Component} props.
|
|
378
|
|
- *
|
|
379
|
|
- * @param {Object} props - The read-only React {@code Component} props that
|
|
380
|
|
- * will eventually be received by this {@code AbstractApp}.
|
|
381
|
|
- * @private
|
|
382
|
|
- * @returns {Store} - The redux store to be used by this
|
|
383
|
|
- * {@code AbstractApp}.
|
|
384
|
|
- */
|
|
385
|
|
- _maybeCreateStore({ store }) {
|
|
386
|
|
- // The application Jitsi Meet is architected with redux. However, I do
|
|
387
|
|
- // not want consumers of the App React Component to be forced into
|
|
388
|
|
- // dealing with redux. If the consumer did not provide an external redux
|
|
389
|
|
- // store, utilize an internal redux store.
|
|
390
|
|
- if (typeof store === 'undefined') {
|
|
391
|
|
- // eslint-disable-next-line no-param-reassign
|
|
392
|
|
- store = this._createStore();
|
|
393
|
|
-
|
|
394
|
|
- // This is temporary workaround to be able to dispatch actions from
|
|
395
|
|
- // non-reactified parts of the code (conference.js for example).
|
|
396
|
|
- // Don't use in the react code!!!
|
|
397
|
|
- // FIXME: remove when the reactification is finished!
|
|
398
|
|
- if (typeof APP !== 'undefined') {
|
|
399
|
|
- APP.store = store;
|
|
400
|
|
- }
|
|
401
|
|
- }
|
|
402
|
|
-
|
|
403
|
|
- // StateListenerRegistry
|
|
404
|
|
- store && StateListenerRegistry.subscribe(store);
|
|
405
|
|
-
|
|
406
|
|
- return store;
|
|
407
|
|
- }
|
|
408
|
|
-
|
|
409
|
345
|
/**
|
|
410
|
346
|
* Navigates to a specific Route.
|
|
411
|
347
|
*
|
|
|
@@ -441,6 +377,6 @@ export class AbstractApp extends Component {
|
|
441
|
377
|
* @returns {void}
|
|
442
|
378
|
*/
|
|
443
|
379
|
_openURL(url) {
|
|
444
|
|
- this._getStore().dispatch(appNavigate(toURLString(url)));
|
|
|
380
|
+ this.state.store.dispatch(appNavigate(toURLString(url)));
|
|
445
|
381
|
}
|
|
446
|
382
|
}
|