ref(notifications): bring hiding of notifications into redux
This commit is contained in:
parent
74ddae4a6a
commit
cd66a7fcb7
|
@ -40,7 +40,8 @@ import {
|
|||
showToolbox
|
||||
} from '../../react/features/toolbox';
|
||||
import {
|
||||
maybeShowNotificationWithDoNotDisplay
|
||||
maybeShowNotificationWithDoNotDisplay,
|
||||
setNotificationsEnabled
|
||||
} from '../../react/features/notifications';
|
||||
|
||||
var EventEmitter = require("events");
|
||||
|
@ -51,17 +52,6 @@ import FollowMe from "../FollowMe";
|
|||
var eventEmitter = new EventEmitter();
|
||||
UI.eventEmitter = eventEmitter;
|
||||
|
||||
/**
|
||||
* Whether an overlay is visible or not.
|
||||
*
|
||||
* FIXME: This is temporary solution. Don't use this variable!
|
||||
* Should be removed when all the code is move to react.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @public
|
||||
*/
|
||||
UI.overlayVisible = false;
|
||||
|
||||
let etherpadManager;
|
||||
let sharedVideoManager;
|
||||
|
||||
|
@ -335,7 +325,7 @@ UI.start = function () {
|
|||
$("body").addClass("filmstrip-only");
|
||||
UI.showToolbar();
|
||||
Filmstrip.setFilmstripOnly();
|
||||
messageHandler.enableNotifications(false);
|
||||
APP.store.dispatch(setNotificationsEnabled(false));
|
||||
JitsiPopover.enabled = false;
|
||||
}
|
||||
|
||||
|
@ -1307,19 +1297,6 @@ UI.onSharedVideoStop = function (id, attributes) {
|
|||
sharedVideoManager.onSharedVideoStop(id, attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates if any the "top" overlays are currently visible. The check includes
|
||||
* the call/ring overlay, the suspended overlay, the GUM permissions overlay,
|
||||
* and the page-reload overlay.
|
||||
*
|
||||
* @returns {*|boolean} {true} if an overlay is visible; {false}, otherwise
|
||||
*/
|
||||
UI.isOverlayVisible = function () {
|
||||
return (
|
||||
this.overlayVisible
|
||||
|| APP.store.getState()['features/jwt'].callOverlayVisible);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles user's features changes.
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,7 @@ import VideoLayout from '../videolayout/VideoLayout';
|
|||
import Feedback from '../feedback/Feedback.js';
|
||||
|
||||
import { setToolboxEnabled } from '../../../react/features/toolbox';
|
||||
import { setNotificationsEnabled } from '../../../react/features/notifications';
|
||||
|
||||
/**
|
||||
* The dialog for user input.
|
||||
|
@ -309,7 +310,7 @@ var Recording = {
|
|||
VideoLayout.setLocalVideoVisible(false);
|
||||
Feedback.enableFeedback(false);
|
||||
APP.store.dispatch(setToolboxEnabled(false));
|
||||
APP.UI.messageHandler.enableNotifications(false);
|
||||
APP.store.dispatch(setNotificationsEnabled(false));
|
||||
APP.UI.messageHandler.enablePopups(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,6 @@ import {
|
|||
showNotification
|
||||
} from '../../../react/features/notifications';
|
||||
|
||||
/**
|
||||
* Flag for enable/disable of the notifications.
|
||||
* @type {boolean}
|
||||
*/
|
||||
let notificationsEnabled = true;
|
||||
|
||||
/**
|
||||
* Flag for enabling/disabling popups.
|
||||
* @type {boolean}
|
||||
|
@ -456,11 +450,6 @@ var messageHandler = {
|
|||
*/
|
||||
participantNotification: function(displayName, displayNameKey, cls,
|
||||
messageKey, messageArguments, timeout = 2500) {
|
||||
// If we're in ringing state we skip all notifications.
|
||||
if (!notificationsEnabled || APP.UI.isOverlayVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.store.dispatch(
|
||||
showNotification(
|
||||
Notification,
|
||||
|
@ -485,22 +474,10 @@ var messageHandler = {
|
|||
* @returns {void}
|
||||
*/
|
||||
notify: function(titleKey, messageKey, messageArguments) {
|
||||
|
||||
// If we're in ringing state we skip all notifications.
|
||||
if(!notificationsEnabled || APP.UI.isOverlayVisible())
|
||||
return;
|
||||
|
||||
this.participantNotification(
|
||||
null, titleKey, null, messageKey, messageArguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables / disables notifications.
|
||||
*/
|
||||
enableNotifications: function (enable) {
|
||||
notificationsEnabled = enable;
|
||||
},
|
||||
|
||||
enablePopups: function (enable) {
|
||||
popupEnabled = enable;
|
||||
},
|
||||
|
|
|
@ -79,7 +79,7 @@ class Conference extends Component {
|
|||
{ filmStripOnly ? null : <Toolbox /> }
|
||||
|
||||
<DialogContainer />
|
||||
{ filmStripOnly ? null : <NotificationsContainer /> }
|
||||
<NotificationsContainer />
|
||||
<OverlayContainer />
|
||||
|
||||
{/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* The type of (redux) action which signals that a specific notification should
|
||||
* not be displayed anymore.
|
||||
*
|
||||
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
export const HIDE_NOTIFICATION = Symbol('HIDE_NOTIFICATION');
|
||||
|
||||
/*
|
||||
/**
|
||||
* The type of (redux) action which signals that a notification component should
|
||||
* be displayed.
|
||||
*
|
||||
|
@ -22,3 +22,14 @@ export const HIDE_NOTIFICATION = Symbol('HIDE_NOTIFICATION');
|
|||
* }
|
||||
*/
|
||||
export const SHOW_NOTIFICATION = Symbol('SHOW_NOTIFICATION');
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that notifications should not
|
||||
* display.
|
||||
*
|
||||
* {
|
||||
* type: SET_NOTIFICATIONS_ENABLED,
|
||||
* enabled: Boolean
|
||||
* }
|
||||
*/
|
||||
export const SET_NOTIFICATIONS_ENABLED = Symbol('SET_NOTIFICATIONS_ENABLED');
|
||||
|
|
|
@ -2,6 +2,7 @@ import jitsiLocalStorage from '../../../modules/util/JitsiLocalStorage';
|
|||
|
||||
import {
|
||||
HIDE_NOTIFICATION,
|
||||
SET_NOTIFICATIONS_ENABLED,
|
||||
SHOW_NOTIFICATION
|
||||
} from './actionTypes';
|
||||
import { NotificationWithToggle } from './components';
|
||||
|
@ -23,6 +24,22 @@ export function hideNotification(uid) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops notifications from being displayed.
|
||||
*
|
||||
* @param {boolean} enabled - Whether or not notifications should display.
|
||||
* @returns {{
|
||||
* type: SET_NOTIFICATIONS_ENABLED,
|
||||
* enabled: boolean
|
||||
* }}
|
||||
*/
|
||||
export function setNotificationsEnabled(enabled) {
|
||||
return {
|
||||
type: SET_NOTIFICATIONS_ENABLED,
|
||||
enabled
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a notification for display.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,12 @@ class NotificationsContainer extends Component {
|
|||
*/
|
||||
_notifications: React.PropTypes.array,
|
||||
|
||||
/**
|
||||
* Whether or not notifications should be displayed at all. If not,
|
||||
* notifications will be dismissed immediately.
|
||||
*/
|
||||
_showNotifications: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* Invoked to update the redux store in order to remove notifications.
|
||||
*/
|
||||
|
@ -59,18 +65,27 @@ class NotificationsContainer extends Component {
|
|||
* returns {void}
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
const { _notifications } = this.props;
|
||||
const { _notifications, _showNotifications } = this.props;
|
||||
|
||||
if (_notifications.length && !this._notificationDismissTimeout) {
|
||||
if (_notifications.length) {
|
||||
const notification = _notifications[0];
|
||||
const { timeout, uid } = notification;
|
||||
|
||||
this._notificationDismissTimeout = setTimeout(() => {
|
||||
// Perform a no-op if a timeout is not specified.
|
||||
if (Number.isInteger(timeout)) {
|
||||
this._onDismissed(uid);
|
||||
}
|
||||
}, timeout);
|
||||
if (!_showNotifications) {
|
||||
this._onDismissed(notification.uid);
|
||||
} else if (this._notificationDismissTimeout) {
|
||||
|
||||
// No-op because there should already be a notification that
|
||||
// is waiting for dismissal.
|
||||
} else {
|
||||
const { timeout, uid } = notification;
|
||||
|
||||
this._notificationDismissTimeout = setTimeout(() => {
|
||||
// Perform a no-op if a timeout is not specified.
|
||||
if (Number.isInteger(timeout)) {
|
||||
this._onDismissed(uid);
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,28 +106,9 @@ class NotificationsContainer extends Component {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _notifications } = this.props;
|
||||
|
||||
const flags = _notifications.map(notification => {
|
||||
const Notification = notification.component;
|
||||
const { props, uid } = notification;
|
||||
|
||||
// The id attribute is necessary as {@code FlagGroup} looks for
|
||||
// either id or key to set a key on notifications, but accessing
|
||||
// props.key will cause React to print an error.
|
||||
return (
|
||||
<Notification
|
||||
{ ...props }
|
||||
id = { uid }
|
||||
key = { uid }
|
||||
uid = { uid } />
|
||||
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<FlagGroup onDismissed = { this._onDismissed }>
|
||||
{ flags }
|
||||
{ this._renderFlags() }
|
||||
</FlagGroup>
|
||||
);
|
||||
}
|
||||
|
@ -131,6 +127,38 @@ class NotificationsContainer extends Component {
|
|||
|
||||
this.props.dispatch(hideNotification(flagUid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders notifications to display as ReactElements. An empty array will
|
||||
* be returned if notifications are disabled.
|
||||
*
|
||||
* @private
|
||||
* @returns {ReactElement[]}
|
||||
*/
|
||||
_renderFlags() {
|
||||
const { _notifications, _showNotifications } = this.props;
|
||||
|
||||
if (!_showNotifications) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _notifications.map(notification => {
|
||||
const Notification = notification.component;
|
||||
const { props, uid } = notification;
|
||||
|
||||
// The id attribute is necessary as {@code FlagGroup} looks for
|
||||
// either id or key to set a key on notifications, but accessing
|
||||
// props.key will cause React to print an error.
|
||||
return (
|
||||
<Notification
|
||||
{ ...props }
|
||||
id = { uid }
|
||||
key = { uid }
|
||||
uid = { uid } />
|
||||
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,8 +172,25 @@ class NotificationsContainer extends Component {
|
|||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
// TODO: Per existing behavior, notifications should not display when an
|
||||
// overlay is visible. This logic for checking overlay display can likely be
|
||||
// simplified.
|
||||
const {
|
||||
connectionEstablished,
|
||||
haveToReload,
|
||||
isMediaPermissionPromptVisible,
|
||||
suspendDetected
|
||||
} = state['features/overlay'];
|
||||
const isAnyOverlayVisible = (connectionEstablished && haveToReload)
|
||||
|| isMediaPermissionPromptVisible
|
||||
|| suspendDetected
|
||||
|| state['features/jwt'].callOverlayVisible;
|
||||
|
||||
const { enabled, notifications } = state['features/notifications'];
|
||||
|
||||
return {
|
||||
_notifications: state['features/notifications']
|
||||
_notifications: notifications,
|
||||
_showNotifications: enabled && !isAnyOverlayVisible
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import { ReducerRegistry } from '../base/redux';
|
|||
|
||||
import {
|
||||
HIDE_NOTIFICATION,
|
||||
SET_NOTIFICATIONS_ENABLED,
|
||||
SHOW_NOTIFICATION
|
||||
} from './actionTypes';
|
||||
|
||||
|
@ -10,7 +11,10 @@ import {
|
|||
*
|
||||
* @type {array}
|
||||
*/
|
||||
const DEFAULT_STATE = [];
|
||||
const DEFAULT_STATE = {
|
||||
enabled: true,
|
||||
notifications: []
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces redux actions which affect the display of notifications.
|
||||
|
@ -24,19 +28,31 @@ ReducerRegistry.register('features/notifications',
|
|||
(state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case HIDE_NOTIFICATION:
|
||||
return state.filter(
|
||||
notification => notification.uid !== action.uid);
|
||||
return {
|
||||
...state,
|
||||
notifications: state.notifications.filter(
|
||||
notification => notification.uid !== action.uid)
|
||||
};
|
||||
|
||||
case SET_NOTIFICATIONS_ENABLED:
|
||||
return {
|
||||
...state,
|
||||
enabled: action.enabled
|
||||
};
|
||||
|
||||
case SHOW_NOTIFICATION:
|
||||
return [
|
||||
return {
|
||||
...state,
|
||||
{
|
||||
component: action.component,
|
||||
props: action.props,
|
||||
timeout: action.timeout,
|
||||
uid: action.uid
|
||||
}
|
||||
];
|
||||
notifications: [
|
||||
...state.notifications,
|
||||
{
|
||||
component: action.component,
|
||||
props: action.props,
|
||||
timeout: action.timeout,
|
||||
uid: action.uid
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -11,7 +11,6 @@ import UserMediaPermissionsFilmstripOnlyOverlay
|
|||
from './UserMediaPermissionsFilmstripOnlyOverlay';
|
||||
import UserMediaPermissionsOverlay from './UserMediaPermissionsOverlay';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
|
@ -133,23 +132,6 @@ class OverlayContainer extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* React Component method that executes once component is updated.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {void}
|
||||
* @protected
|
||||
*/
|
||||
componentDidUpdate() {
|
||||
if (typeof APP === 'object') {
|
||||
APP.UI.overlayVisible
|
||||
= (this.props._connectionEstablished
|
||||
&& this.props._haveToReload)
|
||||
|| this.props._suspendDetected
|
||||
|| this.props._isMediaPermissionPromptVisible;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue