Browse Source

Merge pull request #2946 from jitsi/fix-app-props-typeerror

[Android] Fix possible TypeError in multi-JitsiMeetView SDK consumers
j8
Zoltan Bettenbuk 7 years ago
parent
commit
b797b0b201
No account linked to committer's email address

+ 28
- 0
react/features/app/functions.any.js View File

@@ -0,0 +1,28 @@
1
+// @flow
2
+
3
+import { toState } from '../base/redux';
4
+
5
+/**
6
+ * Gets the value of a specific React {@code Component} prop of the currently
7
+ * mounted {@link App}.
8
+ *
9
+ * @param {Function|Object} stateful - The redux store or {@code getState}
10
+ * function.
11
+ * @param {string} propName - The name of the React {@code Component} prop of
12
+ * the currently mounted {@code App} to get.
13
+ * @returns {*} The value of the specified React {@code Compoennt} prop of the
14
+ * currently mounted {@code App}.
15
+ */
16
+export function getAppProp(stateful: Function | Object, propName: string) {
17
+    const state = toState(stateful)['features/app'];
18
+
19
+    if (state) {
20
+        const { app } = state;
21
+
22
+        if (app) {
23
+            return app.props[propName];
24
+        }
25
+    }
26
+
27
+    return undefined;
28
+}

+ 1
- 0
react/features/app/functions.native.js View File

@@ -2,6 +2,7 @@
2 2
 
3 3
 import { NativeModules } from 'react-native';
4 4
 
5
+export * from './functions.any';
5 6
 export * from './getRouteToRender';
6 7
 
7 8
 /**

+ 3
- 1
react/features/app/functions.web.js View File

@@ -1,4 +1,4 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 import { toState } from '../base/redux';
4 4
 import { getDeepLinkingPage } from '../deep-linking';
@@ -49,6 +49,8 @@ const _INTERCEPT_COMPONENT_RULES = [
49 49
     }
50 50
 ];
51 51
 
52
+export * from './functions.any';
53
+
52 54
 /**
53 55
  * Determines which route is to be rendered in order to depict a specific redux
54 56
  * store.

+ 3
- 5
react/features/invite/functions.js View File

@@ -1,5 +1,6 @@
1 1
 // @flow
2 2
 
3
+import { getAppProp } from '../app';
3 4
 import { getLocalParticipant, PARTICIPANT_ROLE } from '../base/participants';
4 5
 import { doGetJSON } from '../base/util';
5 6
 
@@ -282,8 +283,7 @@ export function isAddPeopleEnabled(state: Object): boolean {
282 283
         // XXX The mobile/react-native app is capable of disabling the
283 284
         // adding/inviting of people in the current conference. Anyway, the
284 285
         // Web/React app does not have that capability so default appropriately.
285
-        const { app } = state['features/app'];
286
-        const addPeopleEnabled = app && app.props.addPeopleEnabled;
286
+        const addPeopleEnabled = getAppProp(state, 'addPeopleEnabled');
287 287
 
288 288
         return (
289 289
             (typeof addPeopleEnabled === 'undefined')
@@ -313,9 +313,7 @@ export function isDialOutEnabled(state: Object): boolean {
313 313
         // XXX The mobile/react-native app is capable of disabling of dial-out.
314 314
         // Anyway, the Web/React app does not have that capability so default
315 315
         // appropriately.
316
-        const { app } = state['features/app'];
317
-
318
-        dialOutEnabled = app && app.props.dialoOutEnabled;
316
+        dialOutEnabled = getAppProp(state, 'dialOutEnabled');
319 317
 
320 318
         return (
321 319
             (typeof dialOutEnabled === 'undefined') || Boolean(dialOutEnabled));

+ 6
- 13
react/features/invite/middleware.native.js View File

@@ -4,7 +4,7 @@ import i18next from 'i18next';
4 4
 import { NativeEventEmitter, NativeModules } from 'react-native';
5 5
 
6 6
 import { MiddlewareRegistry } from '../base/redux';
7
-import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
7
+import { APP_WILL_MOUNT, APP_WILL_UNMOUNT, getAppProp } from '../app';
8 8
 
9 9
 import { invite } from './actions';
10 10
 import {
@@ -107,21 +107,15 @@ function _appWillMount({ dispatch, getState }, next, action) {
107 107
  * @private
108 108
  * @returns {*} The value returned by {@code next(action)}.
109 109
  */
110
-function _beginAddPeople({ getState }, next, action) {
110
+function _beginAddPeople(store, next, action) {
111 111
     const result = next(action);
112 112
 
113 113
     // The JavaScript App needs to provide uniquely identifying information to
114 114
     // the native Invite module so that the latter may match the former to the
115 115
     // native JitsiMeetView which hosts it.
116
-    const { app } = getState()['features/app'];
116
+    const externalAPIScope = getAppProp(store, 'externalAPIScope');
117 117
 
118
-    if (app) {
119
-        const { externalAPIScope } = app.props;
120
-
121
-        if (externalAPIScope) {
122
-            Invite.beginAddPeople(externalAPIScope);
123
-        }
124
-    }
118
+    externalAPIScope && Invite.beginAddPeople(externalAPIScope);
125 119
 
126 120
     return result;
127 121
 }
@@ -139,8 +133,7 @@ function _onInvite({ addPeopleControllerScope, externalAPIScope, invitees }) {
139 133
     // If there are multiple JitsiMeetView instances alive, they will all get
140 134
     // the event, since there is a single bridge, so make sure we don't act if
141 135
     // the event is not for us.
142
-    if (getState()['features/app'].app.props.externalAPIScope
143
-            !== externalAPIScope) {
136
+    if (getAppProp(getState, 'externalAPIScope') !== externalAPIScope) {
144 137
         return;
145 138
     }
146 139
 
@@ -167,7 +160,7 @@ function _onPerformQuery(
167 160
     // If there are multiple JitsiMeetView instances alive, they will all get
168 161
     // the event, since there is a single bridge, so make sure we don't act if
169 162
     // the event is not for us.
170
-    if (state['features/app'].app.props.externalAPIScope !== externalAPIScope) {
163
+    if (getAppProp(state, 'externalAPIScope') !== externalAPIScope) {
171 164
         return;
172 165
     }
173 166
 

+ 6
- 13
react/features/mobile/external-api/middleware.js View File

@@ -1,7 +1,8 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 import { NativeModules } from 'react-native';
4 4
 
5
+import { getAppProp } from '../../app';
5 6
 import {
6 7
     CONFERENCE_FAILED,
7 8
     CONFERENCE_JOINED,
@@ -215,22 +216,14 @@ function _sendConferenceFailedOnConnectionError(store, action) {
215 216
  * @private
216 217
  * @returns {void}
217 218
  */
218
-function _sendEvent(
219
-        { getState }: { getState: Function },
220
-        name: string,
221
-        data: Object) {
219
+function _sendEvent(store: Object, name: string, data: Object) {
222 220
     // The JavaScript App needs to provide uniquely identifying information to
223 221
     // the native ExternalAPI module so that the latter may match the former to
224 222
     // the native JitsiMeetView which hosts it.
225
-    const { app } = getState()['features/app'];
223
+    const externalAPIScope = getAppProp(store, 'externalAPIScope');
226 224
 
227
-    if (app) {
228
-        const { externalAPIScope } = app.props;
229
-
230
-        if (externalAPIScope) {
231
-            NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
232
-        }
233
-    }
225
+    externalAPIScope
226
+        && NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
234 227
 }
235 228
 
236 229
 /**

+ 2
- 4
react/features/mobile/picture-in-picture/actions.js View File

@@ -2,6 +2,7 @@
2 2
 
3 3
 import { NativeModules } from 'react-native';
4 4
 
5
+import { getAppProp } from '../../app';
5 6
 import { Platform } from '../../base/react';
6 7
 
7 8
 import { ENTER_PICTURE_IN_PICTURE } from './actionTypes';
@@ -18,13 +19,10 @@ import { ENTER_PICTURE_IN_PICTURE } from './actionTypes';
18 19
  */
19 20
 export function enterPictureInPicture() {
20 21
     return (dispatch: Dispatch, getState: Function) => {
21
-        const state = getState();
22
-        const { app } = state['features/app'];
23
-
24 22
         // XXX At the time of this writing this action can only be dispatched by
25 23
         // the button which is on the conference view, which means that it's
26 24
         // fine to enter PiP mode.
27
-        if (app && app.props.pictureInPictureEnabled) {
25
+        if (getAppProp(getState, 'pictureInPictureEnabled')) {
28 26
             const { PictureInPicture } = NativeModules;
29 27
             const p
30 28
                 = Platform.OS === 'android'

+ 2
- 3
react/features/mobile/picture-in-picture/components/EnterPictureInPictureToolbarButton.js View File

@@ -3,6 +3,7 @@
3 3
 import React, { Component } from 'react';
4 4
 import { connect } from 'react-redux';
5 5
 
6
+import { getAppProp } from '../../../app';
6 7
 import { ToolbarButton } from '../../../toolbox';
7 8
 
8 9
 import { enterPictureInPicture } from '../actions';
@@ -93,8 +94,6 @@ function _mapDispatchToProps(dispatch) {
93 94
  * }}
94 95
  */
95 96
 function _mapStateToProps(state) {
96
-    const { app } = state['features/app'];
97
-
98 97
     return {
99 98
 
100 99
         /**
@@ -104,7 +103,7 @@ function _mapStateToProps(state) {
104 103
          * @type {boolean}
105 104
          */
106 105
         _pictureInPictureEnabled:
107
-            Boolean(app && app.props.pictureInPictureEnabled)
106
+            Boolean(getAppProp(state, 'pictureInPictureEnabled'))
108 107
     };
109 108
 }
110 109
 

+ 10
- 12
react/features/welcome/functions.js View File

@@ -1,5 +1,6 @@
1
-/* @flow */
1
+// @flow
2 2
 
3
+import { getAppProp } from '../app';
3 4
 import { toState } from '../base/redux';
4 5
 
5 6
 declare var APP: Object;
@@ -12,12 +13,12 @@ export * from './roomnameGenerator';
12 13
  * (e.g. programmatically via the Jitsi Meet SDK for Android and iOS). Not to be
13 14
  * confused with {@link isWelcomePageUserEnabled}.
14 15
  *
15
- * @param {Object|Function} stateOrGetState - The redux state or
16
- * {@link getState} function.
16
+ * @param {Function|Object} stateful - The redux state or {@link getState}
17
+ * function.
17 18
  * @returns {boolean} If the {@code WelcomePage} is enabled by the app, then
18 19
  * {@code true}; otherwise, {@code false}.
19 20
  */
20
-export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
21
+export function isWelcomePageAppEnabled(stateful: Function | Object) {
21 22
     let b;
22 23
 
23 24
     if (navigator.product === 'ReactNative') {
@@ -28,9 +29,7 @@ export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
28 29
         // - Enabling/disabling the Welcome page on Web historically
29 30
         // automatically redirects to a random room and that does not make sense
30 31
         // on mobile (right now).
31
-        const { app } = toState(stateOrGetState)['features/app'];
32
-
33
-        b = Boolean(app && app.props.welcomePageEnabled);
32
+        b = Boolean(getAppProp(stateful, 'welcomePageEnabled'));
34 33
     } else {
35 34
         b = true;
36 35
     }
@@ -43,15 +42,14 @@ export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
43 42
  * herself or through her deployment config(uration). Not to be confused with
44 43
  * {@link isWelcomePageAppEnabled}.
45 44
  *
46
- * @param {Object|Function} stateOrGetState - The redux state or
47
- * {@link getState} function.
45
+ * @param {Function|Object} stateful - The redux state or {@link getState}
46
+ * function.
48 47
  * @returns {boolean} If the {@code WelcomePage} is enabled by the user, then
49 48
  * {@code true}; otherwise, {@code false}.
50 49
  */
51
-export function isWelcomePageUserEnabled(stateOrGetState: Object | Function) {
50
+export function isWelcomePageUserEnabled(stateful: Function | Object) {
52 51
     return (
53 52
         typeof APP === 'undefined'
54 53
             ? true
55
-            : toState(stateOrGetState)['features/base/config']
56
-                .enableWelcomePage);
54
+            : toState(stateful)['features/base/config'].enableWelcomePage);
57 55
 }

Loading…
Cancel
Save