feat(overlay): native page reload dialog (#12667)
feat(overlay): native feature removal + replaced PageReloadOverlay with PageReloadDialog
This commit is contained in:
parent
22ded30b61
commit
3cb0df579c
|
@ -141,7 +141,7 @@ import {
|
|||
showNotification,
|
||||
showWarningNotification
|
||||
} from './react/features/notifications';
|
||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
|
||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay/actions';
|
||||
import { suspendDetected } from './react/features/power-monitor';
|
||||
import { initPrejoin, makePrecallTest, setJoiningInProgress } from './react/features/prejoin/actions';
|
||||
import { isPrejoinPageVisible } from './react/features/prejoin/functions';
|
||||
|
|
|
@ -30,8 +30,6 @@ import {
|
|||
// @ts-ignore
|
||||
import { screen } from '../mobile/navigation/routes';
|
||||
import { clearNotifications } from '../notifications/actions';
|
||||
// @ts-ignore
|
||||
import { setFatalError } from '../overlay';
|
||||
|
||||
import { addTrackStateToURL, getDefaultURL } from './functions.native';
|
||||
import logger from './logger';
|
||||
|
@ -177,7 +175,6 @@ export function maybeRedirectToWelcomePage(options: any) { // eslint-disable-lin
|
|||
*/
|
||||
export function reloadNow() {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
dispatch(setFatalError(undefined));
|
||||
|
||||
const state = getState();
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
|
|
@ -20,7 +20,6 @@ import {
|
|||
import { isVpaasMeeting } from '../jaas/functions';
|
||||
import { clearNotifications, showNotification } from '../notifications/actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
|
||||
import { setFatalError } from '../overlay/actions';
|
||||
import { isWelcomePageEnabled } from '../welcome/functions';
|
||||
|
||||
import {
|
||||
|
@ -222,7 +221,6 @@ export function maybeRedirectToWelcomePage(options: { feedbackSubmitted?: boolea
|
|||
*/
|
||||
export function reloadNow() {
|
||||
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
||||
dispatch(setFatalError(undefined));
|
||||
|
||||
const state = getState();
|
||||
const { locationURL } = state['features/base/connection'];
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { BaseApp } from '../../base/app';
|
||||
import { toURLString } from '../../base/util';
|
||||
import { OverlayContainer } from '../../overlay';
|
||||
import { appNavigate } from '../actions';
|
||||
import { getDefaultURL } from '../functions';
|
||||
|
||||
|
@ -73,23 +70,7 @@ export class AbstractApp extends BaseApp<Props, *> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an extra {@link ReactElement}s to be added (unconditionally)
|
||||
* alongside the main element.
|
||||
*
|
||||
* @abstract
|
||||
* @protected
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createExtraElement() {
|
||||
return (
|
||||
<Fragment>
|
||||
<OverlayContainer />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
_createMainElement: (React$Element<*>, Object) => ?React$Element<*>;
|
||||
_createMainElement: (React.ReactElement, Object) => ?React.ReactElement;
|
||||
|
||||
/**
|
||||
* Gets the default URL to be opened when this {@code App} mounts.
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||
import React from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
|
||||
import GlobalStyles from '../../base/ui/components/GlobalStyles.web';
|
||||
import JitsiThemeProvider from '../../base/ui/components/JitsiThemeProvider.web';
|
||||
import DialogContainer from '../../base/ui/components/web/DialogContainer';
|
||||
import { ChromeExtensionBanner } from '../../chrome-extension-banner';
|
||||
import OverlayContainer from '../../overlay/components/web/OverlayContainer';
|
||||
|
||||
import { AbstractApp } from './AbstractApp';
|
||||
|
||||
|
@ -14,12 +13,30 @@ import { AbstractApp } from './AbstractApp';
|
|||
import '../middlewares';
|
||||
import '../reducers';
|
||||
|
||||
|
||||
/**
|
||||
* Root app {@code Component} on Web/React.
|
||||
*
|
||||
* @augments AbstractApp
|
||||
*/
|
||||
export class App extends AbstractApp {
|
||||
|
||||
/**
|
||||
* Creates an extra {@link ReactElement}s to be added (unconditionally)
|
||||
* alongside the main element.
|
||||
*
|
||||
* @abstract
|
||||
* @protected
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createExtraElement() {
|
||||
return (
|
||||
<Fragment>
|
||||
<OverlayContainer />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent method to inject {@link AtlasKitThemeProvider} as
|
||||
* the top most component.
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Container, Text } from '../../react';
|
||||
import { type StyleType } from '../../styles';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Children of the component.
|
||||
*/
|
||||
children: string | React$Node,
|
||||
|
||||
style: ?StyleType
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic dialog content container to provide the same styling for all custom
|
||||
* dialogs.
|
||||
*/
|
||||
export default class DialogContent extends Component<Props> {
|
||||
/**
|
||||
* Implements {@code Component#render}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
const { children, style } = this.props;
|
||||
|
||||
const childrenComponent = typeof children === 'string'
|
||||
? <Text style = { style }>{ children }</Text>
|
||||
: children;
|
||||
|
||||
return (
|
||||
<Container style = { styles.dialogContainer }>
|
||||
{ childrenComponent }
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * from './_';
|
||||
|
||||
export { default as DialogContent } from './DialogContent';
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
|
||||
// @ts-ignore
|
||||
import { randomInt } from '@jitsi/js-utils/random';
|
||||
import React, { Component } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { appNavigate, reloadNow } from '../../../../app/actions.native';
|
||||
import { IReduxState } from '../../../../app/types';
|
||||
import { translate } from '../../../i18n/functions';
|
||||
import { isFatalJitsiConnectionError } from '../../../lib-jitsi-meet/functions.native';
|
||||
import { connect } from '../../../redux/functions';
|
||||
// @ts-ignore
|
||||
import logger from '../../logger';
|
||||
|
||||
// @ts-ignore
|
||||
import ConfirmDialog from './ConfirmDialog';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of
|
||||
* {@link PageReloadDialog}.
|
||||
*/
|
||||
interface IPageReloadDialogProps extends WithTranslation {
|
||||
dispatch: Dispatch<any>;
|
||||
isNetworkFailure: boolean;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of
|
||||
* {@link PageReloadDialog}.
|
||||
*/
|
||||
interface IPageReloadDialogState {
|
||||
message: string;
|
||||
timeLeft: number;
|
||||
timeoutSeconds: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React Component that is shown before the
|
||||
* conference is reloaded.
|
||||
* Shows a warning message and counts down towards the re-load.
|
||||
*/
|
||||
class PageReloadDialog extends Component<IPageReloadDialogProps, IPageReloadDialogState> {
|
||||
|
||||
// @ts-ignore
|
||||
_interval: IntervalID;
|
||||
|
||||
/**
|
||||
* Initializes a new PageReloadOverlay instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
* @public
|
||||
*/
|
||||
constructor(props: IPageReloadDialogProps) {
|
||||
super(props);
|
||||
|
||||
const timeoutSeconds = 10 + randomInt(0, 20);
|
||||
|
||||
let message, title;
|
||||
|
||||
if (this.props.isNetworkFailure) {
|
||||
title = 'dialog.conferenceDisconnectTitle';
|
||||
message = 'dialog.conferenceDisconnectMsg';
|
||||
} else {
|
||||
title = 'dialog.conferenceReloadTitle';
|
||||
message = 'dialog.conferenceReloadMsg';
|
||||
}
|
||||
|
||||
this.state = {
|
||||
message,
|
||||
timeLeft: timeoutSeconds,
|
||||
timeoutSeconds,
|
||||
title
|
||||
};
|
||||
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onReloadNow = this._onReloadNow.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* React Component method that executes once component is mounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const { dispatch } = this.props;
|
||||
const { timeLeft } = this.state;
|
||||
|
||||
logger.info(
|
||||
`The conference will be reloaded after ${
|
||||
this.state.timeoutSeconds} seconds.`);
|
||||
|
||||
this._interval
|
||||
= setInterval(
|
||||
() => {
|
||||
if (timeLeft === 0) {
|
||||
if (this._interval) {
|
||||
clearInterval(this._interval);
|
||||
this._interval = undefined;
|
||||
}
|
||||
|
||||
dispatch(reloadNow());
|
||||
} else {
|
||||
this.setState(prevState => {
|
||||
return {
|
||||
timeLeft: prevState.timeLeft - 1
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the timer interval.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
if (this._interval) {
|
||||
clearInterval(this._interval);
|
||||
this._interval = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicking of the "Cancel" button. It will navigate back to the
|
||||
* welcome page.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onCancel() {
|
||||
clearInterval(this._interval);
|
||||
this.props.dispatch(appNavigate(undefined));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {boolean}
|
||||
*/
|
||||
_onReloadNow() {
|
||||
clearInterval(this._interval);
|
||||
this.props.dispatch(reloadNow());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { message, timeLeft, title } = this.state;
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
cancelLabel = 'dialog.Cancel'
|
||||
confirmLabel = 'dialog.rejoinNow'
|
||||
descriptionKey = { `${t(message, { seconds: timeLeft })}` }
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onReloadNow }
|
||||
title = { title } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the redux state to the associated component's props.
|
||||
*
|
||||
* @param {Object} state - The redux state.
|
||||
* @protected
|
||||
* @returns {{
|
||||
* message: string,
|
||||
* reason: string,
|
||||
* title: string
|
||||
* }}
|
||||
*/
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
const { error: conferenceError } = state['features/base/conference'];
|
||||
const { error: configError } = state['features/base/config'];
|
||||
const { error: connectionError } = state['features/base/connection'];
|
||||
const { fatalError } = state['features/overlay'];
|
||||
|
||||
const fatalConnectionError
|
||||
// @ts-ignore
|
||||
= connectionError && isFatalJitsiConnectionError(connectionError);
|
||||
const fatalConfigError = fatalError === configError;
|
||||
|
||||
const isNetworkFailure = fatalConfigError || fatalConnectionError;
|
||||
|
||||
let reason;
|
||||
|
||||
if (conferenceError) {
|
||||
reason = `error.conference.${conferenceError.name}`;
|
||||
} else if (connectionError) {
|
||||
reason = `error.conference.${connectionError.name}`;
|
||||
} else if (configError) {
|
||||
reason = `error.config.${configError.name}`;
|
||||
} else {
|
||||
logger.error('No reload reason defined!');
|
||||
}
|
||||
|
||||
return {
|
||||
isNetworkFailure,
|
||||
reason
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(mapStateToProps)(PageReloadDialog));
|
|
@ -5,6 +5,7 @@ export { default as ConfirmDialog } from './ConfirmDialog';
|
|||
export { default as DialogContainer } from './DialogContainer';
|
||||
export { default as AlertDialog } from './AlertDialog';
|
||||
export { default as InputDialog } from './InputDialog';
|
||||
export { default as PageReloadDialog } from './PageReloadDialog';
|
||||
|
||||
// NOTE: Some dialogs reuse the style of these base classes for consistency
|
||||
// and as we're in a /native namespace, it's safe to export the styles.
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import { BoxModel, createStyleSheet } from '../../styles';
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code Dialog}.
|
||||
*/
|
||||
export default createStyleSheet({
|
||||
/**
|
||||
* Unified container for a consistent Dialog style.
|
||||
*/
|
||||
dialogContainer: {
|
||||
paddingHorizontal: BoxModel.padding,
|
||||
paddingVertical: 1.5 * BoxModel.padding
|
||||
}
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
/**
|
||||
* Placeholder styles for web to be able to use cross platform components
|
||||
* unmodified such as {@code DialogContent}.
|
||||
*/
|
||||
export default {};
|
|
@ -1,9 +1,12 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { IStateful } from '../app/types';
|
||||
import { toState } from '../redux/functions';
|
||||
|
||||
// @ts-ignore
|
||||
import JitsiMeetJS from './_';
|
||||
|
||||
|
||||
const JitsiConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import { CalleeInfoContainer } from '../../../invite';
|
|||
import { LargeVideo } from '../../../large-video';
|
||||
import { LobbyScreen } from '../../../lobby';
|
||||
import { getIsLobbyVisible } from '../../../lobby/functions';
|
||||
import { getOverlayToRender } from '../../../overlay/functions.web';
|
||||
import { ParticipantsPane } from '../../../participants-pane/components/web';
|
||||
import Prejoin from '../../../prejoin/components/web/Prejoin';
|
||||
import { isPrejoinPageVisible } from '../../../prejoin/functions';
|
||||
|
@ -33,6 +34,7 @@ import type { AbstractProps } from '../AbstractConference';
|
|||
import ConferenceInfo from './ConferenceInfo';
|
||||
import { default as Notice } from './Notice';
|
||||
|
||||
|
||||
declare var APP: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
|
@ -59,6 +61,11 @@ type Props = AbstractProps & {
|
|||
*/
|
||||
_backgroundAlpha: number,
|
||||
|
||||
/**
|
||||
* Are any overlays visible?
|
||||
*/
|
||||
_isAnyOverlayVisible: boolean,
|
||||
|
||||
/**
|
||||
* The CSS class to apply to the root of {@link Conference} to modify the
|
||||
* application layout.
|
||||
|
@ -198,6 +205,7 @@ class Conference extends AbstractConference<Props, *> {
|
|||
*/
|
||||
render() {
|
||||
const {
|
||||
_isAnyOverlayVisible,
|
||||
_layoutClassName,
|
||||
_notificationsVisible,
|
||||
_overflowDrawer,
|
||||
|
@ -234,7 +242,7 @@ class Conference extends AbstractConference<Props, *> {
|
|||
|
||||
{ _showPrejoin || _showLobby || <Toolbox /> }
|
||||
|
||||
{_notificationsVisible && (_overflowDrawer
|
||||
{_notificationsVisible && !_isAnyOverlayVisible && (_overflowDrawer
|
||||
? <JitsiPortal className = 'notification-portal'>
|
||||
{this.renderNotificationsContainer({ portal: true })}
|
||||
</JitsiPortal>
|
||||
|
@ -383,6 +391,7 @@ function _mapStateToProps(state) {
|
|||
return {
|
||||
...abstractMapStateToProps(state),
|
||||
_backgroundAlpha: backgroundAlpha,
|
||||
_isAnyOverlayVisible: Boolean(getOverlayToRender(state)),
|
||||
_layoutClassName: LAYOUT_CLASSNAMES[getCurrentLayout(state)],
|
||||
_mouseMoveCallbackInterval: mouseMoveCallbackInterval,
|
||||
_overflowDrawer: overflowDrawer,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IStateful } from '../base/app/types';
|
||||
import { toState } from '../base/redux/functions';
|
||||
import { areThereNotifications } from '../notifications/functions';
|
||||
import { getOverlayToRender } from '../overlay/functions';
|
||||
|
||||
|
||||
/**
|
||||
* Tells whether or not the notifications should be displayed within
|
||||
|
@ -12,10 +12,7 @@ import { getOverlayToRender } from '../overlay/functions';
|
|||
*/
|
||||
export function shouldDisplayNotifications(stateful: IStateful) {
|
||||
const state = toState(stateful);
|
||||
const isAnyOverlayVisible = Boolean(getOverlayToRender(state));
|
||||
const { calleeInfoVisible } = state['features/invite'];
|
||||
|
||||
return areThereNotifications(state)
|
||||
&& !isAnyOverlayVisible
|
||||
&& !calleeInfoVisible;
|
||||
return areThereNotifications(state) && !calleeInfoVisible;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import { getLocalTracks, isLocalTrackMuted, toggleScreensharing } from '../../ba
|
|||
import { CLOSE_CHAT, OPEN_CHAT } from '../../chat';
|
||||
import { openChat } from '../../chat/actions';
|
||||
import { closeChat, sendMessage, setPrivateMessageRecipient } from '../../chat/actions.any';
|
||||
import { SET_PAGE_RELOAD_OVERLAY_CANCELED } from '../../overlay/actionTypes';
|
||||
import { setRequestingSubtitles } from '../../subtitles';
|
||||
import { muteLocal } from '../../video-menu/actions';
|
||||
import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';
|
||||
|
@ -214,16 +213,6 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
}
|
||||
break;
|
||||
|
||||
case SET_PAGE_RELOAD_OVERLAY_CANCELED:
|
||||
sendEvent(
|
||||
store,
|
||||
CONFERENCE_TERMINATED,
|
||||
/* data */ {
|
||||
error: _toErrorString(action.error),
|
||||
url: _normalizeUrl(store.getState()['features/base/connection'].locationURL)
|
||||
});
|
||||
|
||||
break;
|
||||
case SET_VIDEO_MUTED:
|
||||
sendEvent(
|
||||
store,
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
// @flow
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SafeAreaView, Text, View } from 'react-native';
|
||||
|
||||
// @ts-ignore
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { LoadingIndicator } from '../../../base/react';
|
||||
// @ts-ignore
|
||||
import LoadingIndicator from '../../../base/react/components/native/LoadingIndicator';
|
||||
|
||||
// @ts-ignore
|
||||
import { TEXT_COLOR, navigationStyles } from './styles';
|
||||
|
||||
|
||||
const ConnectingPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -1,16 +1,25 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import React, { useCallback } from 'react';
|
||||
import { StatusBar } from 'react-native';
|
||||
|
||||
import { connect } from '../../../base/redux';
|
||||
import { DialInSummary } from '../../../invite';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
// @ts-ignore
|
||||
import DialInSummary from '../../../invite/components/dial-in-summary/native/DialInSummary';
|
||||
import Prejoin from '../../../prejoin/components/native/Prejoin';
|
||||
// @ts-ignore
|
||||
import WelcomePage from '../../../welcome/components/WelcomePage';
|
||||
import { isWelcomePageEnabled } from '../../../welcome/functions';
|
||||
// @ts-ignore
|
||||
import { _ROOT_NAVIGATION_READY } from '../actionTypes';
|
||||
// @ts-ignore
|
||||
import { rootNavigationRef } from '../rootNavigationContainerRef';
|
||||
// @ts-ignore
|
||||
import { screen } from '../routes';
|
||||
// @ts-ignore
|
||||
import {
|
||||
conferenceNavigationContainerScreenOptions,
|
||||
connectingScreenOptions,
|
||||
|
@ -18,6 +27,7 @@ import {
|
|||
navigationContainerTheme,
|
||||
preJoinScreenOptions,
|
||||
welcomeScreenOptions
|
||||
// @ts-ignore
|
||||
} from '../screenOptions';
|
||||
|
||||
import ConnectingPage from './ConnectingPage';
|
||||
|
@ -32,13 +42,13 @@ type Props = {
|
|||
/**
|
||||
* Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
dispatch: Function;
|
||||
|
||||
/**
|
||||
* Is welcome page available?
|
||||
*/
|
||||
isWelcomePageAvailable: boolean
|
||||
}
|
||||
isWelcomePageAvailable: boolean;
|
||||
};
|
||||
|
||||
|
||||
const RootNavigationContainer = ({ dispatch, isWelcomePageAvailable }: Props) => {
|
||||
|
@ -100,7 +110,7 @@ const RootNavigationContainer = ({ dispatch, isWelcomePageAvailable }: Props) =>
|
|||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function mapStateToProps(state: Object) {
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
isWelcomePageAvailable: isWelcomePageEnabled(state)
|
||||
};
|
|
@ -13,26 +13,3 @@
|
|||
*/
|
||||
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
|
||||
= 'MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED';
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* {
|
||||
* type: SET_FATAL_ERROR,
|
||||
* fatalError: ?Object
|
||||
* }
|
||||
* @public
|
||||
*/
|
||||
export const SET_FATAL_ERROR = 'SET_FATAL_ERROR';
|
||||
|
||||
/**
|
||||
* The type of the Redux action which signals that the overlay was canceled.
|
||||
*
|
||||
* {
|
||||
* type: export const SET_PAGE_RELOAD_OVERLAY_CANCELED
|
||||
* }
|
||||
* @public
|
||||
*/
|
||||
export const SET_PAGE_RELOAD_OVERLAY_CANCELED
|
||||
= 'SET_PAGE_RELOAD_OVERLAY_CANCELED';
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* eslint-disable max-len */
|
||||
|
||||
// @ts-ignore
|
||||
import { PageReloadDialog, openDialog } from '../base/dialog';
|
||||
|
||||
|
||||
/**
|
||||
* Signals that the prompt for media permission is visible or not.
|
||||
*
|
||||
* @param {boolean} _isVisible - If the value is true - the prompt for media
|
||||
* permission is visible otherwise the value is false/undefined.
|
||||
* @param {string} _browser - The name of the current browser.
|
||||
* @public
|
||||
* @returns {{
|
||||
* type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
* browser: {string},
|
||||
* isVisible: {boolean}
|
||||
* }}
|
||||
*/
|
||||
export function mediaPermissionPromptVisibilityChanged(_isVisible: boolean, _browser: string) {
|
||||
// Dummy.
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens {@link PageReloadDialog}.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function openPageReloadDialog() {
|
||||
return openDialog(PageReloadDialog);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
import {
|
||||
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
SET_FATAL_ERROR,
|
||||
SET_PAGE_RELOAD_OVERLAY_CANCELED
|
||||
} from './actionTypes';
|
||||
|
||||
/**
|
||||
* Signals that the prompt for media permission is visible or not.
|
||||
*
|
||||
* @param {boolean} isVisible - If the value is true - the prompt for media
|
||||
* permission is visible otherwise the value is false/undefined.
|
||||
* @param {string} browser - The name of the current browser.
|
||||
* @public
|
||||
* @returns {{
|
||||
* type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
* browser: {string},
|
||||
* isVisible: {boolean}
|
||||
* }}
|
||||
*/
|
||||
export function mediaPermissionPromptVisibilityChanged(isVisible: boolean, browser: string) {
|
||||
return {
|
||||
type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
browser,
|
||||
isVisible
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The action indicates that an unrecoverable error has occurred and the reload
|
||||
* screen will be displayed or hidden.
|
||||
*
|
||||
* @param {Object} fatalError - A critical error which was not claimed by any
|
||||
* feature for error recovery (the recoverable flag was not set). If
|
||||
* {@code undefined} then any fatal error currently stored will be discarded.
|
||||
* @returns {{
|
||||
* type: SET_FATAL_ERROR,
|
||||
* fatalError: ?Error
|
||||
* }}
|
||||
*/
|
||||
export function setFatalError(fatalError?: Object) {
|
||||
return {
|
||||
type: SET_FATAL_ERROR,
|
||||
fatalError
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The action indicates that the overlay was canceled.
|
||||
*
|
||||
* @param {Object} error - The error that caused the display of the overlay.
|
||||
*
|
||||
* @returns {{
|
||||
* type: SET_PAGE_RELOAD_OVERLAY_CANCELED,
|
||||
* error: ?Error
|
||||
* }}
|
||||
*/
|
||||
export function setPageReloadOverlayCanceled(error: Object) {
|
||||
return {
|
||||
type: SET_PAGE_RELOAD_OVERLAY_CANCELED,
|
||||
error
|
||||
};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED } from './actionTypes';
|
||||
|
||||
|
||||
/**
|
||||
* Signals that the prompt for media permission is visible or not.
|
||||
*
|
||||
* @param {boolean} isVisible - If the value is true - the prompt for media
|
||||
* permission is visible otherwise the value is false/undefined.
|
||||
* @param {string} browser - The name of the current browser.
|
||||
* @public
|
||||
* @returns {{
|
||||
* type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
* browser: {string},
|
||||
* isVisible: {boolean}
|
||||
* }}
|
||||
*/
|
||||
export function mediaPermissionPromptVisibilityChanged(isVisible: boolean, browser: string) {
|
||||
return {
|
||||
type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
browser,
|
||||
isVisible
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens {@link PageReloadDialog}.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function openPageReloadDialog() {
|
||||
// Dummy
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export * from './native';
|
|
@ -1,3 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export * from './web';
|
|
@ -1,4 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export { default as OverlayContainer } from './OverlayContainer';
|
||||
export * from './_';
|
|
@ -1,38 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component, type Node } from 'react';
|
||||
import { SafeAreaView, View } from 'react-native';
|
||||
|
||||
import 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: 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 {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<View style = { styles.container }>
|
||||
<SafeAreaView style = { styles.safeContainer } >
|
||||
{ this.props.children }
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { appNavigate, reloadNow } from '../../../app/actions';
|
||||
import { ConfirmDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { setFatalError, setPageReloadOverlayCanceled } from '../../actions';
|
||||
import AbstractPageReloadOverlay, {
|
||||
type Props,
|
||||
abstractMapStateToProps
|
||||
} from '../AbstractPageReloadOverlay';
|
||||
|
||||
import OverlayFrame from './OverlayFrame';
|
||||
|
||||
|
||||
/**
|
||||
* 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<Props> {
|
||||
_interval: IntervalID;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
/**
|
||||
* Handle clicking of the "Cancel" button. It will navigate back to the
|
||||
* welcome page.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onCancel() {
|
||||
clearInterval(this._interval);
|
||||
this.props.dispatch(setPageReloadOverlayCanceled(this.props.error));
|
||||
this.props.dispatch(setFatalError(undefined));
|
||||
this.props.dispatch(appNavigate(undefined));
|
||||
}
|
||||
|
||||
_onReloadNow: () => void;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
<ConfirmDialog
|
||||
cancelLabel = 'dialog.Cancel'
|
||||
confirmLabel = 'dialog.rejoinNow'
|
||||
descriptionKey = { `${t(message, { seconds: timeLeft })}` }
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onReloadNow }
|
||||
title = { title } />
|
||||
</OverlayFrame>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect(abstractMapStateToProps)(PageReloadOverlay));
|
|
@ -1,4 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export { default as OverlayFrame } from './OverlayFrame';
|
||||
export { default as PageReloadOverlay } from './PageReloadOverlay';
|
|
@ -1,24 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of the overlay feature.
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* Style for a backdrop overlay covering the screen the the overlay is
|
||||
* rendered.
|
||||
*/
|
||||
container: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: BaseTheme.palette.ui00
|
||||
},
|
||||
|
||||
safeContainer: {
|
||||
flex: 1
|
||||
}
|
||||
};
|
|
@ -7,15 +7,15 @@ import type { Dispatch } from 'redux';
|
|||
import {
|
||||
createPageReloadScheduledEvent,
|
||||
sendAnalytics
|
||||
} from '../../analytics';
|
||||
import { reloadNow } from '../../app/actions';
|
||||
} from '../../../analytics';
|
||||
import { reloadNow } from '../../../app/actions';
|
||||
import {
|
||||
isFatalJitsiConferenceError,
|
||||
isFatalJitsiConnectionError
|
||||
} from '../../base/lib-jitsi-meet/functions';
|
||||
import logger from '../logger';
|
||||
} from '../../../base/lib-jitsi-meet/functions';
|
||||
import logger from '../../logger';
|
||||
|
||||
import ReloadButton from './web/ReloadButton';
|
||||
import ReloadButton from './ReloadButton';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
|
@ -91,6 +91,7 @@ type State = {
|
|||
*/
|
||||
export default class AbstractPageReloadOverlay<P: Props>
|
||||
extends Component<P, State> {
|
||||
|
||||
/**
|
||||
* Determines whether this overlay needs to be rendered (according to a
|
||||
* specific redux state). Called by {@link OverlayContainer}.
|
||||
|
@ -100,34 +101,18 @@ export default class AbstractPageReloadOverlay<P: Props>
|
|||
* {@code false}, otherwise.
|
||||
*/
|
||||
static needsRender(state: Object) {
|
||||
// FIXME web does not rely on the 'recoverable' flag set on an error
|
||||
// action, but on a predefined list of fatal errors. Because of that
|
||||
// the value of 'fatalError' which relies on the flag should not be used
|
||||
// on web yet (until conference/connection and their errors handling is
|
||||
// not unified).
|
||||
return typeof APP === 'undefined'
|
||||
? Boolean(state['features/overlay'].fatalError)
|
||||
: this.needsRenderWeb(state);
|
||||
}
|
||||
const { error: conferenceError } = state['features/base/conference'];
|
||||
const { error: configError } = state['features/base/config'];
|
||||
const { error: connectionError } = state['features/base/connection'];
|
||||
|
||||
/**
|
||||
* 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 needsRenderWeb(state: Object) {
|
||||
const conferenceError = state['features/base/conference'].error;
|
||||
const configError = state['features/base/config'].error;
|
||||
const connectionError = state['features/base/connection'].error;
|
||||
const jitsiConnectionError
|
||||
|
||||
return (
|
||||
(connectionError && isFatalJitsiConnectionError(connectionError))
|
||||
|| (conferenceError
|
||||
&& isFatalJitsiConferenceError(conferenceError))
|
||||
|| configError);
|
||||
// @ts-ignore
|
||||
= connectionError && isFatalJitsiConnectionError(connectionError);
|
||||
const jitsiConferenceError
|
||||
= conferenceError && isFatalJitsiConferenceError(conferenceError);
|
||||
|
||||
return jitsiConnectionError || jitsiConferenceError || configError;
|
||||
}
|
||||
|
||||
_interval: ?IntervalID;
|
|
@ -28,6 +28,6 @@ export default class AbstractSuspendedOverlay extends Component<Props> {
|
|||
* {@code false}, otherwise.
|
||||
*/
|
||||
static needsRender(state: Object) {
|
||||
return state['features/power-monitor'].suspendDetected;
|
||||
return state['features/power-monitor']?.suspendDetected;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { connect } from '../../base/redux';
|
||||
import { getOverlayToRender } from '../functions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
import { getOverlayToRender } from '../../functions.web';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* The type of the React {@link Component} props of {@code OverlayContainer}.
|
||||
|
@ -16,8 +14,8 @@ type Props = {
|
|||
* The React {@link Component} type of overlay to be rendered by the
|
||||
* associated {@code OverlayContainer}.
|
||||
*/
|
||||
overlay: ?React$ComponentType<*>
|
||||
}
|
||||
overlay: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a React {@link Component} that will display the correct overlay
|
||||
|
@ -48,7 +46,7 @@ class OverlayContainer extends Component<Props> {
|
|||
* overlay: ?Object
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
/**
|
||||
* The React {@link Component} type of overlay to be rendered by the
|
|
@ -1,8 +1,4 @@
|
|||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
import React, { Component, ReactChildren } from 'react';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link OverlayFrame}.
|
||||
|
@ -12,18 +8,18 @@ type Props = {
|
|||
/**
|
||||
* The children components to be displayed into the overlay frame.
|
||||
*/
|
||||
children: React$Node,
|
||||
children: ReactChildren;
|
||||
|
||||
/**
|
||||
* Indicates the css style of the overlay. If true, then lighter; darker,
|
||||
* otherwise.
|
||||
*/
|
||||
isLightOverlay?: boolean,
|
||||
isLightOverlay?: boolean;
|
||||
|
||||
/**
|
||||
* The style property.
|
||||
*/
|
||||
style: Object
|
||||
style: Object;
|
||||
};
|
||||
|
||||
/**
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
|
||||
import AbstractPageReloadOverlay, {
|
||||
type Props,
|
||||
abstractMapStateToProps
|
||||
} from '../AbstractPageReloadOverlay';
|
||||
|
||||
} from './AbstractPageReloadOverlay';
|
||||
import OverlayFrame from './OverlayFrame';
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export { default as OverlayFrame } from './OverlayFrame';
|
||||
|
||||
export { default as PageReloadOverlay } from './PageReloadOverlay';
|
||||
export { default as SuspendedOverlay } from './SuspendedOverlay';
|
||||
export { default as UserMediaPermissionsOverlay } from './UserMediaPermissionsOverlay';
|
|
@ -1,7 +1,13 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { IReduxState } from '../app/types';
|
||||
|
||||
import { getOverlays } from './overlays';
|
||||
|
||||
// @ts-ignore
|
||||
import PageReloadOverlay from './components/web/PageReloadOverlay';
|
||||
// @ts-ignore
|
||||
import SuspendedOverlay from './components/web/SuspendedOverlay';
|
||||
// @ts-ignore
|
||||
import UserMediaPermissionsOverlay from './components/web/UserMediaPermissionsOverlay';
|
||||
/**
|
||||
* Returns the overlay to be currently rendered.
|
||||
*
|
||||
|
@ -9,7 +15,13 @@ import { getOverlays } from './overlays';
|
|||
* @returns {?React$ComponentType<*>}
|
||||
*/
|
||||
export function getOverlayToRender(state: IReduxState) {
|
||||
for (const overlay of getOverlays()) {
|
||||
const overlays = [
|
||||
PageReloadOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
];
|
||||
|
||||
for (const overlay of overlays) {
|
||||
// react-i18n / react-redux wrap components and thus we cannot access
|
||||
// the wrapped component's static methods directly.
|
||||
// @ts-ignore
|
||||
|
@ -22,13 +34,3 @@ export function getOverlayToRender(state: IReduxState) {
|
|||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the visibility of the media permissions prompt.
|
||||
*
|
||||
* @param {IReduxState} state - The Redux state.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function getMediaPermissionPromptVisibility(state: IReduxState) {
|
||||
return state['features/overlay'].isMediaPermissionPromptVisible;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
// @flow
|
||||
|
||||
export * from './actions';
|
||||
export * from './components';
|
||||
export * from './functions';
|
|
@ -1,12 +1,15 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { IStore } from '../app/types';
|
||||
import { JitsiConferenceErrors } from '../base/lib-jitsi-meet';
|
||||
import {
|
||||
isFatalJitsiConferenceError,
|
||||
isFatalJitsiConnectionError
|
||||
} from '../base/lib-jitsi-meet/functions';
|
||||
} from '../base/lib-jitsi-meet/functions.any';
|
||||
import StateListenerRegistry from '../base/redux/StateListenerRegistry';
|
||||
|
||||
import { setFatalError } from './actions';
|
||||
import { openPageReloadDialog } from './actions';
|
||||
|
||||
|
||||
/**
|
||||
* Error type. Basically like Error, but augmented with a recoverable property.
|
||||
|
@ -47,12 +50,11 @@ const ERROR_TYPES = {
|
|||
/**
|
||||
* Gets the error type and whether it's fatal or not.
|
||||
*
|
||||
* @param {Function} getState - The redux function for fetching the current state.
|
||||
* @param {Object} state - The redux state.
|
||||
* @param {Object|string} error - The error to process.
|
||||
* @returns {void}
|
||||
*/
|
||||
const getErrorExtraInfo = (getState: IStore['getState'], error: ErrorType) => {
|
||||
const state = getState();
|
||||
const getErrorExtraInfo = (state: any, error: ErrorType) => {
|
||||
const { error: conferenceError } = state['features/base/conference'];
|
||||
const { error: configError } = state['features/base/config'];
|
||||
const { error: connectionError } = state['features/base/connection'];
|
||||
|
@ -92,20 +94,26 @@ StateListenerRegistry.register(
|
|||
|
||||
return configError || connectionError || conferenceError;
|
||||
},
|
||||
/* listener */ (error: ErrorType, { dispatch, getState }) => {
|
||||
/* listener */ (error: ErrorType, store: IStore) => {
|
||||
const state = store.getState();
|
||||
|
||||
if (!error) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-negated-condition
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.API.notifyError({
|
||||
...error,
|
||||
...getErrorExtraInfo(getState, error)
|
||||
...getErrorExtraInfo(state, error)
|
||||
});
|
||||
}
|
||||
|
||||
if (NON_OVERLAY_ERRORS.indexOf(error.name) === -1 && typeof error.recoverable === 'undefined') {
|
||||
dispatch(setFatalError(error));
|
||||
setTimeout(() => {
|
||||
// @ts-ignore
|
||||
store.dispatch(openPageReloadDialog());
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
import { ReactElement } from 'react';
|
||||
|
||||
// @ts-ignore
|
||||
import { PageReloadOverlay } from './components/native';
|
||||
|
||||
/**
|
||||
* Returns the list of available platform specific overlays.
|
||||
*
|
||||
* @returns {Array<ReactElement>}
|
||||
*/
|
||||
export function getOverlays(): Array<ReactElement> {
|
||||
return [
|
||||
PageReloadOverlay
|
||||
];
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import {
|
||||
PageReloadOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
|
||||
// @ts-ignore
|
||||
} from './components/web';
|
||||
|
||||
/**
|
||||
* Returns the list of available platform specific overlays.
|
||||
*
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
export function getOverlays(): Array<Object> {
|
||||
return [
|
||||
PageReloadOverlay,
|
||||
SuspendedOverlay,
|
||||
UserMediaPermissionsOverlay
|
||||
];
|
||||
}
|
|
@ -1,17 +1,13 @@
|
|||
import { CONFIG_WILL_LOAD, LOAD_CONFIG_ERROR, SET_CONFIG } from '../base/config/actionTypes';
|
||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
import { assign, set } from '../base/redux/functions';
|
||||
import { assign } from '../base/redux/functions';
|
||||
|
||||
import { MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED } from './actionTypes';
|
||||
|
||||
import {
|
||||
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||
SET_FATAL_ERROR
|
||||
} from './actionTypes';
|
||||
|
||||
export interface IOverlayState {
|
||||
browser?: string;
|
||||
fatalError?: Error;
|
||||
isMediaPermissionPromptVisible?: boolean;
|
||||
loadConfigOverlayVisible?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,18 +17,8 @@ export interface IOverlayState {
|
|||
*/
|
||||
ReducerRegistry.register<IOverlayState>('features/overlay', (state = {}, action): IOverlayState => {
|
||||
switch (action.type) {
|
||||
case CONFIG_WILL_LOAD:
|
||||
return _setShowLoadConfigOverlay(state, Boolean(action.room));
|
||||
|
||||
case LOAD_CONFIG_ERROR:
|
||||
case SET_CONFIG:
|
||||
return _setShowLoadConfigOverlay(state, false);
|
||||
|
||||
case MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED:
|
||||
return _mediaPermissionPromptVisibilityChanged(state, action);
|
||||
|
||||
case SET_FATAL_ERROR:
|
||||
return _setFatalError(state, action);
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -56,29 +42,3 @@ function _mediaPermissionPromptVisibilityChanged(
|
|||
isMediaPermissionPromptVisible: isVisible
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code LoadConfigOverlay} overlay visible or not.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature overlay.
|
||||
* @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 _setShowLoadConfigOverlay(state: IOverlayState, show?: boolean) {
|
||||
return set(state, 'loadConfigOverlayVisible', show);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces a specific redux action {@code SET_FATAL_ERROR} of the feature
|
||||
* overlay.
|
||||
*
|
||||
* @param {Object} state - The redux state of the feature overlay.
|
||||
* @param {Error} fatalError - If the value is set it indicates that a fatal
|
||||
* error has occurred and that the reload screen is to be displayed.
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
function _setFatalError(state: IOverlayState, { fatalError }: { fatalError?: Error; }) {
|
||||
return set(state, 'fatalError', fatalError);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue