fix(gum) add event handling for SLOW_GET_USER_MEDIA
Show an overlay with a spinner when slow gUM is fired
This commit is contained in:
parent
43761fc398
commit
f50fd7b7bd
|
@ -115,7 +115,7 @@ import {
|
||||||
submitFeedback
|
submitFeedback
|
||||||
} from './react/features/feedback';
|
} from './react/features/feedback';
|
||||||
import { showNotification } from './react/features/notifications';
|
import { showNotification } from './react/features/notifications';
|
||||||
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
|
import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
|
||||||
import { suspendDetected } from './react/features/power-monitor';
|
import { suspendDetected } from './react/features/power-monitor';
|
||||||
import {
|
import {
|
||||||
initPrejoin,
|
initPrejoin,
|
||||||
|
@ -502,6 +502,11 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitsiMeetJS.mediaDevices.addEventListener(
|
||||||
|
JitsiMediaDevicesEvents.SLOW_GET_USER_MEDIA,
|
||||||
|
() => APP.store.dispatch(toggleSlowGUMOverlay(true))
|
||||||
|
);
|
||||||
|
|
||||||
let tryCreateLocalTracks;
|
let tryCreateLocalTracks;
|
||||||
|
|
||||||
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
|
// On Electron there is no permission prompt for granting permissions. That's why we don't need to
|
||||||
|
@ -519,8 +524,10 @@ export default {
|
||||||
|
|
||||||
return createLocalTracksF({
|
return createLocalTracksF({
|
||||||
devices: [ 'audio' ],
|
devices: [ 'audio' ],
|
||||||
timeout
|
timeout,
|
||||||
}, true)
|
firePermissionPromptIsShownEvent: true,
|
||||||
|
fireSlowPromiseEvent: true
|
||||||
|
})
|
||||||
.then(([ audioStream ]) =>
|
.then(([ audioStream ]) =>
|
||||||
[ desktopStream, audioStream ])
|
[ desktopStream, audioStream ])
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -536,8 +543,10 @@ export default {
|
||||||
return requestedAudio
|
return requestedAudio
|
||||||
? createLocalTracksF({
|
? createLocalTracksF({
|
||||||
devices: [ 'audio' ],
|
devices: [ 'audio' ],
|
||||||
timeout
|
timeout,
|
||||||
}, true)
|
firePermissionPromptIsShownEvent: true,
|
||||||
|
fireSlowPromiseEvent: true
|
||||||
|
})
|
||||||
: [];
|
: [];
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -551,8 +560,10 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
tryCreateLocalTracks = createLocalTracksF({
|
tryCreateLocalTracks = createLocalTracksF({
|
||||||
devices: initialDevices,
|
devices: initialDevices,
|
||||||
timeout
|
timeout,
|
||||||
}, true)
|
firePermissionPromptIsShownEvent: true,
|
||||||
|
fireSlowPromiseEvent: true
|
||||||
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (requestedAudio && requestedVideo) {
|
if (requestedAudio && requestedVideo) {
|
||||||
|
|
||||||
|
@ -574,8 +585,10 @@ export default {
|
||||||
return (
|
return (
|
||||||
createLocalTracksF({
|
createLocalTracksF({
|
||||||
devices: [ 'audio' ],
|
devices: [ 'audio' ],
|
||||||
timeout
|
timeout,
|
||||||
}, true));
|
firePermissionPromptIsShownEvent: true,
|
||||||
|
fireSlowPromiseEvent: true
|
||||||
|
}));
|
||||||
} else if (requestedAudio && !requestedVideo) {
|
} else if (requestedAudio && !requestedVideo) {
|
||||||
errors.audioOnlyError = err;
|
errors.audioOnlyError = err;
|
||||||
|
|
||||||
|
@ -598,8 +611,9 @@ export default {
|
||||||
return requestedVideo
|
return requestedVideo
|
||||||
? createLocalTracksF({
|
? createLocalTracksF({
|
||||||
devices: [ 'video' ],
|
devices: [ 'video' ],
|
||||||
timeout
|
firePermissionPromptIsShownEvent: true,
|
||||||
}, true)
|
fireSlowPromiseEvent: true
|
||||||
|
})
|
||||||
: [];
|
: [];
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
@ -619,6 +633,7 @@ export default {
|
||||||
// the user inputs their credentials, but the dialog would be
|
// the user inputs their credentials, but the dialog would be
|
||||||
// overshadowed by the overlay.
|
// overshadowed by the overlay.
|
||||||
tryCreateLocalTracks.then(tracks => {
|
tryCreateLocalTracks.then(tracks => {
|
||||||
|
APP.store.dispatch(toggleSlowGUMOverlay(false));
|
||||||
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
|
APP.store.dispatch(mediaPermissionPromptVisibilityChanged(false));
|
||||||
|
|
||||||
return tracks;
|
return tracks;
|
||||||
|
@ -882,7 +897,7 @@ export default {
|
||||||
showUI && APP.store.dispatch(notifyMicError(error));
|
showUI && APP.store.dispatch(notifyMicError(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
createLocalTracksF({ devices: [ 'audio' ] }, false)
|
createLocalTracksF({ devices: [ 'audio' ] })
|
||||||
.then(([ audioTrack ]) => audioTrack)
|
.then(([ audioTrack ]) => audioTrack)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
maybeShowErrorDialog(error);
|
maybeShowErrorDialog(error);
|
||||||
|
@ -996,7 +1011,7 @@ export default {
|
||||||
//
|
//
|
||||||
// FIXME when local track creation is moved to react/redux
|
// FIXME when local track creation is moved to react/redux
|
||||||
// it should take care of the use case described above
|
// it should take care of the use case described above
|
||||||
createLocalTracksF({ devices: [ 'video' ] }, false)
|
createLocalTracksF({ devices: [ 'video' ] })
|
||||||
.then(([ videoTrack ]) => videoTrack)
|
.then(([ videoTrack ]) => videoTrack)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// FIXME should send some feedback to the API on error ?
|
// FIXME should send some feedback to the API on error ?
|
||||||
|
|
|
@ -33,4 +33,12 @@
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__spinner-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10343,8 +10343,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lib-jitsi-meet": {
|
"lib-jitsi-meet": {
|
||||||
"version": "github:jitsi/lib-jitsi-meet#7f919faaccb268ef307d619992260919a6535e95",
|
"version": "github:jitsi/lib-jitsi-meet#c534f748849a308d08b06e306f5a66709ccae056",
|
||||||
"from": "github:jitsi/lib-jitsi-meet#7f919faaccb268ef307d619992260919a6535e95",
|
"from": "github:jitsi/lib-jitsi-meet#c534f748849a308d08b06e306f5a66709ccae056",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jitsi/js-utils": "1.0.2",
|
"@jitsi/js-utils": "1.0.2",
|
||||||
"@jitsi/sdp-interop": "1.0.3",
|
"@jitsi/sdp-interop": "1.0.3",
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
"jquery-i18next": "1.2.1",
|
"jquery-i18next": "1.2.1",
|
||||||
"js-md5": "0.6.1",
|
"js-md5": "0.6.1",
|
||||||
"jwt-decode": "2.2.0",
|
"jwt-decode": "2.2.0",
|
||||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#7f919faaccb268ef307d619992260919a6535e95",
|
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#c534f748849a308d08b06e306f5a66709ccae056",
|
||||||
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
|
||||||
"lodash": "4.17.19",
|
"lodash": "4.17.19",
|
||||||
"moment": "2.19.4",
|
"moment": "2.19.4",
|
||||||
|
|
|
@ -127,7 +127,6 @@ export function createLocalTracksA(options = {}) {
|
||||||
options.facingMode || CAMERA_FACING_MODE.USER,
|
options.facingMode || CAMERA_FACING_MODE.USER,
|
||||||
micDeviceId: options.micDeviceId
|
micDeviceId: options.micDeviceId
|
||||||
},
|
},
|
||||||
/* firePermissionPromptIsShownEvent */ false,
|
|
||||||
store)
|
store)
|
||||||
.then(
|
.then(
|
||||||
localTracks => {
|
localTracks => {
|
||||||
|
|
|
@ -63,16 +63,25 @@ export async function createLocalPresenterTrack(options, desktopHeight) {
|
||||||
* @param {string|null} [options.micDeviceId] - Microphone device id or
|
* @param {string|null} [options.micDeviceId] - Microphone device id or
|
||||||
* {@code undefined} to use app's settings.
|
* {@code undefined} to use app's settings.
|
||||||
* @param {number|undefined} [oprions.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
* @param {number|undefined} [oprions.timeout] - A timeout for JitsiMeetJS.createLocalTracks used to create the tracks.
|
||||||
* @param {boolean} [firePermissionPromptIsShownEvent] - Whether lib-jitsi-meet
|
* @param {boolean} [options.firePermissionPromptIsShownEvent] - Whether lib-jitsi-meet
|
||||||
* should check for a {@code getUserMedia} permission prompt and fire a
|
* should check for a {@code getUserMedia} permission prompt and fire a
|
||||||
* corresponding event.
|
* corresponding event.
|
||||||
|
* @param {boolean} [options.fireSlowPromiseEvent] - Whether lib-jitsi-meet
|
||||||
|
* should check for a slow {@code getUserMedia} request and fire a
|
||||||
|
* corresponding event.
|
||||||
* @param {Object} store - The redux store in the context of which the function
|
* @param {Object} store - The redux store in the context of which the function
|
||||||
* is to execute and from which state such as {@code config} is to be retrieved.
|
* is to execute and from which state such as {@code config} is to be retrieved.
|
||||||
* @returns {Promise<JitsiLocalTrack[]>}
|
* @returns {Promise<JitsiLocalTrack[]>}
|
||||||
*/
|
*/
|
||||||
export function createLocalTracksF(options = {}, firePermissionPromptIsShownEvent, store) {
|
export function createLocalTracksF(options = {}, store) {
|
||||||
let { cameraDeviceId, micDeviceId } = options;
|
let { cameraDeviceId, micDeviceId } = options;
|
||||||
const { desktopSharingSourceDevice, desktopSharingSources, timeout } = options;
|
const {
|
||||||
|
desktopSharingSourceDevice,
|
||||||
|
desktopSharingSources,
|
||||||
|
firePermissionPromptIsShownEvent,
|
||||||
|
fireSlowPromiseEvent,
|
||||||
|
timeout
|
||||||
|
} = options;
|
||||||
|
|
||||||
if (typeof APP !== 'undefined') {
|
if (typeof APP !== 'undefined') {
|
||||||
// TODO The app's settings should go in the redux store and then the
|
// TODO The app's settings should go in the redux store and then the
|
||||||
|
@ -114,11 +123,12 @@ export function createLocalTracksF(options = {}, firePermissionPromptIsShownEven
|
||||||
devices: options.devices.slice(0),
|
devices: options.devices.slice(0),
|
||||||
effects,
|
effects,
|
||||||
firefox_fake_device, // eslint-disable-line camelcase
|
firefox_fake_device, // eslint-disable-line camelcase
|
||||||
|
firePermissionPromptIsShownEvent,
|
||||||
|
fireSlowPromiseEvent,
|
||||||
micDeviceId,
|
micDeviceId,
|
||||||
resolution,
|
resolution,
|
||||||
timeout
|
timeout
|
||||||
},
|
})
|
||||||
firePermissionPromptIsShownEvent)
|
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error('Failed to create local tracks', options.devices, err);
|
logger.error('Failed to create local tracks', options.devices, err);
|
||||||
|
|
||||||
|
@ -161,7 +171,10 @@ export function createPrejoinTracks() {
|
||||||
// Resolve with no tracks
|
// Resolve with no tracks
|
||||||
tryCreateLocalTracks = Promise.resolve([]);
|
tryCreateLocalTracks = Promise.resolve([]);
|
||||||
} else {
|
} else {
|
||||||
tryCreateLocalTracks = createLocalTracksF({ devices: initialDevices }, true)
|
tryCreateLocalTracks = createLocalTracksF({
|
||||||
|
devices: initialDevices,
|
||||||
|
firePermissionPromptIsShownEvent: true
|
||||||
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (requestedAudio && requestedVideo) {
|
if (requestedAudio && requestedVideo) {
|
||||||
|
|
||||||
|
@ -169,7 +182,10 @@ export function createPrejoinTracks() {
|
||||||
errors.audioAndVideoError = err;
|
errors.audioAndVideoError = err;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
createLocalTracksF({ devices: [ 'audio' ] }, true));
|
createLocalTracksF({
|
||||||
|
devices: [ 'audio' ],
|
||||||
|
firePermissionPromptIsShownEvent: true
|
||||||
|
}));
|
||||||
} else if (requestedAudio && !requestedVideo) {
|
} else if (requestedAudio && !requestedVideo) {
|
||||||
errors.audioOnlyError = err;
|
errors.audioOnlyError = err;
|
||||||
|
|
||||||
|
@ -190,7 +206,10 @@ export function createPrejoinTracks() {
|
||||||
|
|
||||||
// Try video only...
|
// Try video only...
|
||||||
return requestedVideo
|
return requestedVideo
|
||||||
? createLocalTracksF({ devices: [ 'video' ] }, true)
|
? createLocalTracksF({
|
||||||
|
devices: [ 'video' ],
|
||||||
|
firePermissionPromptIsShownEvent: true
|
||||||
|
})
|
||||||
: [];
|
: [];
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
|
|
@ -14,6 +14,17 @@
|
||||||
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
|
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
|
||||||
= 'MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED';
|
= 'MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the Redux action which signals that the overlay for slow gUM is visible or not.
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* type: TOGGLE_SLOW_GUM_OVERLAY,
|
||||||
|
* isVisible: {boolean},
|
||||||
|
* }
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export const TOGGLE_SLOW_GUM_OVERLAY = 'TOGGLE_SLOW_GUM_OVERLAY';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust the state of the fatal error which shows/hides the reload screen. See
|
* 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.
|
* action methods's description for more info about each of the fields.
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||||
SET_FATAL_ERROR
|
SET_FATAL_ERROR,
|
||||||
|
TOGGLE_SLOW_GUM_OVERLAY
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +27,24 @@ export function mediaPermissionPromptVisibilityChanged(isVisible: boolean, brows
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @public
|
||||||
|
* @returns {{
|
||||||
|
* type: SLOW_GET_USER_MEDIA_OVERLAY,
|
||||||
|
* isVisible: {boolean}
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function toggleSlowGUMOverlay(isVisible: boolean) {
|
||||||
|
return {
|
||||||
|
type: TOGGLE_SLOW_GUM_OVERLAY,
|
||||||
|
isVisible
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The action indicates that an unrecoverable error has occurred and the reload
|
* The action indicates that an unrecoverable error has occurred and the reload
|
||||||
* screen will be displayed or hidden.
|
* screen will be displayed or hidden.
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { Component } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@code Component} props of
|
||||||
|
* {@link AbstractSlowGUMOverlay}.
|
||||||
|
*/
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to translate human-readable text.
|
||||||
|
*/
|
||||||
|
t: Function
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a React {@link Component} for slow gUM overlay. Shown when
|
||||||
|
* a slow gUM promise resolution is detected
|
||||||
|
*/
|
||||||
|
export default class AbstractSlowGUMOverlay 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 state['features/overlay'].isSlowGUMOverlayVisible;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
// @flow
|
||||||
|
import Spinner from '@atlaskit/spinner';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { translate } from '../../../base/i18n';
|
||||||
|
|
||||||
|
import AbstractSlowGUMOverlay from './AbstractSlowGUMOverlay';
|
||||||
|
import OverlayFrame from './OverlayFrame';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements a React {@link Component} for slow gUM overlay. Shown when
|
||||||
|
* a slow gUM promise resolution is detected
|
||||||
|
*/
|
||||||
|
class SlowGUMOverlay extends AbstractSlowGUMOverlay {
|
||||||
|
/**
|
||||||
|
* Implements React's {@link Component#render()}.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
// const { t } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayFrame>
|
||||||
|
<div className = { 'overlay__spinner-container' }>
|
||||||
|
<Spinner
|
||||||
|
invertColor = { true }
|
||||||
|
size = { 'large' } />
|
||||||
|
</div>
|
||||||
|
</OverlayFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate(SlowGUMOverlay);
|
|
@ -5,3 +5,4 @@ export { default as OverlayFrame } from './OverlayFrame';
|
||||||
export { default as PageReloadOverlay } from './PageReloadOverlay';
|
export { default as PageReloadOverlay } from './PageReloadOverlay';
|
||||||
export { default as SuspendedOverlay } from './SuspendedOverlay';
|
export { default as SuspendedOverlay } from './SuspendedOverlay';
|
||||||
export { default as UserMediaPermissionsOverlay } from './UserMediaPermissionsOverlay';
|
export { default as UserMediaPermissionsOverlay } from './UserMediaPermissionsOverlay';
|
||||||
|
export { default as SlowGUMOverlay } from './SlowGUMOverlay';
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PageReloadOverlay,
|
PageReloadOverlay,
|
||||||
|
SlowGUMOverlay,
|
||||||
SuspendedOverlay,
|
SuspendedOverlay,
|
||||||
UserMediaPermissionsOverlay
|
UserMediaPermissionsOverlay
|
||||||
} from './components/web';
|
} from './components/web';
|
||||||
|
@ -17,6 +18,7 @@ export function getOverlays(): Array<Object> {
|
||||||
return [
|
return [
|
||||||
PageReloadOverlay,
|
PageReloadOverlay,
|
||||||
SuspendedOverlay,
|
SuspendedOverlay,
|
||||||
UserMediaPermissionsOverlay
|
UserMediaPermissionsOverlay,
|
||||||
|
SlowGUMOverlay
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ import { assign, ReducerRegistry, set } from '../base/redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
|
||||||
SET_FATAL_ERROR
|
SET_FATAL_ERROR,
|
||||||
|
TOGGLE_SLOW_GUM_OVERLAY
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +29,8 @@ ReducerRegistry.register('features/overlay', (state = { }, action) => {
|
||||||
case SET_FATAL_ERROR:
|
case SET_FATAL_ERROR:
|
||||||
return _setFatalError(state, action);
|
return _setFatalError(state, action);
|
||||||
|
|
||||||
|
case TOGGLE_SLOW_GUM_OVERLAY:
|
||||||
|
return _toggleSlowGUMOverlay(state, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
@ -52,6 +55,24 @@ function _mediaPermissionPromptVisibilityChanged(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduces a specific redux action TOGGLE_SLOW_GUM_OVERLAY of
|
||||||
|
* the feature overlay.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state of the feature overlay.
|
||||||
|
* @param {Action} action - The redux action to reduce.
|
||||||
|
* @private
|
||||||
|
* @returns {Object} The new state of the feature overlay after the reduction of
|
||||||
|
* the specified action.
|
||||||
|
*/
|
||||||
|
function _toggleSlowGUMOverlay(
|
||||||
|
state,
|
||||||
|
{ isVisible }) {
|
||||||
|
return assign(state, {
|
||||||
|
isSlowGUMOverlayVisible: isVisible
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@code LoadConfigOverlay} overlay visible or not.
|
* Sets the {@code LoadConfigOverlay} overlay visible or not.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue