diff --git a/conference.js b/conference.js index 11fec902e..d6fd9872a 100644 --- a/conference.js +++ b/conference.js @@ -123,7 +123,11 @@ import { maybeOpenFeedbackDialog, submitFeedback } from './react/features/feedback'; -import { isModerationNotificationDisplayed, showNotification } from './react/features/notifications'; +import { + isModerationNotificationDisplayed, + showNotification, + NOTIFICATION_TIMEOUT_TYPE +} from './react/features/notifications'; import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay'; import { suspendDetected } from './react/features/power-monitor'; import { @@ -357,7 +361,10 @@ class ConferenceConnector { case JitsiConferenceErrors.FOCUS_DISCONNECTED: { const [ focus, retrySec ] = params; - APP.UI.notifyFocusDisconnected(focus, retrySec); + APP.store.dispatch(showNotification({ + descriptionKey: focus, + titleKey: retrySec + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); break; } @@ -755,7 +762,7 @@ export default { APP.store.dispatch(showNotification({ descriptionKey: 'notify.startSilentDescription', titleKey: 'notify.startSilentTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } // XXX The API will take care of disconnecting from the XMPP @@ -2364,7 +2371,12 @@ export default { } Promise.allSettled(promises) - .then(() => APP.UI.notifyInitiallyMuted()); + .then(() => { + APP.store.dispatch(showNotification({ + titleKey: 'notify.mutedTitle', + descriptionKey: 'notify.muted' + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); + }); }); room.on( diff --git a/config.js b/config.js index 58e82dddf..12602b125 100644 --- a/config.js +++ b/config.js @@ -375,6 +375,13 @@ var config = { // resizeDesktopForPresenter: false // }, + // Notification timeouts + // notificationTimeouts: { + // short: 2500, + // medium: 5000, + // long: 10000 + // }, + // // Options for the recording limit notification. // recordingLimit: { // diff --git a/interface_config.js b/interface_config.js index ddcd693c6..15491df9e 100644 --- a/interface_config.js +++ b/interface_config.js @@ -225,13 +225,6 @@ var interfaceConfig = { */ // ANDROID_APP_PACKAGE: 'org.jitsi.meet', - /** - * Override the behavior of some notifications to remain displayed until - * explicitly dismissed through a user action. The value is how long, in - * milliseconds, those notifications should remain displayed. - */ - // ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT: 15000, - // List of undocumented settings /** INDICATOR_FONT_SIZES diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 6198da6aa..eb065304d 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -10,7 +10,12 @@ import { isMobileBrowser } from '../../react/features/base/environment/utils'; import { setColorAlpha } from '../../react/features/base/util'; import { setDocumentUrl } from '../../react/features/etherpad'; import { setFilmstripVisible } from '../../react/features/filmstrip'; -import { joinLeaveNotificationsDisabled, setNotificationsEnabled } from '../../react/features/notifications'; +import { + joinLeaveNotificationsDisabled, + setNotificationsEnabled, + showNotification, + NOTIFICATION_TIMEOUT_TYPE +} from '../../react/features/notifications'; import { dockToolbox, setToolboxEnabled, @@ -215,12 +220,10 @@ UI.updateUserStatus = (user, status) => { const displayName = user.getDisplayName(); - messageHandler.participantNotification( - displayName, - '', - 'connected', - 'dialOut.statusMessage', - { status: UIUtil.escapeHtml(status) }); + APP.store.dispatch(showNotification({ + titleKey: `${displayName} connected`, + descriptionKey: 'dialOut.statusMessage' + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); }; /** @@ -333,18 +336,6 @@ UI.notifyMaxUsersLimitReached = function() { }); }; -/** - * Notify user that he was automatically muted when joned the conference. - */ -UI.notifyInitiallyMuted = function() { - messageHandler.participantNotification( - null, - 'notify.mutedTitle', - 'connected', - 'notify.muted', - null); -}; - UI.handleLastNEndpoints = function(leavingIds, enteringIds) { VideoLayout.onLastNEndpointsChanged(leavingIds, enteringIds); }; @@ -363,15 +354,6 @@ UI.notifyTokenAuthFailed = function() { }); }; -UI.notifyFocusDisconnected = function(focus, retrySec) { - messageHandler.participantNotification( - null, 'notify.focus', - 'disconnected', 'notify.focusFail', - { component: focus, - ms: retrySec } - ); -}; - /** * Update list of available physical devices. */ diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js index e2d76021c..edf175959 100644 --- a/modules/UI/util/MessageHandler.js +++ b/modules/UI/util/MessageHandler.js @@ -1,9 +1,8 @@ /* global APP */ import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, - showNotification, showWarningNotification } from '../../../react/features/notifications'; @@ -48,7 +47,7 @@ const messageHandler = { * showErrorNotification action. */ showError(props) { - APP.store.dispatch(showErrorNotification(props)); + APP.store.dispatch(showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG)); }, /** @@ -58,35 +57,7 @@ const messageHandler = { * showWarningNotification action. */ showWarning(props) { - APP.store.dispatch(showWarningNotification(props)); - }, - - /** - * Displays a notification about participant action. - * @param displayName the display name of the participant that is - * associated with the notification. - * @param displayNameKey the key from the language file for the display - * name. Only used if displayName is not provided. - * @param cls css class for the notification - * @param messageKey the key from the language file for the text of the - * message. - * @param messageArguments object with the arguments for the message. - * @param optional configurations for the notification (e.g. timeout) - */ - participantNotification( // eslint-disable-line max-params - displayName, - displayNameKey, - cls, - messageKey, - messageArguments, - timeout = NOTIFICATION_TIMEOUT) { - APP.store.dispatch(showNotification({ - descriptionArguments: messageArguments, - descriptionKey: messageKey, - titleKey: displayNameKey, - title: displayName - }, - timeout)); + APP.store.dispatch(showWarningNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG)); } }; diff --git a/react/features/app/actions.js b/react/features/app/actions.js index 3d59cfd89..dc0d19ed7 100644 --- a/react/features/app/actions.js +++ b/react/features/app/actions.js @@ -25,7 +25,7 @@ import { toURLString } from '../base/util'; import { isVpaasMeeting } from '../jaas/functions'; -import { clearNotifications, showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, clearNotifications, showNotification } from '../notifications'; import { setFatalError } from '../overlay'; import { @@ -328,7 +328,7 @@ export function maybeRedirectToWelcomePage(options: Object = {}) { dispatch(showNotification({ titleArguments: { appName: getName() }, titleKey: 'dialog.thankYou' - })); + }, NOTIFICATION_TIMEOUT_TYPE.STICKY)); } // if Welcome page is enabled redirect to welcome page after 3 sec, if diff --git a/react/features/av-moderation/middleware.js b/react/features/av-moderation/middleware.js index dd8f3d7eb..788f49041 100644 --- a/react/features/av-moderation/middleware.js +++ b/react/features/av-moderation/middleware.js @@ -17,6 +17,7 @@ import { import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { + NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; @@ -106,7 +107,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { sticky: true, titleKey, uid - })); + }, NOTIFICATION_TIMEOUT_TYPE.STICKY)); break; } @@ -222,7 +223,7 @@ StateListenerRegistry.register( sticky: true, customActionNameKey: 'notify.unmute', customActionHandler: () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) - })); + }, NOTIFICATION_TIMEOUT_TYPE.STICKY)); dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID)); } }); diff --git a/react/features/base/conference/middleware.any.js b/react/features/base/conference/middleware.any.js index 5c46c01d2..31ed8f0f0 100644 --- a/react/features/base/conference/middleware.any.js +++ b/react/features/base/conference/middleware.any.js @@ -9,7 +9,7 @@ import { } from '../../analytics'; import { reloadNow } from '../../app/actions'; import { openDisplayNamePrompt } from '../../display-name'; -import { showErrorNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications'; import { CONNECTION_ESTABLISHED, CONNECTION_FAILED, connectionDisconnected } from '../connection'; import { validateJwt } from '../jwt'; import { JitsiConferenceErrors } from '../lib-jitsi-meet'; @@ -129,7 +129,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { dispatch(showErrorNotification({ description: reason, titleKey: 'dialog.sessTerminated' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); break; } @@ -138,7 +138,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { dispatch(showErrorNotification({ description: 'Restart initiated because of a bridge failure', titleKey: 'dialog.sessionRestarted' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } break; @@ -151,7 +151,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) { descriptionArguments: { msg }, descriptionKey: msg ? 'dialog.connectErrorWithMsg' : 'dialog.connectError', titleKey: 'connection.CONNFAIL' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); break; } diff --git a/react/features/base/config/configWhitelist.js b/react/features/base/config/configWhitelist.js index cb3be2af9..c49a02d0a 100644 --- a/react/features/base/config/configWhitelist.js +++ b/react/features/base/config/configWhitelist.js @@ -172,6 +172,7 @@ export default [ 'maxFullResolutionParticipants', 'mouseMoveCallbackInterval', 'notifications', + 'notificationTimeouts', 'openSharedDocumentOnJoin', 'opusMaxAverageBitrate', 'p2p', diff --git a/react/features/base/config/interfaceConfigWhitelist.js b/react/features/base/config/interfaceConfigWhitelist.js index 56eba89cd..3c48cd28e 100644 --- a/react/features/base/config/interfaceConfigWhitelist.js +++ b/react/features/base/config/interfaceConfigWhitelist.js @@ -26,7 +26,6 @@ export default [ 'DISPLAY_WELCOME_PAGE_CONTENT', 'ENABLE_DIAL_OUT', 'ENABLE_FEEDBACK_ANIMATION', - 'ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT', 'FILM_STRIP_MAX_HEIGHT', 'GENERATE_ROOMNAMES_ON_WELCOME_PAGE', 'HIDE_INVITE_MORE_HEADER', diff --git a/react/features/base/devices/middleware.js b/react/features/base/devices/middleware.js index 760dc3e82..6cac60cdf 100644 --- a/react/features/base/devices/middleware.js +++ b/react/features/base/devices/middleware.js @@ -2,7 +2,7 @@ import UIEvents from '../../../../service/UI/UIEvents'; import { processExternalDeviceRequest } from '../../device-selection'; -import { showNotification, showWarningNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification, showWarningNotification } from '../../notifications'; import { replaceAudioTrackById, replaceVideoTrackById, setDeviceStatusWarning } from '../../prejoin/actions'; import { isPrejoinPageVisible } from '../../prejoin/functions'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app'; @@ -50,8 +50,6 @@ const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = { } }; -const WARNING_DISPLAY_TIMER = 4000; - /** * A listener for device permissions changed reported from lib-jitsi-meet. */ @@ -134,7 +132,7 @@ MiddlewareRegistry.register(store => next => action => { description: additionalCameraErrorMsg, descriptionKey: cameraErrorMsg, titleKey - }, WARNING_DISPLAY_TIMER)); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); if (isPrejoinPageVisible(store.getState())) { store.dispatch(setDeviceStatusWarning(titleKey)); @@ -163,7 +161,7 @@ MiddlewareRegistry.register(store => next => action => { description: additionalMicErrorMsg, descriptionKey: micErrorMsg, titleKey - }, WARNING_DISPLAY_TIMER)); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); if (isPrejoinPageVisible(store.getState())) { store.dispatch(setDeviceStatusWarning(titleKey)); @@ -298,7 +296,7 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) { titleKey, customActionNameKey: 'notify.newDeviceAction', customActionHandler: _useDevice.bind(undefined, store, devicesArray) - })); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); } }); } diff --git a/react/features/base/participants/actions.js b/react/features/base/participants/actions.js index c3f3e9da0..537a466ac 100644 --- a/react/features/base/participants/actions.js +++ b/react/features/base/participants/actions.js @@ -1,4 +1,4 @@ -import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications'; import { set } from '../redux'; import { @@ -478,7 +478,7 @@ export function participantMutedUs(participant, track) { titleArguments: { participantDisplayName: getParticipantDisplayName(getState, participant.getId()) } - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }; } @@ -510,7 +510,7 @@ export function participantKicked(kicker, kicked) { getParticipantDisplayName(getState, kicker.getId()) }, titleKey: 'notify.kickParticipant' - }, NOTIFICATION_TIMEOUT * 2)); // leave more time for this + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); }; } diff --git a/react/features/base/participants/middleware.js b/react/features/base/participants/middleware.js index 97bbebe50..6d7d7194b 100644 --- a/react/features/base/participants/middleware.js +++ b/react/features/base/participants/middleware.js @@ -6,7 +6,7 @@ import UIEvents from '../../../../service/UI/UIEvents'; import { approveParticipant } from '../../av-moderation/actions'; import { toggleE2EE } from '../../e2ee/actions'; import { MAX_MODE } from '../../e2ee/constants'; -import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications'; import { isForceMuted } from '../../participants-pane/functions'; import { CALLING, INVITED } from '../../presence-status'; import { RAISE_HAND_SOUND_ID } from '../../reactions/constants'; @@ -562,7 +562,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne raiseHandNotification: true, concatText: true, ...action - }, NOTIFICATION_TIMEOUT * (shouldDisplayAllowAction ? 2 : 1))); + }, shouldDisplayAllowAction ? NOTIFICATION_TIMEOUT_TYPE.MEDIUM : NOTIFICATION_TIMEOUT_TYPE.SHORT)); dispatch(playSound(RAISE_HAND_SOUND_ID)); } } diff --git a/react/features/base/tracks/actions.js b/react/features/base/tracks/actions.js index 2933bc938..4868688f1 100644 --- a/react/features/base/tracks/actions.js +++ b/react/features/base/tracks/actions.js @@ -4,7 +4,7 @@ import { createTrackMutedEvent, sendAnalytics } from '../../analytics'; -import { showErrorNotification, showNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications'; import { JitsiTrackErrors, JitsiTrackEvents, createLocalTrack } from '../lib-jitsi-meet'; import { CAMERA_FACING_MODE, @@ -245,7 +245,7 @@ export function showNoDataFromSourceVideoError(jitsiTrack) { const notificationAction = await dispatch(showErrorNotification({ descriptionKey: 'dialog.cameraNotSendingData', titleKey: 'dialog.cameraNotSendingDataTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); notificationInfo = { uid: notificationAction.uid @@ -397,7 +397,7 @@ export function trackAdded(track) { const notificationAction = await dispatch(showNotification({ descriptionKey: 'dialog.micNotSendingData', titleKey: 'dialog.micNotSendingDataTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); // Set the notification ID so that other parts of the application know that this was // displayed in the context of the current device. @@ -406,7 +406,9 @@ export function trackAdded(track) { noDataFromSourceNotificationInfo = { uid: notificationAction.uid }; } else { - const timeout = setTimeout(() => dispatch(showNoDataFromSourceVideoError(track)), 5000); + const timeout = setTimeout(() => dispatch( + showNoDataFromSourceVideoError(track)), + NOTIFICATION_TIMEOUT_TYPE.MEDIUM); noDataFromSourceNotificationInfo = { timeout }; } diff --git a/react/features/conference/actions.web.js b/react/features/conference/actions.web.js index 413416c00..faf83c8b9 100644 --- a/react/features/conference/actions.web.js +++ b/react/features/conference/actions.web.js @@ -4,6 +4,7 @@ import type { Dispatch } from 'redux'; import { getParticipantDisplayName } from '../base/participants'; import { + NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE, showNotification } from '../notifications'; @@ -34,6 +35,6 @@ export function notifyKickedOut(participant: Object, _: ?Function) { // eslint-d descriptionArguments: args, titleKey: 'dialog.kickTitle', titleArguments: args - })); + }, NOTIFICATION_TIMEOUT_TYPE.STICKY)); }; } diff --git a/react/features/conference/functions.web.js b/react/features/conference/functions.web.js index a2db54596..fa56c34a6 100644 --- a/react/features/conference/functions.web.js +++ b/react/features/conference/functions.web.js @@ -1,6 +1,6 @@ import { isSuboptimalBrowser } from '../base/environment'; import { translateToHTML } from '../base/i18n'; -import { showWarningNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showWarningNotification } from '../notifications'; export * from './functions.any'; @@ -24,7 +24,7 @@ export function maybeShowSuboptimalExperienceNotification(dispatch, t) { recommendedBrowserPageLink: `${window.location.origin}/static/recommendedBrowsers.html` } ) - } + }, NOTIFICATION_TIMEOUT_TYPE.LONG ) ); } diff --git a/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js b/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js index 79bad8619..2c115ef2a 100644 --- a/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js +++ b/react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js @@ -4,7 +4,7 @@ import { Component } from 'react'; import { createInviteDialogEvent, sendAnalytics } from '../../../analytics'; import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../../notifications'; import { invite } from '../../actions'; @@ -203,7 +203,7 @@ export default class AbstractAddPeopleDialog if (notificationProps) { dispatch( - showNotification(notificationProps, NOTIFICATION_TIMEOUT)); + showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT)); } } diff --git a/react/features/lobby/middleware.js b/react/features/lobby/middleware.js index 9cd506be4..020dbe02a 100644 --- a/react/features/lobby/middleware.js +++ b/react/features/lobby/middleware.js @@ -9,7 +9,11 @@ import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/pa import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { isTestModeEnabled } from '../base/testing'; -import { NOTIFICATION_TYPE, showNotification } from '../notifications'; +import { + NOTIFICATION_TIMEOUT_TYPE, + NOTIFICATION_TYPE, + showNotification +} from '../notifications'; import { shouldAutoKnock } from '../prejoin/functions'; import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes'; @@ -66,10 +70,12 @@ StateListenerRegistry.register( conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => { batch(() => { - dispatch(participantIsKnockingOrUpdated({ - id, - name - })); + dispatch( + participantIsKnockingOrUpdated({ + id, + name + }) + ); dispatch(playSound(KNOCKING_PARTICIPANT_SOUND_ID)); if (typeof APP !== 'undefined') { APP.API.notifyKnockingParticipant({ @@ -81,10 +87,12 @@ StateListenerRegistry.register( }); conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => { - dispatch(participantIsKnockingOrUpdated({ - ...participant, - id - })); + dispatch( + participantIsKnockingOrUpdated({ + ...participant, + id + }) + ); }); conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => { @@ -98,7 +106,8 @@ StateListenerRegistry.register( }) ); } - }); + } +); /** * Function to handle the conference failed event and navigate the user to the lobby screen @@ -135,11 +144,13 @@ function _conferenceFailed({ dispatch, getState }, next, action) { dispatch(hideLobbyScreen()); if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) { - dispatch(showNotification({ - appearance: NOTIFICATION_TYPE.ERROR, - hideErrorSupportLink: true, - titleKey: 'lobby.joinRejectedMessage' - })); + dispatch( + showNotification({ + appearance: NOTIFICATION_TYPE.ERROR, + hideErrorSupportLink: true, + titleKey: 'lobby.joinRejectedMessage' + }, NOTIFICATION_TIMEOUT_TYPE.LONG) + ); } return next(action); @@ -174,10 +185,12 @@ function _findLoadableAvatarForKnockingParticipant(store, { id }) { if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) { getFirstLoadableAvatarUrl(updatedParticipant, store).then(loadableAvatarUrl => { if (loadableAvatarUrl) { - dispatch(participantIsKnockingOrUpdated({ - loadableAvatarUrl, - id - })); + dispatch( + participantIsKnockingOrUpdated({ + loadableAvatarUrl, + id + }) + ); } }); } @@ -217,5 +230,10 @@ function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) { break; } - dispatch(showNotification(notificationProps, isTestModeEnabled(getState()) ? undefined : 5000)); + dispatch( + showNotification( + notificationProps, + isTestModeEnabled(getState()) ? NOTIFICATION_TIMEOUT_TYPE.STICKY : NOTIFICATION_TIMEOUT_TYPE.MEDIUM + ) + ); } diff --git a/react/features/local-recording/middleware.js b/react/features/local-recording/middleware.js index 6c8f418aa..030216e09 100644 --- a/react/features/local-recording/middleware.js +++ b/react/features/local-recording/middleware.js @@ -8,6 +8,7 @@ import { i18next } from '../base/i18n'; import { SET_AUDIO_MUTED } from '../base/media/actionTypes'; import { MiddlewareRegistry } from '../base/redux'; import { SETTINGS_UPDATED } from '../base/settings/actionTypes'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications'; import { showNotification } from '../notifications/actions'; import { localRecordingEngaged, localRecordingUnengaged } from './actions'; @@ -48,14 +49,14 @@ MiddlewareRegistry.register(({ getState, dispatch }) => next => action => { dispatch(showNotification({ titleKey: 'localRecording.localRecording', description: i18next.t(messageKey, messageParams) - }, 10000)); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }; recordingController.onNotify = (messageKey, messageParams) => { dispatch(showNotification({ titleKey: 'localRecording.localRecording', description: i18next.t(messageKey, messageParams) - }, 10000)); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }; typeof APP === 'object' && typeof APP.keyboardshortcut === 'object' diff --git a/react/features/no-audio-signal/middleware.js b/react/features/no-audio-signal/middleware.js index 221c98226..66e02c373 100644 --- a/react/features/no-audio-signal/middleware.js +++ b/react/features/no-audio-signal/middleware.js @@ -12,7 +12,7 @@ import JitsiMeetJS, { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { MiddlewareRegistry } from '../base/redux'; import { updateSettings } from '../base/settings'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; -import { hideNotification, showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; import { setNoAudioSignalNotificationUid } from './actions'; import DialInLink from './components/DialInLink'; @@ -114,7 +114,7 @@ async function _handleNoAudioSignalNotification({ dispatch, getState }, action) descriptionKey, customActionNameKey, customActionHandler - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); dispatch(playSound(NO_AUDIO_SIGNAL_SOUND_ID)); diff --git a/react/features/noise-detection/middleware.js b/react/features/noise-detection/middleware.js index c56846535..a25650a56 100644 --- a/react/features/noise-detection/middleware.js +++ b/react/features/noise-detection/middleware.js @@ -5,7 +5,7 @@ import { CONFERENCE_JOINED } from '../base/conference'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { MiddlewareRegistry } from '../base/redux'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; -import { hideNotification, showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; import { setNoisyAudioInputNotificationUid } from './actions'; import { NOISY_AUDIO_INPUT_SOUND_ID } from './constants'; @@ -41,7 +41,7 @@ MiddlewareRegistry.register(store => next => action => { const notification = await dispatch(showNotification({ titleKey: 'toolbar.noisyAudioInputTitle', descriptionKey: 'toolbar.noisyAudioInputDesc' - })); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); dispatch(playSound(NOISY_AUDIO_INPUT_SOUND_ID)); diff --git a/react/features/notifications/actions.js b/react/features/notifications/actions.js index 5f2fa93bd..732d46ac6 100644 --- a/react/features/notifications/actions.js +++ b/react/features/notifications/actions.js @@ -14,11 +14,31 @@ import { SHOW_NOTIFICATION } from './actionTypes'; import { + NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TIMEOUT, NOTIFICATION_TYPE, SILENT_JOIN_THRESHOLD } from './constants'; +/** + * Function that returns notification timeout value based on notification timeout type. + * + * @param {string} type - Notification type. + * @param {Object} notificationTimeouts - Config notification timeouts. + * @returns {number} + */ +function getNotificationTimeout(type: ?string, notificationTimeouts: ?Object) { + if (type === NOTIFICATION_TIMEOUT_TYPE.SHORT) { + return notificationTimeouts?.short ?? NOTIFICATION_TIMEOUT.SHORT; + } else if (type === NOTIFICATION_TIMEOUT_TYPE.MEDIUM) { + return notificationTimeouts?.medium ?? NOTIFICATION_TIMEOUT.MEDIUM; + } else if (type === NOTIFICATION_TIMEOUT_TYPE.LONG) { + return notificationTimeouts?.long ?? NOTIFICATION_TIMEOUT.LONG; + } + + return NOTIFICATION_TIMEOUT.STICKY; +} + /** * Clears (removes) all the notifications. * @@ -82,26 +102,26 @@ export function setNotificationsEnabled(enabled: boolean) { * Queues an error notification for display. * * @param {Object} props - The props needed to show the notification component. + * @param {string} type - Notification type. * @returns {Object} */ -export function showErrorNotification(props: Object) { +export function showErrorNotification(props: Object, type: ?string) { return showNotification({ ...props, appearance: NOTIFICATION_TYPE.ERROR - }); + }, type); } /** * Queues a notification for display. * * @param {Object} props - The props needed to show the notification component. - * @param {number} timeout - How long the notification should display before - * automatically being hidden. + * @param {string} type - Notification type. * @returns {Function} */ -export function showNotification(props: Object = {}, timeout: ?number) { +export function showNotification(props: Object = {}, type: ?string) { return function(dispatch: Function, getState: Function) { - const { notifications } = getState()['features/base/config']; + const { notifications, notificationTimeouts } = getState()['features/base/config']; const enabledFlag = getFeatureFlag(getState(), NOTIFICATIONS_ENABLED, true); const shouldDisplay = enabledFlag @@ -113,7 +133,7 @@ export function showNotification(props: Object = {}, timeout: ?number) { return dispatch({ type: SHOW_NOTIFICATION, props, - timeout, + timeout: getNotificationTimeout(type, notificationTimeouts), uid: props.uid || window.Date.now().toString() }); } @@ -124,15 +144,15 @@ export function showNotification(props: Object = {}, timeout: ?number) { * Queues a warning notification for display. * * @param {Object} props - The props needed to show the notification component. - * @param {number} timeout - How long the notification should display before - * automatically being hidden. + * @param {string} type - Notification type. * @returns {Object} */ -export function showWarningNotification(props: Object, timeout: ?number) { +export function showWarningNotification(props: Object, type: ?string) { + return showNotification({ ...props, appearance: NOTIFICATION_TYPE.WARNING - }, timeout); + }, type); } /** @@ -192,7 +212,7 @@ const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch, if (notificationProps) { dispatch( - showNotification(notificationProps, NOTIFICATION_TIMEOUT)); + showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT)); } joinedParticipantsNames = []; diff --git a/react/features/notifications/components/web/NotificationsContainer.js b/react/features/notifications/components/web/NotificationsContainer.js index 29f71eadc..fa51c30a2 100644 --- a/react/features/notifications/components/web/NotificationsContainer.js +++ b/react/features/notifications/components/web/NotificationsContainer.js @@ -13,8 +13,6 @@ import { areThereNotifications } from '../../functions'; import Notification from './Notification'; -declare var interfaceConfig: Object; - type Props = { /** @@ -33,12 +31,6 @@ type Props = { */ _notifications: Array, - /** - * The length, in milliseconds, to use as a default timeout for all - * dismissible timeouts that do not have a timeout specified. - */ - autoDismissTimeout: number, - /** * JSS classes object. */ @@ -260,14 +252,14 @@ class NotificationsContainer extends Component { * @returns {void} */ _updateTimeouts() { - const { _notifications, autoDismissTimeout } = this.props; + const { _notifications } = this.props; for (const notification of _notifications) { - if ((notification.timeout || typeof autoDismissTimeout === 'number') + if (notification.timeout && notification.props.isDismissAllowed !== false && !this._timeouts.has(notification.uid)) { const { - timeout = autoDismissTimeout, + timeout, uid } = notification; const timerID = setTimeout(() => { @@ -296,8 +288,7 @@ function _mapStateToProps(state) { return { _iAmSipGateway: Boolean(iAmSipGateway), _isChatOpen: isChatOpen, - _notifications: _visible ? notifications : [], - autoDismissTimeout: interfaceConfig.ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT + _notifications: _visible ? notifications : [] }; } diff --git a/react/features/notifications/constants.js b/react/features/notifications/constants.js index 73213206d..cfe31cf0b 100644 --- a/react/features/notifications/constants.js +++ b/react/features/notifications/constants.js @@ -3,7 +3,22 @@ /** * The standard time when auto-disappearing notifications should disappear. */ -export const NOTIFICATION_TIMEOUT = 2500; +export const NOTIFICATION_TIMEOUT = { + SHORT: 2500, + MEDIUM: 5000, + LONG: 10000, + STICKY: false +}; + +/** + * Notification timeout type. + */ +export const NOTIFICATION_TIMEOUT_TYPE = { + SHORT: 'short', + MEDIUM: 'medium', + LONG: 'long', + STICKY: 'sticky' +}; /** * The set of possible notification types. diff --git a/react/features/notifications/middleware.js b/react/features/notifications/middleware.js index b6bf69962..e7cde811f 100644 --- a/react/features/notifications/middleware.js +++ b/react/features/notifications/middleware.js @@ -19,7 +19,7 @@ import { showNotification, showParticipantJoinedNotification } from './actions'; -import { NOTIFICATION_TIMEOUT } from './constants'; +import { NOTIFICATION_TIMEOUT_TYPE } from './constants'; import { joinLeaveNotificationsDisabled } from './functions'; declare var interfaceConfig: Object; @@ -54,15 +54,12 @@ MiddlewareRegistry.register(store => next => action => { action.participant.id ); - if (typeof interfaceConfig === 'object' - && participant - && !participant.local - && !action.participant.isReplaced) { + if (participant && !participant.local && !action.participant.isReplaced) { store.dispatch(showNotification({ descriptionKey: 'notify.disconnected', titleKey: 'notify.somebody', title: participant.name - }, NOTIFICATION_TIMEOUT)); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); } } @@ -91,7 +88,7 @@ MiddlewareRegistry.register(store => next => action => { store.dispatch(showNotification({ titleKey: 'notify.moderator' }, - NOTIFICATION_TIMEOUT)); + NOTIFICATION_TIMEOUT_TYPE.SHORT)); } return next(action); diff --git a/react/features/old-client-notification/middleware.js b/react/features/old-client-notification/middleware.js index 807fc1b98..3a734a1b8 100644 --- a/react/features/old-client-notification/middleware.js +++ b/react/features/old-client-notification/middleware.js @@ -4,7 +4,7 @@ import React from 'react'; import { APP_WILL_MOUNT } from '../base/app'; import { MiddlewareRegistry } from '../base/redux'; -import { showErrorNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../notifications'; import { OldElectronAPPNotificationDescription } from './components'; import { isOldJitsiMeetElectronApp } from './functions'; @@ -36,7 +36,7 @@ function _appWillMount(store, next, action) { dispatch(showErrorNotification({ titleKey: 'notify.OldElectronAPPTitle', description: - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } return next(action); diff --git a/react/features/polls/subscriber.js b/react/features/polls/subscriber.js index 6c49e4673..55c6fa46a 100644 --- a/react/features/polls/subscriber.js +++ b/react/features/polls/subscriber.js @@ -4,7 +4,7 @@ import { getCurrentConference } from '../base/conference'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { StateListenerRegistry } from '../base/redux'; import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE, showNotification } from '../notifications'; @@ -83,7 +83,7 @@ StateListenerRegistry.register( appearance: NOTIFICATION_TYPE.NORMAL, titleKey: 'polls.notification.title', descriptionKey: 'polls.notification.description' - }, NOTIFICATION_TIMEOUT)); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); break; } diff --git a/react/features/prejoin/actions.js b/react/features/prejoin/actions.js index 9959063d9..28149f422 100644 --- a/react/features/prejoin/actions.js +++ b/react/features/prejoin/actions.js @@ -19,7 +19,7 @@ import { } from '../base/tracks'; import { openURLInBrowser } from '../base/util'; import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions'; -import { showErrorNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../notifications'; import { PREJOIN_JOINING_IN_PROGRESS, @@ -114,7 +114,7 @@ function pollForStatus( case DIAL_OUT_STATUS.DISCONNECTED: { dispatch(showErrorNotification({ titleKey: 'prejoin.errorDialOutDisconnected' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); return onFail(); } @@ -122,7 +122,7 @@ function pollForStatus( case DIAL_OUT_STATUS.FAILED: { dispatch(showErrorNotification({ titleKey: 'prejoin.errorDialOutFailed' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); return onFail(); } @@ -130,7 +130,7 @@ function pollForStatus( } catch (err) { dispatch(showErrorNotification({ titleKey: 'prejoin.errorDialOutStatus' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); logger.error('Error getting dial out status', err); onFail(); } @@ -183,7 +183,7 @@ export function dialOut(onSuccess: Function, onFail: Function) { } } - dispatch(showErrorNotification(notification)); + dispatch(showErrorNotification(notification, NOTIFICATION_TIMEOUT_TYPE.LONG)); logger.error('Error dialing out', err); onFail(); } diff --git a/react/features/reactions/middleware.js b/react/features/reactions/middleware.js index 9834fc08a..34f6f63ef 100644 --- a/react/features/reactions/middleware.js +++ b/react/features/reactions/middleware.js @@ -9,7 +9,7 @@ import { MiddlewareRegistry } from '../base/redux'; import { SETTINGS_UPDATED, updateSettings } from '../base/settings'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { getDisabledSounds } from '../base/sounds/functions.any'; -import { NOTIFICATION_TIMEOUT, showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { ADD_REACTION_BUFFER, @@ -169,7 +169,7 @@ MiddlewareRegistry.register(store => next => action => { customActionHandler: () => dispatch(updateSettings({ soundsReactions: false })) - }, NOTIFICATION_TIMEOUT)); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); break; } } diff --git a/react/features/recording/actions.any.js b/react/features/recording/actions.any.js index 2bc433db6..ace5bfc77 100644 --- a/react/features/recording/actions.any.js +++ b/react/features/recording/actions.any.js @@ -6,7 +6,7 @@ import { getLocalParticipant, getParticipantDisplayName } from '../base/particip import { copyText } from '../base/util/helpers'; import { getVpaasTenant, isVpaasMeeting } from '../jaas/functions'; import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, hideNotification, showErrorNotification, showNotification, @@ -98,7 +98,7 @@ export function showPendingRecordingNotification(streamType: string) { const notification = await dispatch(showNotification({ isDismissAllowed: false, ...dialogProps - })); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); if (notification) { dispatch(_setPendingRecordingNotificationUid(notification.uid, streamType)); @@ -113,7 +113,7 @@ export function showPendingRecordingNotification(streamType: string) { * @returns {showErrorNotification} */ export function showRecordingError(props: Object) { - return showErrorNotification(props); + return showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG); } /** @@ -149,7 +149,7 @@ export function showStoppedRecordingNotification(streamType: string, participant titleKey: 'dialog.recording' }; - return showNotification(dialogProps, NOTIFICATION_TIMEOUT); + return showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT); } /** @@ -214,14 +214,14 @@ export function showStartedRecordingNotification( } catch (err) { dispatch(showErrorNotification({ titleKey: 'recording.errorFetchingLink' - })); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); return logger.error('Could not fetch recording link', err); } } } - dispatch(showNotification(dialogProps, NOTIFICATION_TIMEOUT)); + dispatch(showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT)); }; } diff --git a/react/features/recording/actions.native.js b/react/features/recording/actions.native.js index d8de2e328..fe5b91087 100644 --- a/react/features/recording/actions.native.js +++ b/react/features/recording/actions.native.js @@ -1,7 +1,7 @@ // @flow import JitsiMeetJS from '../base/lib-jitsi-meet'; -import { showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; export * from './actions.any'; @@ -37,6 +37,6 @@ export function showRecordingLimitNotification(streamType: string) { descriptionKey, titleKey, maxLines: 2 - }, 10000)); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }; } diff --git a/react/features/recording/actions.web.js b/react/features/recording/actions.web.js index 3baef9d12..ee2701264 100644 --- a/react/features/recording/actions.web.js +++ b/react/features/recording/actions.web.js @@ -3,7 +3,7 @@ import React from 'react'; import JitsiMeetJS from '../base/lib-jitsi-meet'; -import { showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { RecordingLimitNotificationDescription } from './components'; @@ -23,5 +23,5 @@ export function showRecordingLimitNotification(streamType: string) { return showNotification({ description: , titleKey: isLiveStreaming ? 'dialog.liveStreaming' : 'dialog.recording' - }, 10000); + }, NOTIFICATION_TIMEOUT_TYPE.LONG); } diff --git a/react/features/recording/components/Recording/AbstractStartRecordingDialog.js b/react/features/recording/components/Recording/AbstractStartRecordingDialog.js index d93976bbf..a1201f4e3 100644 --- a/react/features/recording/components/Recording/AbstractStartRecordingDialog.js +++ b/react/features/recording/components/Recording/AbstractStartRecordingDialog.js @@ -13,7 +13,7 @@ import { getNewAccessToken, updateDropboxToken } from '../../../dropbox'; -import { showErrorNotification } from '../../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../../notifications'; import { toggleRequestingSubtitles } from '../../../subtitles'; import { setSelectedRecordingService } from '../../actions'; import { RECORDING_TYPES } from '../../constants'; @@ -298,7 +298,7 @@ class AbstractStartRecordingDialog extends Component { } else { dispatch(showErrorNotification({ titleKey: 'dialog.noDropboxToken' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); return; } diff --git a/react/features/remote-control/actions.js b/react/features/remote-control/actions.js index c924c18d6..3858732ff 100644 --- a/react/features/remote-control/actions.js +++ b/react/features/remote-control/actions.js @@ -4,7 +4,7 @@ import { openDialog } from '../base/dialog'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { getParticipantDisplayName, getPinnedParticipant, pinParticipant } from '../base/participants'; import { getLocalVideoTrack } from '../base/tracks'; -import { showNotification } from '../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; import { CAPTURE_EVENTS, @@ -190,7 +190,7 @@ export function processPermissionRequestReply(participantId: string, event: Obje descriptionArguments: { user: getParticipantDisplayName(state, participantId) }, descriptionKey, titleKey: 'dialog.remoteControlTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); if (permissionGranted) { // the remote control permissions has been granted @@ -269,7 +269,7 @@ export function stopController(notifyRemoteParty: boolean = false) { dispatch(showNotification({ descriptionKey: 'dialog.remoteControlStopMessage', titleKey: 'dialog.remoteControlTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }; } @@ -425,7 +425,7 @@ export function stopReceiver(dontNotifyLocalParty: boolean = false, dontNotifyRe dispatch(showNotification({ descriptionKey: 'dialog.remoteControlStopMessage', titleKey: 'dialog.remoteControlTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } }; } @@ -564,7 +564,7 @@ export function grant(participantId: string) { dispatch(showNotification({ descriptionKey: 'dialog.startRemoteControlErrorMessage', titleKey: 'dialog.remoteControlTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); dispatch(stopReceiver(true)); }); diff --git a/react/features/room-lock/middleware.js b/react/features/room-lock/middleware.js index b347b4d90..697073710 100644 --- a/react/features/room-lock/middleware.js +++ b/react/features/room-lock/middleware.js @@ -11,7 +11,7 @@ import { hideDialog } from '../base/dialog'; import { JitsiConferenceErrors } from '../base/lib-jitsi-meet'; import { MiddlewareRegistry } from '../base/redux'; import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications'; @@ -54,12 +54,12 @@ MiddlewareRegistry.register(store => next => action => { store.dispatch( showNotification({ titleKey: 'notify.passwordSetRemotely' - }, NOTIFICATION_TIMEOUT)); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); } else if (previousLockedState === LOCKED_REMOTELY && !currentLockedState) { store.dispatch( showNotification({ titleKey: 'notify.passwordRemovedRemotely' - }, NOTIFICATION_TIMEOUT)); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT)); } return result; diff --git a/react/features/shared-video/components/web/AbstractVideoManager.js b/react/features/shared-video/components/web/AbstractVideoManager.js index d23358887..43f7886b2 100644 --- a/react/features/shared-video/components/web/AbstractVideoManager.js +++ b/react/features/shared-video/components/web/AbstractVideoManager.js @@ -9,6 +9,7 @@ import { getCurrentConference } from '../../../base/conference'; import { MEDIA_TYPE } from '../../../base/media'; import { getLocalParticipant } from '../../../base/participants'; import { isLocalTrackMuted } from '../../../base/tracks'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../../../notifications'; import { showWarningNotification } from '../../../notifications/actions'; import { dockToolbox } from '../../../toolbox/actions.web'; import { muteLocal } from '../../../video-menu/actions.any'; @@ -424,7 +425,7 @@ export function _mapDispatchToProps(dispatch: Function): $Shape { _displayWarning: () => { dispatch(showWarningNotification({ titleKey: 'dialog.shareVideoLinkError' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); }, _dockToolbox: value => { dispatch(dockToolbox(value)); diff --git a/react/features/stream-effects/virtual-background/index.js b/react/features/stream-effects/virtual-background/index.js index fe754dfcb..56bacf20f 100644 --- a/react/features/stream-effects/virtual-background/index.js +++ b/react/features/stream-effects/virtual-background/index.js @@ -1,5 +1,6 @@ // @flow +import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications'; import { showWarningNotification } from '../../notifications/actions'; import { timeout } from '../../virtual-background/functions'; import logger from '../../virtual-background/logger'; @@ -62,13 +63,13 @@ export async function createVirtualBackgroundEffect(virtualBackground: Object, d logger.error('Failed to download tflite model!'); dispatch(showWarningNotification({ titleKey: 'virtualBackground.backgroundEffectError' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } else { logger.error('Looks like WebAssembly is disabled or not supported on this browser'); dispatch(showWarningNotification({ titleKey: 'virtualBackground.webAssemblyWarning', description: 'WebAssembly disabled or not supported by this browser' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); } return; diff --git a/react/features/talk-while-muted/middleware.js b/react/features/talk-while-muted/middleware.js index 06c31160c..276535e7c 100644 --- a/react/features/talk-while-muted/middleware.js +++ b/react/features/talk-while-muted/middleware.js @@ -8,6 +8,7 @@ import { getLocalParticipant, raiseHand } from '../base/participants'; import { MiddlewareRegistry } from '../base/redux'; import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { + NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications'; @@ -50,7 +51,7 @@ MiddlewareRegistry.register(store => next => action => { titleKey: 'toolbar.talkWhileMutedPopup', customActionNameKey: forceMuted ? 'notify.raiseHandAction' : 'notify.unmute', customActionHandler: () => dispatch(forceMuted ? raiseHand(true) : setAudioMuted(false)) - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); const { soundsTalkWhileMuted } = getState()['features/base/settings']; diff --git a/react/features/transcribing/actions.js b/react/features/transcribing/actions.js index 4de38a424..eb90c0bbb 100644 --- a/react/features/transcribing/actions.js +++ b/react/features/transcribing/actions.js @@ -1,7 +1,7 @@ // @flow import { - NOTIFICATION_TIMEOUT, + NOTIFICATION_TIMEOUT_TYPE, hideNotification, showErrorNotification, showNotification @@ -74,7 +74,7 @@ export function showPendingTranscribingNotification() { descriptionKey: 'transcribing.pending', isDismissAllowed: false, titleKey: 'dialog.transcribing' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); if (notification) { dispatch(setPendingTranscribingNotificationUid(notification.uid)); @@ -127,7 +127,7 @@ export function showStoppedTranscribingNotification() { return showNotification({ descriptionKey: 'transcribing.off', titleKey: 'dialog.transcribing' - }, NOTIFICATION_TIMEOUT); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT); } @@ -140,5 +140,5 @@ export function showTranscribingError() { return showErrorNotification({ descriptionKey: 'transcribing.error', titleKey: 'transcribing.failedToStart' - }); + }, NOTIFICATION_TIMEOUT_TYPE.LONG); } diff --git a/react/features/videosipgw/middleware.js b/react/features/videosipgw/middleware.js index 8624ce39d..e9bcfd773 100644 --- a/react/features/videosipgw/middleware.js +++ b/react/features/videosipgw/middleware.js @@ -7,6 +7,7 @@ import { } from '../base/lib-jitsi-meet'; import { MiddlewareRegistry } from '../base/redux'; import { + NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification, showWarningNotification @@ -103,7 +104,7 @@ function _inviteRooms(rooms, conference, dispatch) { dispatch(showErrorNotification({ descriptionKey: 'videoSIPGW.errorInvite', titleKey: 'videoSIPGW.errorInviteTitle' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); return; } @@ -111,7 +112,7 @@ function _inviteRooms(rooms, conference, dispatch) { dispatch(showWarningNotification({ titleKey: 'videoSIPGW.errorAlreadyInvited', titleArguments: { displayName } - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); return; } @@ -148,7 +149,7 @@ function _sessionStateChanged( titleArguments: { displayName: event.displayName } - }, 2000); + }, NOTIFICATION_TIMEOUT_TYPE.SHORT); } case JitsiSIPVideoGWStatus.STATE_FAILED: { return showErrorNotification({ @@ -157,14 +158,14 @@ function _sessionStateChanged( displayName: event.displayName }, descriptionKey: 'videoSIPGW.errorInviteFailed' - }); + }, NOTIFICATION_TIMEOUT_TYPE.LONG); } case JitsiSIPVideoGWStatus.STATE_OFF: { if (event.failureReason === JitsiSIPVideoGWStatus.STATUS_BUSY) { return showErrorNotification({ descriptionKey: 'videoSIPGW.busy', titleKey: 'videoSIPGW.busyTitle' - }); + }, NOTIFICATION_TIMEOUT_TYPE.LONG); } else if (event.failureReason) { logger.error(`Unknown sip videogw error ${event.newState} ${ event.failureReason}`); diff --git a/react/features/virtual-background/components/VirtualBackgroundDialog.js b/react/features/virtual-background/components/VirtualBackgroundDialog.js index c24e19d76..38f805f7d 100644 --- a/react/features/virtual-background/components/VirtualBackgroundDialog.js +++ b/react/features/virtual-background/components/VirtualBackgroundDialog.js @@ -16,7 +16,7 @@ import { connect } from '../../base/redux'; import { updateSettings } from '../../base/settings'; import { Tooltip } from '../../base/tooltip'; import { getLocalVideoTrack } from '../../base/tracks'; -import { showErrorNotification } from '../../notifications'; +import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications'; import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions'; import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants'; import { toDataURL } from '../functions'; @@ -219,7 +219,7 @@ function VirtualBackground({ if (!isCancelled) { dispatch(showErrorNotification({ titleKey: 'virtualBackground.desktopShareError' - })); + }, NOTIFICATION_TIMEOUT_TYPE.LONG)); logger.error('Could not create desktop share as a virtual background!'); } diff --git a/react/features/virtual-background/components/VirtualBackgroundPreview.js b/react/features/virtual-background/components/VirtualBackgroundPreview.js index e1cf1e91b..dc0a79567 100644 --- a/react/features/virtual-background/components/VirtualBackgroundPreview.js +++ b/react/features/virtual-background/components/VirtualBackgroundPreview.js @@ -10,6 +10,7 @@ import Video from '../../base/media/components/Video'; import { connect, equals } from '../../base/redux'; import { getCurrentCameraDeviceId } from '../../base/settings'; import { createLocalTracksF } from '../../base/tracks/functions'; +import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications'; import { showWarningNotification } from '../../notifications/actions'; import { toggleBackgroundEffect } from '../actions'; import { VIRTUAL_BACKGROUND_TYPE } from '../constants'; @@ -140,7 +141,7 @@ class VirtualBackgroundPreview extends PureComponent { showWarningNotification({ titleKey: 'virtualBackground.backgroundEffectError', description: 'Failed to access camera device.' - }) + }, NOTIFICATION_TIMEOUT_TYPE.LONG) ); logger.error('Failed to access camera device. Error on apply background effect.');