[RN] Add conference connecting overlay
This commit is contained in:
parent
84b917d708
commit
8bb56be317
|
@ -57,6 +57,9 @@
|
|||
},
|
||||
"title": "Chat"
|
||||
},
|
||||
"connectingOverlay": {
|
||||
"joiningRoom": "Connecting you to your meeting..."
|
||||
},
|
||||
"connection": {
|
||||
"ATTACHED": "Attached",
|
||||
"AUTHENTICATING": "Authenticating",
|
||||
|
|
|
@ -55,12 +55,12 @@ export function appNavigate(uri: ?string) {
|
|||
}
|
||||
|
||||
location.protocol || (location.protocol = 'https:');
|
||||
const { contextRoot, host, room } = location;
|
||||
const locationURL = new URL(location.toString());
|
||||
|
||||
dispatch(configWillLoad(locationURL));
|
||||
dispatch(configWillLoad(locationURL, room));
|
||||
|
||||
let protocol = location.protocol.toLowerCase();
|
||||
const { contextRoot, host, room } = location;
|
||||
|
||||
// The React Native app supports an app-specific scheme which is sure to not
|
||||
// be supported by fetch.
|
||||
|
|
|
@ -117,7 +117,7 @@ export default class BaseApp extends Component<*, State> {
|
|||
render() {
|
||||
const { route: { component }, store } = this.state;
|
||||
|
||||
if (store && component) {
|
||||
if (store) {
|
||||
return (
|
||||
<I18nextProvider i18n = { i18next }>
|
||||
<Provider store = { store }>
|
||||
|
@ -160,7 +160,7 @@ export default class BaseApp extends Component<*, State> {
|
|||
* @protected
|
||||
*/
|
||||
_createMainElement(component, props) {
|
||||
return React.createElement(component, props || {});
|
||||
return component ? React.createElement(component, props || {}) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,6 +29,10 @@ export default {
|
|||
'LargeVideo': {
|
||||
background: ColorPalette.black
|
||||
},
|
||||
'LoadConfigOverlay': {
|
||||
background: ColorPalette.black,
|
||||
text: ColorPalette.white
|
||||
},
|
||||
'Thumbnail': {
|
||||
activeParticipantHighlight: ColorPalette.blue,
|
||||
activeParticipantTint: ColorPalette.black,
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
*
|
||||
* {
|
||||
* type: CONFIG_WILL_LOAD,
|
||||
* locationURL: URL
|
||||
* locationURL: URL,
|
||||
* room: string
|
||||
* }
|
||||
*/
|
||||
export const CONFIG_WILL_LOAD = 'CONFIG_WILL_LOAD';
|
||||
|
|
|
@ -15,15 +15,18 @@ import { setConfigFromURLParams } from './functions';
|
|||
*
|
||||
* @param {URL} locationURL - The URL of the location which necessitated the
|
||||
* loading of a configuration.
|
||||
* @param {string} room - The name of the room (conference) for which we're loading the config for.
|
||||
* @returns {{
|
||||
* type: CONFIG_WILL_LOAD,
|
||||
* locationURL: URL
|
||||
* locationURL: URL,
|
||||
* room: string
|
||||
* }}
|
||||
*/
|
||||
export function configWillLoad(locationURL: URL) {
|
||||
export function configWillLoad(locationURL: URL, room: string) {
|
||||
return {
|
||||
type: CONFIG_WILL_LOAD,
|
||||
locationURL
|
||||
locationURL,
|
||||
room
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,11 @@ import { ColorPalette } from '../../../styles';
|
|||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The color of the spinner.
|
||||
*/
|
||||
color: ?string,
|
||||
|
||||
/**
|
||||
* Prop to set the size of the indicator. This is the same as the
|
||||
* prop of the native component.
|
||||
|
@ -27,6 +32,7 @@ export default class LoadingIndicator extends Component<Props> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { color = ColorPalette.white } = this.props;
|
||||
let { size = 'large' } = this.props;
|
||||
|
||||
if (size === 'medium') {
|
||||
|
@ -35,7 +41,7 @@ export default class LoadingIndicator extends Component<Props> {
|
|||
|
||||
const props = {
|
||||
animating: true,
|
||||
color: ColorPalette.white,
|
||||
color,
|
||||
...this.props,
|
||||
size
|
||||
};
|
||||
|
@ -43,7 +49,6 @@ export default class LoadingIndicator extends Component<Props> {
|
|||
return (
|
||||
<ActivityIndicator
|
||||
animating = { true }
|
||||
color = { ColorPalette.white }
|
||||
{ ...props }
|
||||
size = { size } />
|
||||
);
|
||||
|
|
|
@ -14,16 +14,6 @@
|
|||
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
|
||||
= 'MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED';
|
||||
|
||||
/**
|
||||
* The type of the Redux action which signals that a suspend was detected.
|
||||
*
|
||||
* {
|
||||
* type: SUSPEND_DETECTED
|
||||
* }
|
||||
* @public
|
||||
*/
|
||||
export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';
|
||||
|
||||
/**
|
||||
* Adjust the state of the fatal error which shows/hides the reload screen. See
|
||||
* action methods's description for more info about each of the fields.
|
||||
|
@ -35,3 +25,13 @@ export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';
|
|||
* @public
|
||||
*/
|
||||
export const SET_FATAL_ERROR = 'SET_FATAL_ERROR';
|
||||
|
||||
/**
|
||||
* The type of the Redux action which signals that a suspend was detected.
|
||||
*
|
||||
* {
|
||||
* type: SUSPEND_DETECTED
|
||||
* }
|
||||
* @public
|
||||
*/
|
||||
export const SUSPEND_DETECTED = 'SUSPEND_DETECTED';
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { SafeAreaView, Text } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { LoadingIndicator } from '../../../base/react';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
|
||||
import OverlayFrame from './OverlayFrame';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The color schemed style of the component.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* The Function to be invoked to translate i18n keys.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements an overlay to tell the user that there is an operation in progress in the background during connect
|
||||
* so then the app doesn't seem hung.
|
||||
*/
|
||||
class LoadConfigOverlay extends Component<Props> {
|
||||
/**
|
||||
* Determines whether this overlay needs to be rendered (according to a
|
||||
* specific redux state). Called by {@link OverlayContainer}.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @returns {boolean} - If this overlay needs to be rendered, {@code true};
|
||||
* {@code false}, otherwise.
|
||||
*/
|
||||
static needsRender(state: Object) {
|
||||
return Boolean(state['features/overlay'].loadConfigOverlayVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _styles } = this.props;
|
||||
|
||||
return (
|
||||
<OverlayFrame>
|
||||
<SafeAreaView
|
||||
style = { [
|
||||
styles.loadingOverlayWrapper,
|
||||
_styles.loadingOverlayWrapper
|
||||
] }>
|
||||
<LoadingIndicator
|
||||
color = { _styles.indicatorColor }
|
||||
size = 'large'
|
||||
style = { styles.connectIndicator } />
|
||||
<Text
|
||||
style = { [
|
||||
styles.loadingOverlayText,
|
||||
_styles.loadingOverlayText
|
||||
] }>
|
||||
{ this.props.t('connectingOverlay.joiningRoom') }
|
||||
</Text>
|
||||
</SafeAreaView>
|
||||
</OverlayFrame>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {{
|
||||
* _styles: StyleType
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
return {
|
||||
_styles: ColorSchemeRegistry.get(state, 'LoadConfigOverlay')
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(LoadConfigOverlay));
|
|
@ -3,7 +3,7 @@
|
|||
import React, { Component, type Node } from 'react';
|
||||
import { SafeAreaView, View } from 'react-native';
|
||||
|
||||
import { overlayFrame as styles } from './styles';
|
||||
import styles from './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@code OverlayFrame}.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @flow
|
||||
|
||||
export { default as LoadConfigOverlay } from './LoadConfigOverlay';
|
||||
export { default as OverlayFrame } from './OverlayFrame';
|
||||
export { default as PageReloadOverlay } from './PageReloadOverlay';
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { ColorPalette } from '../../../base/styles';
|
||||
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
|
||||
import { BoxModel, ColorPalette } from '../../../base/styles';
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code OverlayFrame}.
|
||||
* The React {@code Component} styles of the overlay feature.
|
||||
*/
|
||||
export const overlayFrame = createStyleSheet({
|
||||
export default {
|
||||
connectIndicator: {
|
||||
margin: BoxModel.margin
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for a backdrop overlay covering the screen the the overlay is
|
||||
* rendered.
|
||||
|
@ -17,7 +22,33 @@ export const overlayFrame = createStyleSheet({
|
|||
backgroundColor: ColorPalette.black
|
||||
},
|
||||
|
||||
loadingOverlayText: {
|
||||
color: ColorPalette.white
|
||||
},
|
||||
|
||||
loadingOverlayWrapper: {
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
safeContainer: {
|
||||
flex: 1
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Color schemed styles for all the component based on the abstract dialog.
|
||||
*/
|
||||
ColorSchemeRegistry.register('LoadConfigOverlay', {
|
||||
indicatorColor: schemeColor('text'),
|
||||
|
||||
loadingOverlayText: {
|
||||
color: schemeColor('text')
|
||||
},
|
||||
|
||||
loadingOverlayWrapper: {
|
||||
backgroundColor: schemeColor('background')
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,49 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
PageReloadFilmstripOnlyOverlay,
|
||||
PageReloadOverlay,
|
||||
SuspendedFilmstripOnlyOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsFilmstripOnlyOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
} from './components';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* Returns the list of available overlays that might be rendered.
|
||||
*
|
||||
* @private
|
||||
* @returns {Array<?React$ComponentType<*>>}
|
||||
*/
|
||||
function _getOverlays() {
|
||||
const filmstripOnly
|
||||
= typeof interfaceConfig === 'object' && interfaceConfig.filmStripOnly;
|
||||
let overlays;
|
||||
|
||||
if (filmstripOnly) {
|
||||
overlays = [
|
||||
PageReloadFilmstripOnlyOverlay,
|
||||
SuspendedFilmstripOnlyOverlay,
|
||||
UserMediaPermissionsFilmstripOnlyOverlay
|
||||
];
|
||||
} else {
|
||||
overlays = [
|
||||
PageReloadOverlay
|
||||
];
|
||||
}
|
||||
|
||||
// Mobile only has a PageReloadOverlay.
|
||||
if (navigator.product !== 'ReactNative') {
|
||||
overlays.push(...[
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
]);
|
||||
}
|
||||
|
||||
return overlays;
|
||||
}
|
||||
import { getOverlays } from './overlays';
|
||||
|
||||
/**
|
||||
* Returns the overlay to be currently rendered.
|
||||
|
@ -52,7 +9,7 @@ function _getOverlays() {
|
|||
* @returns {?React$ComponentType<*>}
|
||||
*/
|
||||
export function getOverlayToRender(state: Object) {
|
||||
for (const overlay of _getOverlays()) {
|
||||
for (const overlay of getOverlays()) {
|
||||
// react-i18n / react-redux wrap components and thus we cannot access
|
||||
// the wrapped component's static methods directly.
|
||||
const component = overlay.WrappedComponent || overlay;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
LoadConfigOverlay,
|
||||
PageReloadOverlay
|
||||
} from './components/native';
|
||||
|
||||
/**
|
||||
* Returns the list of available platform specific overlays.
|
||||
*
|
||||
* @returns {Array<React$Element>}
|
||||
*/
|
||||
export function getOverlays(): Array<React$Element<*>> {
|
||||
return [
|
||||
LoadConfigOverlay,
|
||||
PageReloadOverlay
|
||||
];
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
PageReloadFilmstripOnlyOverlay,
|
||||
PageReloadOverlay,
|
||||
SuspendedFilmstripOnlyOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsFilmstripOnlyOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
} from './components/web';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* Returns the list of available platform specific overlays.
|
||||
*
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export function getOverlays(): Array<Object> {
|
||||
const overlays = [
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
];
|
||||
|
||||
const filmstripOnly
|
||||
= typeof interfaceConfig === 'object' && interfaceConfig.filmStripOnly;
|
||||
|
||||
if (filmstripOnly) {
|
||||
overlays.push(
|
||||
PageReloadFilmstripOnlyOverlay,
|
||||
SuspendedFilmstripOnlyOverlay,
|
||||
UserMediaPermissionsFilmstripOnlyOverlay);
|
||||
} else {
|
||||
overlays.push(PageReloadOverlay);
|
||||
}
|
||||
|
||||
return overlays;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { CONFIG_WILL_LOAD, LOAD_CONFIG_ERROR, SET_CONFIG } from '../base/config';
|
||||
import { assign, ReducerRegistry, set } from '../base/redux';
|
||||
|
||||
import {
|
||||
|
@ -15,6 +16,13 @@ import {
|
|||
*/
|
||||
ReducerRegistry.register('features/overlay', (state = { }, action) => {
|
||||
switch (action.type) {
|
||||
case CONFIG_WILL_LOAD:
|
||||
return _setShowLoadConfigOverlay(state, Boolean(action.room));
|
||||
|
||||
case LOAD_CONFIG_ERROR:
|
||||
case SET_CONFIG:
|
||||
return _setShowLoadConfigOverlay(false);
|
||||
|
||||
case MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED:
|
||||
return _mediaPermissionPromptVisibilityChanged(state, action);
|
||||
|
||||
|
@ -48,15 +56,15 @@ function _mediaPermissionPromptVisibilityChanged(
|
|||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action SUSPEND_DETECTED of the feature overlay.
|
||||
* Sets the {@code LoadConfigOverlay} overlay visible or not.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature overlay.
|
||||
* @private
|
||||
* @param {boolean} show - Whether to show or not the overlay.
|
||||
* @returns {Object} The new state of the feature overlay after the reduction of
|
||||
* the specified action.
|
||||
*/
|
||||
function _suspendDetected(state) {
|
||||
return set(state, 'suspendDetected', true);
|
||||
function _setShowLoadConfigOverlay(state, show) {
|
||||
return set(state, 'loadConfigOverlayVisible', show);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,3 +80,15 @@ function _suspendDetected(state) {
|
|||
function _setFatalError(state, { fatalError }) {
|
||||
return set(state, 'fatalError', fatalError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action SUSPEND_DETECTED of the feature overlay.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature overlay.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature overlay after the reduction of
|
||||
* the specified action.
|
||||
*/
|
||||
function _suspendDetected(state) {
|
||||
return set(state, 'suspendDetected', true);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue