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

[Android] Fix possible TypeError in multi-JitsiMeetView SDK consumers
This commit is contained in:
Zoltan Bettenbuk 2018-05-10 12:40:11 +02:00 committed by GitHub
commit b797b0b201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 61 additions and 51 deletions

View File

@ -0,0 +1,28 @@
// @flow
import { toState } from '../base/redux';
/**
* Gets the value of a specific React {@code Component} prop of the currently
* mounted {@link App}.
*
* @param {Function|Object} stateful - The redux store or {@code getState}
* function.
* @param {string} propName - The name of the React {@code Component} prop of
* the currently mounted {@code App} to get.
* @returns {*} The value of the specified React {@code Compoennt} prop of the
* currently mounted {@code App}.
*/
export function getAppProp(stateful: Function | Object, propName: string) {
const state = toState(stateful)['features/app'];
if (state) {
const { app } = state;
if (app) {
return app.props[propName];
}
}
return undefined;
}

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import i18next from 'i18next';
import { NativeEventEmitter, NativeModules } from 'react-native';
import { MiddlewareRegistry } from '../base/redux';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT, getAppProp } from '../app';
import { invite } from './actions';
import {
@ -107,21 +107,15 @@ function _appWillMount({ dispatch, getState }, next, action) {
* @private
* @returns {*} The value returned by {@code next(action)}.
*/
function _beginAddPeople({ getState }, next, action) {
function _beginAddPeople(store, next, action) {
const result = next(action);
// The JavaScript App needs to provide uniquely identifying information to
// the native Invite module so that the latter may match the former to the
// native JitsiMeetView which hosts it.
const { app } = getState()['features/app'];
const externalAPIScope = getAppProp(store, 'externalAPIScope');
if (app) {
const { externalAPIScope } = app.props;
if (externalAPIScope) {
Invite.beginAddPeople(externalAPIScope);
}
}
externalAPIScope && Invite.beginAddPeople(externalAPIScope);
return result;
}
@ -139,8 +133,7 @@ function _onInvite({ addPeopleControllerScope, externalAPIScope, invitees }) {
// If there are multiple JitsiMeetView instances alive, they will all get
// the event, since there is a single bridge, so make sure we don't act if
// the event is not for us.
if (getState()['features/app'].app.props.externalAPIScope
!== externalAPIScope) {
if (getAppProp(getState, 'externalAPIScope') !== externalAPIScope) {
return;
}
@ -167,7 +160,7 @@ function _onPerformQuery(
// If there are multiple JitsiMeetView instances alive, they will all get
// the event, since there is a single bridge, so make sure we don't act if
// the event is not for us.
if (state['features/app'].app.props.externalAPIScope !== externalAPIScope) {
if (getAppProp(state, 'externalAPIScope') !== externalAPIScope) {
return;
}

View File

@ -1,7 +1,8 @@
/* @flow */
// @flow
import { NativeModules } from 'react-native';
import { getAppProp } from '../../app';
import {
CONFERENCE_FAILED,
CONFERENCE_JOINED,
@ -215,22 +216,14 @@ function _sendConferenceFailedOnConnectionError(store, action) {
* @private
* @returns {void}
*/
function _sendEvent(
{ getState }: { getState: Function },
name: string,
data: Object) {
function _sendEvent(store: Object, name: string, data: Object) {
// The JavaScript App needs to provide uniquely identifying information to
// the native ExternalAPI module so that the latter may match the former to
// the native JitsiMeetView which hosts it.
const { app } = getState()['features/app'];
const externalAPIScope = getAppProp(store, 'externalAPIScope');
if (app) {
const { externalAPIScope } = app.props;
if (externalAPIScope) {
NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
}
}
externalAPIScope
&& NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
}
/**

View File

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

View File

@ -3,6 +3,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getAppProp } from '../../../app';
import { ToolbarButton } from '../../../toolbox';
import { enterPictureInPicture } from '../actions';
@ -93,8 +94,6 @@ function _mapDispatchToProps(dispatch) {
* }}
*/
function _mapStateToProps(state) {
const { app } = state['features/app'];
return {
/**
@ -104,7 +103,7 @@ function _mapStateToProps(state) {
* @type {boolean}
*/
_pictureInPictureEnabled:
Boolean(app && app.props.pictureInPictureEnabled)
Boolean(getAppProp(state, 'pictureInPictureEnabled'))
};
}

View File

@ -1,5 +1,6 @@
/* @flow */
// @flow
import { getAppProp } from '../app';
import { toState } from '../base/redux';
declare var APP: Object;
@ -12,12 +13,12 @@ export * from './roomnameGenerator';
* (e.g. programmatically via the Jitsi Meet SDK for Android and iOS). Not to be
* confused with {@link isWelcomePageUserEnabled}.
*
* @param {Object|Function} stateOrGetState - The redux state or
* {@link getState} function.
* @param {Function|Object} stateful - The redux state or {@link getState}
* function.
* @returns {boolean} If the {@code WelcomePage} is enabled by the app, then
* {@code true}; otherwise, {@code false}.
*/
export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
export function isWelcomePageAppEnabled(stateful: Function | Object) {
let b;
if (navigator.product === 'ReactNative') {
@ -28,9 +29,7 @@ export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
// - Enabling/disabling the Welcome page on Web historically
// automatically redirects to a random room and that does not make sense
// on mobile (right now).
const { app } = toState(stateOrGetState)['features/app'];
b = Boolean(app && app.props.welcomePageEnabled);
b = Boolean(getAppProp(stateful, 'welcomePageEnabled'));
} else {
b = true;
}
@ -43,15 +42,14 @@ export function isWelcomePageAppEnabled(stateOrGetState: Object | Function) {
* herself or through her deployment config(uration). Not to be confused with
* {@link isWelcomePageAppEnabled}.
*
* @param {Object|Function} stateOrGetState - The redux state or
* {@link getState} function.
* @param {Function|Object} stateful - The redux state or {@link getState}
* function.
* @returns {boolean} If the {@code WelcomePage} is enabled by the user, then
* {@code true}; otherwise, {@code false}.
*/
export function isWelcomePageUserEnabled(stateOrGetState: Object | Function) {
export function isWelcomePageUserEnabled(stateful: Function | Object) {
return (
typeof APP === 'undefined'
? true
: toState(stateOrGetState)['features/base/config']
.enableWelcomePage);
: toState(stateful)['features/base/config'].enableWelcomePage);
}