[RN] Add reload overlay in case of connection / conference errors
This commit is contained in:
parent
ad497fed7c
commit
87a87eebb9
|
@ -405,7 +405,10 @@ function _setRoom(state, action) {
|
|||
*
|
||||
* @type {string}
|
||||
*/
|
||||
return set(state, 'room', room);
|
||||
return assign(state, {
|
||||
error: undefined,
|
||||
room
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
import { assign, ReducerRegistry } from '../redux';
|
||||
import { SET_ROOM } from '../conference';
|
||||
import { assign, set, ReducerRegistry } from '../redux';
|
||||
import { parseURIString } from '../util';
|
||||
|
||||
import {
|
||||
|
@ -32,6 +33,9 @@ ReducerRegistry.register(
|
|||
|
||||
case SET_LOCATION_URL:
|
||||
return _setLocationURL(state, action);
|
||||
|
||||
case SET_ROOM:
|
||||
return _setRoom(state);
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -194,3 +198,16 @@ function _setLocationURL(
|
|||
options: locationURL ? _constructOptions(locationURL) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action {@link SET_ROOM} of the feature
|
||||
* base/connection.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature base/connection.
|
||||
* @private
|
||||
* @returns {Object} The new state of the feature base/connection after the
|
||||
* reduction of the specified action.
|
||||
*/
|
||||
function _setRoom(state: Object) {
|
||||
return set(state, 'error', undefined);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { connect } from 'react-redux';
|
|||
import CalleeInfo from './CalleeInfo';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link Conference}.
|
||||
* The type of the React {@code Component} props of {@code CalleeInfoContainer}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { appNavigate } from '../app';
|
||||
import { toURLString } from '../base/util';
|
||||
import { reload, replace } from '../../../modules/util/helpers';
|
||||
|
||||
import {
|
||||
|
@ -40,11 +42,13 @@ export function _reloadNow() {
|
|||
|
||||
logger.info(`Reloading the conference using URL: ${locationURL}`);
|
||||
|
||||
// In an iframe reload with the reload() utility because the replace()
|
||||
// utility does not work on an iframe.
|
||||
if (window.self === window.top) {
|
||||
if (navigator.product === 'ReactNative') {
|
||||
dispatch(appNavigate(toURLString(locationURL)));
|
||||
} else if (window.self === window.top) {
|
||||
replace(locationURL);
|
||||
} else {
|
||||
// In an iframe reload with the reload() utility because the
|
||||
// replace() utility does not work on an iframe.
|
||||
reload();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -156,10 +156,13 @@ export default class AbstractPageReloadOverlay extends Component<*, *> {
|
|||
// because the log queue is not flushed before "fabric terminated" is
|
||||
// sent to the backed.
|
||||
// FIXME: We should dispatch action for this.
|
||||
APP.conference.logEvent(
|
||||
PAGE_RELOAD,
|
||||
/* value */ undefined,
|
||||
/* label */ this.props.reason);
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.conference.logEvent(
|
||||
PAGE_RELOAD,
|
||||
/* value */ undefined,
|
||||
/* label */ this.props.reason);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`The conference will be reloaded after ${
|
||||
this.state.timeoutSeconds} seconds.`);
|
||||
|
|
|
@ -91,10 +91,16 @@ function _getOverlays(filmstripOnly) {
|
|||
}
|
||||
} else if (!(overlays = _nonFilmstripOnlyOverlays)) {
|
||||
overlays = _nonFilmstripOnlyOverlays = [
|
||||
PageReloadOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
PageReloadOverlay
|
||||
];
|
||||
|
||||
// Mobile only has a PageReloadOverlay.
|
||||
if (navigator.product !== 'ReactNative') {
|
||||
overlays.push(...[
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return overlays;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { overlayFrame as styles } from './styles';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@code OverlayFrame}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The children components to be displayed into the overlay frame.
|
||||
*/
|
||||
children?: React$Node,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React component to act as the frame for overlays.
|
||||
*/
|
||||
export default class OverlayFrame extends Component<Props> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<View style = { styles.container }>
|
||||
{ this.props.children }
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { appNavigate } from '../../app';
|
||||
import { translate } from '../../base/i18n';
|
||||
import { LoadingIndicator } from '../../base/react';
|
||||
|
||||
import { _reloadNow } from '../actions';
|
||||
|
||||
import AbstractPageReloadOverlay, { abstractMapStateToProps }
|
||||
from './AbstractPageReloadOverlay';
|
||||
import OverlayFrame from './OverlayFrame';
|
||||
import { pageReloadOverlay as styles } from './styles';
|
||||
|
||||
/**
|
||||
* Implements a React Component for page reload overlay. Shown before the
|
||||
* conference is reloaded. Shows a warning message and counts down towards the
|
||||
* reload.
|
||||
*/
|
||||
class PageReloadOverlay extends AbstractPageReloadOverlay {
|
||||
/**
|
||||
* Initializes a new PageReloadOverlay instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
* @public
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onReloadNow = this._onReloadNow.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicking of the "Cancel" button. It will navigate back to the
|
||||
* welcome page.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCancel() {
|
||||
clearInterval(this._interval);
|
||||
this.props.dispatch(appNavigate(undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicking on the "Reload Now" button. It will navigate to the same
|
||||
* conference URL as before immediately, without waiting for the timer to
|
||||
* kick in.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onReloadNow() {
|
||||
clearInterval(this._interval);
|
||||
this.props.dispatch(_reloadNow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { message, timeLeft, title } = this.state;
|
||||
|
||||
return (
|
||||
<OverlayFrame>
|
||||
<View style = { styles.container }>
|
||||
<View style = { styles.loadingIndicator }>
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
<Text style = { styles.title }>
|
||||
{ t(title) }
|
||||
</Text>
|
||||
<Text style = { styles.message }>
|
||||
{ t(message, { seconds: timeLeft }) }
|
||||
</Text>
|
||||
<View style = { styles.buttonBox }>
|
||||
<Text
|
||||
onPress = { this._onReloadNow }
|
||||
style = { styles.button } >
|
||||
{ t('dialog.rejoinNow') }
|
||||
</Text>
|
||||
<Text
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.button } >
|
||||
{ t('dialog.Cancel') }
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</OverlayFrame>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect(abstractMapStateToProps)(PageReloadOverlay));
|
|
@ -0,0 +1,91 @@
|
|||
import { BoxModel, ColorPalette, createStyleSheet } from '../../base/styles';
|
||||
|
||||
/**
|
||||
* The default color of text on overlays.
|
||||
*/
|
||||
const TEXT_COLOR = ColorPalette.white;
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code OverlayFrame}.
|
||||
*/
|
||||
export const overlayFrame = createStyleSheet({
|
||||
/**
|
||||
* Style for a backdrop overlay covering the screen the the overlay is
|
||||
* rendered.
|
||||
*/
|
||||
container: {
|
||||
backgroundColor: ColorPalette.red,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code PageReloadOverlay}.
|
||||
*/
|
||||
export const pageReloadOverlay = createStyleSheet({
|
||||
/**
|
||||
* Style for the buttons on {@code PageReloadOverlay}.
|
||||
*/
|
||||
button: {
|
||||
color: TEXT_COLOR,
|
||||
fontSize: 20,
|
||||
marginVertical: BoxModel.margin,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the "box" surrounding the buttons at the bottom of the page.
|
||||
*/
|
||||
buttonBox: {
|
||||
bottom: BoxModel.margin,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the container of the {@code PageReloadOVerlay}.
|
||||
*/
|
||||
container: {
|
||||
flex: 1,
|
||||
marginBottom: BoxModel.margin,
|
||||
marginHorizontal: BoxModel.margin,
|
||||
marginTop: BoxModel.margin * 3
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the {@code LoadingIndicator}.
|
||||
*/
|
||||
loadingIndicator: {
|
||||
alignItems: 'center',
|
||||
bottom: 0,
|
||||
justifyContent: 'center',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the descriptive error message.
|
||||
*/
|
||||
message: {
|
||||
color: TEXT_COLOR,
|
||||
fontSize: 16,
|
||||
marginTop: BoxModel.margin,
|
||||
textAlign: 'center'
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the error title.
|
||||
*/
|
||||
title: {
|
||||
color: TEXT_COLOR,
|
||||
fontSize: 24,
|
||||
textAlign: 'center'
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue