浏览代码

feat(notifications) revisit timeouts and make them configurable

master
Tudor D. Pop 3 年前
父节点
当前提交
a618697e34
没有帐户链接到提交者的电子邮件
共有 42 个文件被更改,包括 220 次插入206 次删除
  1. 16
    4
      conference.js
  2. 7
    0
      config.js
  3. 0
    7
      interface_config.js
  4. 10
    28
      modules/UI/UI.js
  5. 3
    32
      modules/UI/util/MessageHandler.js
  6. 2
    2
      react/features/app/actions.js
  7. 3
    2
      react/features/av-moderation/middleware.js
  8. 4
    4
      react/features/base/conference/middleware.any.js
  9. 1
    0
      react/features/base/config/configWhitelist.js
  10. 0
    1
      react/features/base/config/interfaceConfigWhitelist.js
  11. 4
    6
      react/features/base/devices/middleware.js
  12. 3
    3
      react/features/base/participants/actions.js
  13. 2
    2
      react/features/base/participants/middleware.js
  14. 6
    4
      react/features/base/tracks/actions.js
  15. 2
    1
      react/features/conference/actions.web.js
  16. 2
    2
      react/features/conference/functions.web.js
  17. 2
    2
      react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js
  18. 38
    20
      react/features/lobby/middleware.js
  19. 3
    2
      react/features/local-recording/middleware.js
  20. 2
    2
      react/features/no-audio-signal/middleware.js
  21. 2
    2
      react/features/noise-detection/middleware.js
  22. 32
    12
      react/features/notifications/actions.js
  23. 4
    13
      react/features/notifications/components/web/NotificationsContainer.js
  24. 16
    1
      react/features/notifications/constants.js
  25. 4
    7
      react/features/notifications/middleware.js
  26. 2
    2
      react/features/old-client-notification/middleware.js
  27. 2
    2
      react/features/polls/subscriber.js
  28. 5
    5
      react/features/prejoin/actions.js
  29. 2
    2
      react/features/reactions/middleware.js
  30. 6
    6
      react/features/recording/actions.any.js
  31. 2
    2
      react/features/recording/actions.native.js
  32. 2
    2
      react/features/recording/actions.web.js
  33. 2
    2
      react/features/recording/components/Recording/AbstractStartRecordingDialog.js
  34. 5
    5
      react/features/remote-control/actions.js
  35. 3
    3
      react/features/room-lock/middleware.js
  36. 2
    1
      react/features/shared-video/components/web/AbstractVideoManager.js
  37. 3
    2
      react/features/stream-effects/virtual-background/index.js
  38. 2
    1
      react/features/talk-while-muted/middleware.js
  39. 4
    4
      react/features/transcribing/actions.js
  40. 6
    5
      react/features/videosipgw/middleware.js
  41. 2
    2
      react/features/virtual-background/components/VirtualBackgroundDialog.js
  42. 2
    1
      react/features/virtual-background/components/VirtualBackgroundPreview.js

+ 16
- 4
conference.js 查看文件

@@ -123,7 +123,11 @@ import {
123 123
     maybeOpenFeedbackDialog,
124 124
     submitFeedback
125 125
 } from './react/features/feedback';
126
-import { isModerationNotificationDisplayed, showNotification } from './react/features/notifications';
126
+import {
127
+    isModerationNotificationDisplayed,
128
+    showNotification,
129
+    NOTIFICATION_TIMEOUT_TYPE
130
+} from './react/features/notifications';
127 131
 import { mediaPermissionPromptVisibilityChanged, toggleSlowGUMOverlay } from './react/features/overlay';
128 132
 import { suspendDetected } from './react/features/power-monitor';
129 133
 import {
@@ -357,7 +361,10 @@ class ConferenceConnector {
357 361
         case JitsiConferenceErrors.FOCUS_DISCONNECTED: {
358 362
             const [ focus, retrySec ] = params;
359 363
 
360
-            APP.UI.notifyFocusDisconnected(focus, retrySec);
364
+            APP.store.dispatch(showNotification({
365
+                descriptionKey: focus,
366
+                titleKey: retrySec
367
+            }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
361 368
             break;
362 369
         }
363 370
 
@@ -755,7 +762,7 @@ export default {
755 762
             APP.store.dispatch(showNotification({
756 763
                 descriptionKey: 'notify.startSilentDescription',
757 764
                 titleKey: 'notify.startSilentTitle'
758
-            }));
765
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
759 766
         }
760 767
 
761 768
         // XXX The API will take care of disconnecting from the XMPP
@@ -2364,7 +2371,12 @@ export default {
2364 2371
             }
2365 2372
 
2366 2373
             Promise.allSettled(promises)
2367
-                .then(() => APP.UI.notifyInitiallyMuted());
2374
+                .then(() => {
2375
+                    APP.store.dispatch(showNotification({
2376
+                        titleKey: 'notify.mutedTitle',
2377
+                        descriptionKey: 'notify.muted'
2378
+                    }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
2379
+                });
2368 2380
         });
2369 2381
 
2370 2382
         room.on(

+ 7
- 0
config.js 查看文件

@@ -375,6 +375,13 @@ var config = {
375 375
     //    resizeDesktopForPresenter: false
376 376
     // },
377 377
 
378
+    // Notification timeouts
379
+    // notificationTimeouts: {
380
+    //     short: 2500,
381
+    //     medium: 5000,
382
+    //     long: 10000
383
+    // },
384
+
378 385
     // // Options for the recording limit notification.
379 386
     // recordingLimit: {
380 387
     //

+ 0
- 7
interface_config.js 查看文件

@@ -225,13 +225,6 @@ var interfaceConfig = {
225 225
      */
226 226
     // ANDROID_APP_PACKAGE: 'org.jitsi.meet',
227 227
 
228
-    /**
229
-     * Override the behavior of some notifications to remain displayed until
230
-     * explicitly dismissed through a user action. The value is how long, in
231
-     * milliseconds, those notifications should remain displayed.
232
-     */
233
-    // ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT: 15000,
234
-
235 228
     // List of undocumented settings
236 229
     /**
237 230
      INDICATOR_FONT_SIZES

+ 10
- 28
modules/UI/UI.js 查看文件

@@ -10,7 +10,12 @@ import { isMobileBrowser } from '../../react/features/base/environment/utils';
10 10
 import { setColorAlpha } from '../../react/features/base/util';
11 11
 import { setDocumentUrl } from '../../react/features/etherpad';
12 12
 import { setFilmstripVisible } from '../../react/features/filmstrip';
13
-import { joinLeaveNotificationsDisabled, setNotificationsEnabled } from '../../react/features/notifications';
13
+import {
14
+    joinLeaveNotificationsDisabled,
15
+    setNotificationsEnabled,
16
+    showNotification,
17
+    NOTIFICATION_TIMEOUT_TYPE
18
+} from '../../react/features/notifications';
14 19
 import {
15 20
     dockToolbox,
16 21
     setToolboxEnabled,
@@ -215,12 +220,10 @@ UI.updateUserStatus = (user, status) => {
215 220
 
216 221
     const displayName = user.getDisplayName();
217 222
 
218
-    messageHandler.participantNotification(
219
-        displayName,
220
-        '',
221
-        'connected',
222
-        'dialOut.statusMessage',
223
-        { status: UIUtil.escapeHtml(status) });
223
+    APP.store.dispatch(showNotification({
224
+        titleKey: `${displayName} connected`,
225
+        descriptionKey: 'dialOut.statusMessage'
226
+    }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
224 227
 };
225 228
 
226 229
 /**
@@ -333,18 +336,6 @@ UI.notifyMaxUsersLimitReached = function() {
333 336
     });
334 337
 };
335 338
 
336
-/**
337
- * Notify user that he was automatically muted when joned the conference.
338
- */
339
-UI.notifyInitiallyMuted = function() {
340
-    messageHandler.participantNotification(
341
-        null,
342
-        'notify.mutedTitle',
343
-        'connected',
344
-        'notify.muted',
345
-        null);
346
-};
347
-
348 339
 UI.handleLastNEndpoints = function(leavingIds, enteringIds) {
349 340
     VideoLayout.onLastNEndpointsChanged(leavingIds, enteringIds);
350 341
 };
@@ -363,15 +354,6 @@ UI.notifyTokenAuthFailed = function() {
363 354
     });
364 355
 };
365 356
 
366
-UI.notifyFocusDisconnected = function(focus, retrySec) {
367
-    messageHandler.participantNotification(
368
-        null, 'notify.focus',
369
-        'disconnected', 'notify.focusFail',
370
-        { component: focus,
371
-            ms: retrySec }
372
-    );
373
-};
374
-
375 357
 /**
376 358
  * Update list of available physical devices.
377 359
  */

+ 3
- 32
modules/UI/util/MessageHandler.js 查看文件

@@ -1,9 +1,8 @@
1 1
 /* global APP */
2 2
 
3 3
 import {
4
-    NOTIFICATION_TIMEOUT,
4
+    NOTIFICATION_TIMEOUT_TYPE,
5 5
     showErrorNotification,
6
-    showNotification,
7 6
     showWarningNotification
8 7
 } from '../../../react/features/notifications';
9 8
 
@@ -48,7 +47,7 @@ const messageHandler = {
48 47
      * showErrorNotification action.
49 48
      */
50 49
     showError(props) {
51
-        APP.store.dispatch(showErrorNotification(props));
50
+        APP.store.dispatch(showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG));
52 51
     },
53 52
 
54 53
     /**
@@ -58,35 +57,7 @@ const messageHandler = {
58 57
      * showWarningNotification action.
59 58
      */
60 59
     showWarning(props) {
61
-        APP.store.dispatch(showWarningNotification(props));
62
-    },
63
-
64
-    /**
65
-     * Displays a notification about participant action.
66
-     * @param displayName the display name of the participant that is
67
-     * associated with the notification.
68
-     * @param displayNameKey the key from the language file for the display
69
-     * name. Only used if displayName is not provided.
70
-     * @param cls css class for the notification
71
-     * @param messageKey the key from the language file for the text of the
72
-     * message.
73
-     * @param messageArguments object with the arguments for the message.
74
-     * @param optional configurations for the notification (e.g. timeout)
75
-     */
76
-    participantNotification( // eslint-disable-line max-params
77
-            displayName,
78
-            displayNameKey,
79
-            cls,
80
-            messageKey,
81
-            messageArguments,
82
-            timeout = NOTIFICATION_TIMEOUT) {
83
-        APP.store.dispatch(showNotification({
84
-            descriptionArguments: messageArguments,
85
-            descriptionKey: messageKey,
86
-            titleKey: displayNameKey,
87
-            title: displayName
88
-        },
89
-        timeout));
60
+        APP.store.dispatch(showWarningNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG));
90 61
     }
91 62
 };
92 63
 

+ 2
- 2
react/features/app/actions.js 查看文件

@@ -25,7 +25,7 @@ import {
25 25
     toURLString
26 26
 } from '../base/util';
27 27
 import { isVpaasMeeting } from '../jaas/functions';
28
-import { clearNotifications, showNotification } from '../notifications';
28
+import { NOTIFICATION_TIMEOUT_TYPE, clearNotifications, showNotification } from '../notifications';
29 29
 import { setFatalError } from '../overlay';
30 30
 
31 31
 import {
@@ -328,7 +328,7 @@ export function maybeRedirectToWelcomePage(options: Object = {}) {
328 328
             dispatch(showNotification({
329 329
                 titleArguments: { appName: getName() },
330 330
                 titleKey: 'dialog.thankYou'
331
-            }));
331
+            }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
332 332
         }
333 333
 
334 334
         // if Welcome page is enabled redirect to welcome page after 3 sec, if

+ 3
- 2
react/features/av-moderation/middleware.js 查看文件

@@ -17,6 +17,7 @@ import {
17 17
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
18 18
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
19 19
 import {
20
+    NOTIFICATION_TIMEOUT_TYPE,
20 21
     hideNotification,
21 22
     showNotification
22 23
 } from '../notifications';
@@ -106,7 +107,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
106 107
             sticky: true,
107 108
             titleKey,
108 109
             uid
109
-        }));
110
+        }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
110 111
 
111 112
         break;
112 113
     }
@@ -222,7 +223,7 @@ StateListenerRegistry.register(
222 223
                         sticky: true,
223 224
                         customActionNameKey: 'notify.unmute',
224 225
                         customActionHandler: () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO))
225
-                    }));
226
+                    }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
226 227
                     dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID));
227 228
                 }
228 229
             });

+ 4
- 4
react/features/base/conference/middleware.any.js 查看文件

@@ -9,7 +9,7 @@ import {
9 9
 } from '../../analytics';
10 10
 import { reloadNow } from '../../app/actions';
11 11
 import { openDisplayNamePrompt } from '../../display-name';
12
-import { showErrorNotification } from '../../notifications';
12
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications';
13 13
 import { CONNECTION_ESTABLISHED, CONNECTION_FAILED, connectionDisconnected } from '../connection';
14 14
 import { validateJwt } from '../jwt';
15 15
 import { JitsiConferenceErrors } from '../lib-jitsi-meet';
@@ -129,7 +129,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
129 129
         dispatch(showErrorNotification({
130 130
             description: reason,
131 131
             titleKey: 'dialog.sessTerminated'
132
-        }));
132
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
133 133
 
134 134
         break;
135 135
     }
@@ -138,7 +138,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
138 138
             dispatch(showErrorNotification({
139 139
                 description: 'Restart initiated because of a bridge failure',
140 140
                 titleKey: 'dialog.sessionRestarted'
141
-            }));
141
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
142 142
         }
143 143
 
144 144
         break;
@@ -151,7 +151,7 @@ function _conferenceFailed({ dispatch, getState }, next, action) {
151 151
             descriptionArguments: { msg },
152 152
             descriptionKey: msg ? 'dialog.connectErrorWithMsg' : 'dialog.connectError',
153 153
             titleKey: 'connection.CONNFAIL'
154
-        }));
154
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
155 155
 
156 156
         break;
157 157
     }

+ 1
- 0
react/features/base/config/configWhitelist.js 查看文件

@@ -172,6 +172,7 @@ export default [
172 172
     'maxFullResolutionParticipants',
173 173
     'mouseMoveCallbackInterval',
174 174
     'notifications',
175
+    'notificationTimeouts',
175 176
     'openSharedDocumentOnJoin',
176 177
     'opusMaxAverageBitrate',
177 178
     'p2p',

+ 0
- 1
react/features/base/config/interfaceConfigWhitelist.js 查看文件

@@ -26,7 +26,6 @@ export default [
26 26
     'DISPLAY_WELCOME_PAGE_CONTENT',
27 27
     'ENABLE_DIAL_OUT',
28 28
     'ENABLE_FEEDBACK_ANIMATION',
29
-    'ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT',
30 29
     'FILM_STRIP_MAX_HEIGHT',
31 30
     'GENERATE_ROOMNAMES_ON_WELCOME_PAGE',
32 31
     'HIDE_INVITE_MORE_HEADER',

+ 4
- 6
react/features/base/devices/middleware.js 查看文件

@@ -2,7 +2,7 @@
2 2
 
3 3
 import UIEvents from '../../../../service/UI/UIEvents';
4 4
 import { processExternalDeviceRequest } from '../../device-selection';
5
-import { showNotification, showWarningNotification } from '../../notifications';
5
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification, showWarningNotification } from '../../notifications';
6 6
 import { replaceAudioTrackById, replaceVideoTrackById, setDeviceStatusWarning } from '../../prejoin/actions';
7 7
 import { isPrejoinPageVisible } from '../../prejoin/functions';
8 8
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
@@ -50,8 +50,6 @@ const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
50 50
     }
51 51
 };
52 52
 
53
-const WARNING_DISPLAY_TIMER = 4000;
54
-
55 53
 /**
56 54
  * A listener for device permissions changed reported from lib-jitsi-meet.
57 55
  */
@@ -134,7 +132,7 @@ MiddlewareRegistry.register(store => next => action => {
134 132
             description: additionalCameraErrorMsg,
135 133
             descriptionKey: cameraErrorMsg,
136 134
             titleKey
137
-        }, WARNING_DISPLAY_TIMER));
135
+        }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
138 136
 
139 137
         if (isPrejoinPageVisible(store.getState())) {
140 138
             store.dispatch(setDeviceStatusWarning(titleKey));
@@ -163,7 +161,7 @@ MiddlewareRegistry.register(store => next => action => {
163 161
             description: additionalMicErrorMsg,
164 162
             descriptionKey: micErrorMsg,
165 163
             titleKey
166
-        }, WARNING_DISPLAY_TIMER));
164
+        }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
167 165
 
168 166
         if (isPrejoinPageVisible(store.getState())) {
169 167
             store.dispatch(setDeviceStatusWarning(titleKey));
@@ -298,7 +296,7 @@ function _checkAndNotifyForNewDevice(store, newDevices, oldDevices) {
298 296
                 titleKey,
299 297
                 customActionNameKey: 'notify.newDeviceAction',
300 298
                 customActionHandler: _useDevice.bind(undefined, store, devicesArray)
301
-            }));
299
+            }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
302 300
         }
303 301
     });
304 302
 }

+ 3
- 3
react/features/base/participants/actions.js 查看文件

@@ -1,4 +1,4 @@
1
-import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications';
1
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications';
2 2
 import { set } from '../redux';
3 3
 
4 4
 import {
@@ -478,7 +478,7 @@ export function participantMutedUs(participant, track) {
478 478
             titleArguments: {
479 479
                 participantDisplayName: getParticipantDisplayName(getState, participant.getId())
480 480
             }
481
-        }));
481
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
482 482
     };
483 483
 }
484 484
 
@@ -510,7 +510,7 @@ export function participantKicked(kicker, kicked) {
510 510
                     getParticipantDisplayName(getState, kicker.getId())
511 511
             },
512 512
             titleKey: 'notify.kickParticipant'
513
-        }, NOTIFICATION_TIMEOUT * 2)); // leave more time for this
513
+        }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
514 514
     };
515 515
 }
516 516
 

+ 2
- 2
react/features/base/participants/middleware.js 查看文件

@@ -6,7 +6,7 @@ import UIEvents from '../../../../service/UI/UIEvents';
6 6
 import { approveParticipant } from '../../av-moderation/actions';
7 7
 import { toggleE2EE } from '../../e2ee/actions';
8 8
 import { MAX_MODE } from '../../e2ee/constants';
9
-import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications';
9
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../../notifications';
10 10
 import { isForceMuted } from '../../participants-pane/functions';
11 11
 import { CALLING, INVITED } from '../../presence-status';
12 12
 import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
@@ -562,7 +562,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
562 562
             raiseHandNotification: true,
563 563
             concatText: true,
564 564
             ...action
565
-        }, NOTIFICATION_TIMEOUT * (shouldDisplayAllowAction ? 2 : 1)));
565
+        }, shouldDisplayAllowAction ? NOTIFICATION_TIMEOUT_TYPE.MEDIUM : NOTIFICATION_TIMEOUT_TYPE.SHORT));
566 566
         dispatch(playSound(RAISE_HAND_SOUND_ID));
567 567
     }
568 568
 }

+ 6
- 4
react/features/base/tracks/actions.js 查看文件

@@ -4,7 +4,7 @@ import {
4 4
     createTrackMutedEvent,
5 5
     sendAnalytics
6 6
 } from '../../analytics';
7
-import { showErrorNotification, showNotification } from '../../notifications';
7
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications';
8 8
 import { JitsiTrackErrors, JitsiTrackEvents, createLocalTrack } from '../lib-jitsi-meet';
9 9
 import {
10 10
     CAMERA_FACING_MODE,
@@ -245,7 +245,7 @@ export function showNoDataFromSourceVideoError(jitsiTrack) {
245 245
             const notificationAction = await dispatch(showErrorNotification({
246 246
                 descriptionKey: 'dialog.cameraNotSendingData',
247 247
                 titleKey: 'dialog.cameraNotSendingDataTitle'
248
-            }));
248
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
249 249
 
250 250
             notificationInfo = {
251 251
                 uid: notificationAction.uid
@@ -397,7 +397,7 @@ export function trackAdded(track) {
397 397
                     const notificationAction = await dispatch(showNotification({
398 398
                         descriptionKey: 'dialog.micNotSendingData',
399 399
                         titleKey: 'dialog.micNotSendingDataTitle'
400
-                    }));
400
+                    }, NOTIFICATION_TIMEOUT_TYPE.LONG));
401 401
 
402 402
                     // Set the notification ID so that other parts of the application know that this was
403 403
                     // displayed in the context of the current device.
@@ -406,7 +406,9 @@ export function trackAdded(track) {
406 406
 
407 407
                     noDataFromSourceNotificationInfo = { uid: notificationAction.uid };
408 408
                 } else {
409
-                    const timeout = setTimeout(() => dispatch(showNoDataFromSourceVideoError(track)), 5000);
409
+                    const timeout = setTimeout(() => dispatch(
410
+                        showNoDataFromSourceVideoError(track)),
411
+                        NOTIFICATION_TIMEOUT_TYPE.MEDIUM);
410 412
 
411 413
                     noDataFromSourceNotificationInfo = { timeout };
412 414
                 }

+ 2
- 1
react/features/conference/actions.web.js 查看文件

@@ -4,6 +4,7 @@ import type { Dispatch } from 'redux';
4 4
 
5 5
 import { getParticipantDisplayName } from '../base/participants';
6 6
 import {
7
+    NOTIFICATION_TIMEOUT_TYPE,
7 8
     NOTIFICATION_TYPE,
8 9
     showNotification
9 10
 } from '../notifications';
@@ -34,6 +35,6 @@ export function notifyKickedOut(participant: Object, _: ?Function) { // eslint-d
34 35
             descriptionArguments: args,
35 36
             titleKey: 'dialog.kickTitle',
36 37
             titleArguments: args
37
-        }));
38
+        }, NOTIFICATION_TIMEOUT_TYPE.STICKY));
38 39
     };
39 40
 }

+ 2
- 2
react/features/conference/functions.web.js 查看文件

@@ -1,6 +1,6 @@
1 1
 import { isSuboptimalBrowser } from '../base/environment';
2 2
 import { translateToHTML } from '../base/i18n';
3
-import { showWarningNotification } from '../notifications';
3
+import { NOTIFICATION_TIMEOUT_TYPE, showWarningNotification } from '../notifications';
4 4
 
5 5
 export * from './functions.any';
6 6
 
@@ -24,7 +24,7 @@ export function maybeShowSuboptimalExperienceNotification(dispatch, t) {
24 24
                             recommendedBrowserPageLink: `${window.location.origin}/static/recommendedBrowsers.html`
25 25
                         }
26 26
                     )
27
-                }
27
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG
28 28
             )
29 29
         );
30 30
     }

+ 2
- 2
react/features/invite/components/add-people-dialog/AbstractAddPeopleDialog.js 查看文件

@@ -4,7 +4,7 @@ import { Component } from 'react';
4 4
 
5 5
 import { createInviteDialogEvent, sendAnalytics } from '../../../analytics';
6 6
 import {
7
-    NOTIFICATION_TIMEOUT,
7
+    NOTIFICATION_TIMEOUT_TYPE,
8 8
     showNotification
9 9
 } from '../../../notifications';
10 10
 import { invite } from '../../actions';
@@ -203,7 +203,7 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
203 203
 
204 204
                     if (notificationProps) {
205 205
                         dispatch(
206
-                            showNotification(notificationProps, NOTIFICATION_TIMEOUT));
206
+                            showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
207 207
                     }
208 208
                 }
209 209
 

+ 38
- 20
react/features/lobby/middleware.js 查看文件

@@ -9,7 +9,11 @@ import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/pa
9 9
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
10 10
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
11 11
 import { isTestModeEnabled } from '../base/testing';
12
-import { NOTIFICATION_TYPE, showNotification } from '../notifications';
12
+import {
13
+    NOTIFICATION_TIMEOUT_TYPE,
14
+    NOTIFICATION_TYPE,
15
+    showNotification
16
+} from '../notifications';
13 17
 import { shouldAutoKnock } from '../prejoin/functions';
14 18
 
15 19
 import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes';
@@ -66,10 +70,12 @@ StateListenerRegistry.register(
66 70
 
67 71
             conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => {
68 72
                 batch(() => {
69
-                    dispatch(participantIsKnockingOrUpdated({
70
-                        id,
71
-                        name
72
-                    }));
73
+                    dispatch(
74
+                        participantIsKnockingOrUpdated({
75
+                            id,
76
+                            name
77
+                        })
78
+                    );
73 79
                     dispatch(playSound(KNOCKING_PARTICIPANT_SOUND_ID));
74 80
                     if (typeof APP !== 'undefined') {
75 81
                         APP.API.notifyKnockingParticipant({
@@ -81,10 +87,12 @@ StateListenerRegistry.register(
81 87
             });
82 88
 
83 89
             conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => {
84
-                dispatch(participantIsKnockingOrUpdated({
85
-                    ...participant,
86
-                    id
87
-                }));
90
+                dispatch(
91
+                    participantIsKnockingOrUpdated({
92
+                        ...participant,
93
+                        id
94
+                    })
95
+                );
88 96
             });
89 97
 
90 98
             conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => {
@@ -98,7 +106,8 @@ StateListenerRegistry.register(
98 106
                 })
99 107
             );
100 108
         }
101
-    });
109
+    }
110
+);
102 111
 
103 112
 /**
104 113
  * 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) {
135 144
     dispatch(hideLobbyScreen());
136 145
 
137 146
     if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) {
138
-        dispatch(showNotification({
139
-            appearance: NOTIFICATION_TYPE.ERROR,
140
-            hideErrorSupportLink: true,
141
-            titleKey: 'lobby.joinRejectedMessage'
142
-        }));
147
+        dispatch(
148
+            showNotification({
149
+                appearance: NOTIFICATION_TYPE.ERROR,
150
+                hideErrorSupportLink: true,
151
+                titleKey: 'lobby.joinRejectedMessage'
152
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG)
153
+        );
143 154
     }
144 155
 
145 156
     return next(action);
@@ -174,10 +185,12 @@ function _findLoadableAvatarForKnockingParticipant(store, { id }) {
174 185
     if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
175 186
         getFirstLoadableAvatarUrl(updatedParticipant, store).then(loadableAvatarUrl => {
176 187
             if (loadableAvatarUrl) {
177
-                dispatch(participantIsKnockingOrUpdated({
178
-                    loadableAvatarUrl,
179
-                    id
180
-                }));
188
+                dispatch(
189
+                    participantIsKnockingOrUpdated({
190
+                        loadableAvatarUrl,
191
+                        id
192
+                    })
193
+                );
181 194
             }
182 195
         });
183 196
     }
@@ -217,5 +230,10 @@ function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
217 230
         break;
218 231
     }
219 232
 
220
-    dispatch(showNotification(notificationProps, isTestModeEnabled(getState()) ? undefined : 5000));
233
+    dispatch(
234
+        showNotification(
235
+            notificationProps,
236
+            isTestModeEnabled(getState()) ? NOTIFICATION_TIMEOUT_TYPE.STICKY : NOTIFICATION_TIMEOUT_TYPE.MEDIUM
237
+        )
238
+    );
221 239
 }

+ 3
- 2
react/features/local-recording/middleware.js 查看文件

@@ -8,6 +8,7 @@ import { i18next } from '../base/i18n';
8 8
 import { SET_AUDIO_MUTED } from '../base/media/actionTypes';
9 9
 import { MiddlewareRegistry } from '../base/redux';
10 10
 import { SETTINGS_UPDATED } from '../base/settings/actionTypes';
11
+import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications';
11 12
 import { showNotification } from '../notifications/actions';
12 13
 
13 14
 import { localRecordingEngaged, localRecordingUnengaged } from './actions';
@@ -48,14 +49,14 @@ MiddlewareRegistry.register(({ getState, dispatch }) => next => action => {
48 49
             dispatch(showNotification({
49 50
                 titleKey: 'localRecording.localRecording',
50 51
                 description: i18next.t(messageKey, messageParams)
51
-            }, 10000));
52
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
52 53
         };
53 54
 
54 55
         recordingController.onNotify = (messageKey, messageParams) => {
55 56
             dispatch(showNotification({
56 57
                 titleKey: 'localRecording.localRecording',
57 58
                 description: i18next.t(messageKey, messageParams)
58
-            }, 10000));
59
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
59 60
         };
60 61
 
61 62
         typeof APP === 'object' && typeof APP.keyboardshortcut === 'object'

+ 2
- 2
react/features/no-audio-signal/middleware.js 查看文件

@@ -12,7 +12,7 @@ import JitsiMeetJS, { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
12 12
 import { MiddlewareRegistry } from '../base/redux';
13 13
 import { updateSettings } from '../base/settings';
14 14
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
15
-import { hideNotification, showNotification } from '../notifications';
15
+import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications';
16 16
 
17 17
 import { setNoAudioSignalNotificationUid } from './actions';
18 18
 import DialInLink from './components/DialInLink';
@@ -114,7 +114,7 @@ async function _handleNoAudioSignalNotification({ dispatch, getState }, action)
114 114
             descriptionKey,
115 115
             customActionNameKey,
116 116
             customActionHandler
117
-        }));
117
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
118 118
 
119 119
         dispatch(playSound(NO_AUDIO_SIGNAL_SOUND_ID));
120 120
 

+ 2
- 2
react/features/noise-detection/middleware.js 查看文件

@@ -5,7 +5,7 @@ import { CONFERENCE_JOINED } from '../base/conference';
5 5
 import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
6 6
 import { MiddlewareRegistry } from '../base/redux';
7 7
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
8
-import { hideNotification, showNotification } from '../notifications';
8
+import { NOTIFICATION_TIMEOUT_TYPE, hideNotification, showNotification } from '../notifications';
9 9
 
10 10
 import { setNoisyAudioInputNotificationUid } from './actions';
11 11
 import { NOISY_AUDIO_INPUT_SOUND_ID } from './constants';
@@ -41,7 +41,7 @@ MiddlewareRegistry.register(store => next => action => {
41 41
                 const notification = await dispatch(showNotification({
42 42
                     titleKey: 'toolbar.noisyAudioInputTitle',
43 43
                     descriptionKey: 'toolbar.noisyAudioInputDesc'
44
-                }));
44
+                }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
45 45
 
46 46
                 dispatch(playSound(NOISY_AUDIO_INPUT_SOUND_ID));
47 47
 

+ 32
- 12
react/features/notifications/actions.js 查看文件

@@ -14,11 +14,31 @@ import {
14 14
     SHOW_NOTIFICATION
15 15
 } from './actionTypes';
16 16
 import {
17
+    NOTIFICATION_TIMEOUT_TYPE,
17 18
     NOTIFICATION_TIMEOUT,
18 19
     NOTIFICATION_TYPE,
19 20
     SILENT_JOIN_THRESHOLD
20 21
 } from './constants';
21 22
 
23
+/**
24
+ * Function that returns notification timeout value based on notification timeout type.
25
+ *
26
+ * @param {string} type - Notification type.
27
+ * @param {Object} notificationTimeouts - Config notification timeouts.
28
+ * @returns {number}
29
+ */
30
+function getNotificationTimeout(type: ?string, notificationTimeouts: ?Object) {
31
+    if (type === NOTIFICATION_TIMEOUT_TYPE.SHORT) {
32
+        return notificationTimeouts?.short ?? NOTIFICATION_TIMEOUT.SHORT;
33
+    } else if (type === NOTIFICATION_TIMEOUT_TYPE.MEDIUM) {
34
+        return notificationTimeouts?.medium ?? NOTIFICATION_TIMEOUT.MEDIUM;
35
+    } else if (type === NOTIFICATION_TIMEOUT_TYPE.LONG) {
36
+        return notificationTimeouts?.long ?? NOTIFICATION_TIMEOUT.LONG;
37
+    }
38
+
39
+    return NOTIFICATION_TIMEOUT.STICKY;
40
+}
41
+
22 42
 /**
23 43
  * Clears (removes) all the notifications.
24 44
  *
@@ -82,26 +102,26 @@ export function setNotificationsEnabled(enabled: boolean) {
82 102
  * Queues an error notification for display.
83 103
  *
84 104
  * @param {Object} props - The props needed to show the notification component.
105
+ * @param {string} type - Notification type.
85 106
  * @returns {Object}
86 107
  */
87
-export function showErrorNotification(props: Object) {
108
+export function showErrorNotification(props: Object, type: ?string) {
88 109
     return showNotification({
89 110
         ...props,
90 111
         appearance: NOTIFICATION_TYPE.ERROR
91
-    });
112
+    }, type);
92 113
 }
93 114
 
94 115
 /**
95 116
  * Queues a notification for display.
96 117
  *
97 118
  * @param {Object} props - The props needed to show the notification component.
98
- * @param {number} timeout - How long the notification should display before
99
- * automatically being hidden.
119
+ * @param {string} type - Notification type.
100 120
  * @returns {Function}
101 121
  */
102
-export function showNotification(props: Object = {}, timeout: ?number) {
122
+export function showNotification(props: Object = {}, type: ?string) {
103 123
     return function(dispatch: Function, getState: Function) {
104
-        const { notifications } = getState()['features/base/config'];
124
+        const { notifications, notificationTimeouts } = getState()['features/base/config'];
105 125
         const enabledFlag = getFeatureFlag(getState(), NOTIFICATIONS_ENABLED, true);
106 126
 
107 127
         const shouldDisplay = enabledFlag
@@ -113,7 +133,7 @@ export function showNotification(props: Object = {}, timeout: ?number) {
113 133
             return dispatch({
114 134
                 type: SHOW_NOTIFICATION,
115 135
                 props,
116
-                timeout,
136
+                timeout: getNotificationTimeout(type, notificationTimeouts),
117 137
                 uid: props.uid || window.Date.now().toString()
118 138
             });
119 139
         }
@@ -124,15 +144,15 @@ export function showNotification(props: Object = {}, timeout: ?number) {
124 144
  * Queues a warning notification for display.
125 145
  *
126 146
  * @param {Object} props - The props needed to show the notification component.
127
- * @param {number} timeout - How long the notification should display before
128
- * automatically being hidden.
147
+ * @param {string} type - Notification type.
129 148
  * @returns {Object}
130 149
  */
131
-export function showWarningNotification(props: Object, timeout: ?number) {
150
+export function showWarningNotification(props: Object, type: ?string) {
151
+
132 152
     return showNotification({
133 153
         ...props,
134 154
         appearance: NOTIFICATION_TYPE.WARNING
135
-    }, timeout);
155
+    }, type);
136 156
 }
137 157
 
138 158
 /**
@@ -192,7 +212,7 @@ const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch<any>,
192 212
 
193 213
     if (notificationProps) {
194 214
         dispatch(
195
-            showNotification(notificationProps, NOTIFICATION_TIMEOUT));
215
+            showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
196 216
     }
197 217
 
198 218
     joinedParticipantsNames = [];

+ 4
- 13
react/features/notifications/components/web/NotificationsContainer.js 查看文件

@@ -13,8 +13,6 @@ import { areThereNotifications } from '../../functions';
13 13
 
14 14
 import Notification from './Notification';
15 15
 
16
-declare var interfaceConfig: Object;
17
-
18 16
 type Props = {
19 17
 
20 18
     /**
@@ -33,12 +31,6 @@ type Props = {
33 31
      */
34 32
     _notifications: Array<Object>,
35 33
 
36
-    /**
37
-     * The length, in milliseconds, to use as a default timeout for all
38
-     * dismissible timeouts that do not have a timeout specified.
39
-     */
40
-    autoDismissTimeout: number,
41
-
42 34
     /**
43 35
      * JSS classes object.
44 36
      */
@@ -260,14 +252,14 @@ class NotificationsContainer extends Component<Props> {
260 252
      * @returns {void}
261 253
      */
262 254
     _updateTimeouts() {
263
-        const { _notifications, autoDismissTimeout } = this.props;
255
+        const { _notifications } = this.props;
264 256
 
265 257
         for (const notification of _notifications) {
266
-            if ((notification.timeout || typeof autoDismissTimeout === 'number')
258
+            if (notification.timeout
267 259
                     && notification.props.isDismissAllowed !== false
268 260
                     && !this._timeouts.has(notification.uid)) {
269 261
                 const {
270
-                    timeout = autoDismissTimeout,
262
+                    timeout,
271 263
                     uid
272 264
                 } = notification;
273 265
                 const timerID = setTimeout(() => {
@@ -296,8 +288,7 @@ function _mapStateToProps(state) {
296 288
     return {
297 289
         _iAmSipGateway: Boolean(iAmSipGateway),
298 290
         _isChatOpen: isChatOpen,
299
-        _notifications: _visible ? notifications : [],
300
-        autoDismissTimeout: interfaceConfig.ENFORCE_NOTIFICATION_AUTO_DISMISS_TIMEOUT
291
+        _notifications: _visible ? notifications : []
301 292
     };
302 293
 }
303 294
 

+ 16
- 1
react/features/notifications/constants.js 查看文件

@@ -3,7 +3,22 @@
3 3
 /**
4 4
  * The standard time when auto-disappearing notifications should disappear.
5 5
  */
6
-export const NOTIFICATION_TIMEOUT = 2500;
6
+export const NOTIFICATION_TIMEOUT = {
7
+    SHORT: 2500,
8
+    MEDIUM: 5000,
9
+    LONG: 10000,
10
+    STICKY: false
11
+};
12
+
13
+/**
14
+ * Notification timeout type.
15
+ */
16
+export const NOTIFICATION_TIMEOUT_TYPE = {
17
+    SHORT: 'short',
18
+    MEDIUM: 'medium',
19
+    LONG: 'long',
20
+    STICKY: 'sticky'
21
+};
7 22
 
8 23
 /**
9 24
  * The set of possible notification types.

+ 4
- 7
react/features/notifications/middleware.js 查看文件

@@ -19,7 +19,7 @@ import {
19 19
     showNotification,
20 20
     showParticipantJoinedNotification
21 21
 } from './actions';
22
-import { NOTIFICATION_TIMEOUT } from './constants';
22
+import { NOTIFICATION_TIMEOUT_TYPE } from './constants';
23 23
 import { joinLeaveNotificationsDisabled } from './functions';
24 24
 
25 25
 declare var interfaceConfig: Object;
@@ -54,15 +54,12 @@ MiddlewareRegistry.register(store => next => action => {
54 54
                 action.participant.id
55 55
             );
56 56
 
57
-            if (typeof interfaceConfig === 'object'
58
-                && participant
59
-                && !participant.local
60
-                && !action.participant.isReplaced) {
57
+            if (participant && !participant.local && !action.participant.isReplaced) {
61 58
                 store.dispatch(showNotification({
62 59
                     descriptionKey: 'notify.disconnected',
63 60
                     titleKey: 'notify.somebody',
64 61
                     title: participant.name
65
-                }, NOTIFICATION_TIMEOUT));
62
+                }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
66 63
             }
67 64
         }
68 65
 
@@ -91,7 +88,7 @@ MiddlewareRegistry.register(store => next => action => {
91 88
             store.dispatch(showNotification({
92 89
                 titleKey: 'notify.moderator'
93 90
             },
94
-            NOTIFICATION_TIMEOUT));
91
+            NOTIFICATION_TIMEOUT_TYPE.SHORT));
95 92
         }
96 93
 
97 94
         return next(action);

+ 2
- 2
react/features/old-client-notification/middleware.js 查看文件

@@ -4,7 +4,7 @@ import React from 'react';
4 4
 
5 5
 import { APP_WILL_MOUNT } from '../base/app';
6 6
 import { MiddlewareRegistry } from '../base/redux';
7
-import { showErrorNotification } from '../notifications';
7
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../notifications';
8 8
 
9 9
 import { OldElectronAPPNotificationDescription } from './components';
10 10
 import { isOldJitsiMeetElectronApp } from './functions';
@@ -36,7 +36,7 @@ function _appWillMount(store, next, action) {
36 36
         dispatch(showErrorNotification({
37 37
             titleKey: 'notify.OldElectronAPPTitle',
38 38
             description: <OldElectronAPPNotificationDescription />
39
-        }));
39
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
40 40
     }
41 41
 
42 42
     return next(action);

+ 2
- 2
react/features/polls/subscriber.js 查看文件

@@ -4,7 +4,7 @@ import { getCurrentConference } from '../base/conference';
4 4
 import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
5 5
 import { StateListenerRegistry } from '../base/redux';
6 6
 import {
7
-    NOTIFICATION_TIMEOUT,
7
+    NOTIFICATION_TIMEOUT_TYPE,
8 8
     NOTIFICATION_TYPE,
9 9
     showNotification
10 10
 } from '../notifications';
@@ -83,7 +83,7 @@ StateListenerRegistry.register(
83 83
                         appearance: NOTIFICATION_TYPE.NORMAL,
84 84
                         titleKey: 'polls.notification.title',
85 85
                         descriptionKey: 'polls.notification.description'
86
-                    }, NOTIFICATION_TIMEOUT));
86
+                    }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
87 87
                     break;
88 88
 
89 89
                 }

+ 5
- 5
react/features/prejoin/actions.js 查看文件

@@ -19,7 +19,7 @@ import {
19 19
 } from '../base/tracks';
20 20
 import { openURLInBrowser } from '../base/util';
21 21
 import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
22
-import { showErrorNotification } from '../notifications';
22
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../notifications';
23 23
 
24 24
 import {
25 25
     PREJOIN_JOINING_IN_PROGRESS,
@@ -114,7 +114,7 @@ function pollForStatus(
114 114
             case DIAL_OUT_STATUS.DISCONNECTED: {
115 115
                 dispatch(showErrorNotification({
116 116
                     titleKey: 'prejoin.errorDialOutDisconnected'
117
-                }));
117
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
118 118
 
119 119
                 return onFail();
120 120
             }
@@ -122,7 +122,7 @@ function pollForStatus(
122 122
             case DIAL_OUT_STATUS.FAILED: {
123 123
                 dispatch(showErrorNotification({
124 124
                     titleKey: 'prejoin.errorDialOutFailed'
125
-                }));
125
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
126 126
 
127 127
                 return onFail();
128 128
             }
@@ -130,7 +130,7 @@ function pollForStatus(
130 130
         } catch (err) {
131 131
             dispatch(showErrorNotification({
132 132
                 titleKey: 'prejoin.errorDialOutStatus'
133
-            }));
133
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
134 134
             logger.error('Error getting dial out status', err);
135 135
             onFail();
136 136
         }
@@ -183,7 +183,7 @@ export function dialOut(onSuccess: Function, onFail: Function) {
183 183
                 }
184 184
             }
185 185
 
186
-            dispatch(showErrorNotification(notification));
186
+            dispatch(showErrorNotification(notification, NOTIFICATION_TIMEOUT_TYPE.LONG));
187 187
             logger.error('Error dialing out', err);
188 188
             onFail();
189 189
         }

+ 2
- 2
react/features/reactions/middleware.js 查看文件

@@ -9,7 +9,7 @@ import { MiddlewareRegistry } from '../base/redux';
9 9
 import { SETTINGS_UPDATED, updateSettings } from '../base/settings';
10 10
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
11 11
 import { getDisabledSounds } from '../base/sounds/functions.any';
12
-import { NOTIFICATION_TIMEOUT, showNotification } from '../notifications';
12
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
13 13
 
14 14
 import {
15 15
     ADD_REACTION_BUFFER,
@@ -169,7 +169,7 @@ MiddlewareRegistry.register(store => next => action => {
169 169
             customActionHandler: () => dispatch(updateSettings({
170 170
                 soundsReactions: false
171 171
             }))
172
-        }, NOTIFICATION_TIMEOUT));
172
+        }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
173 173
         break;
174 174
     }
175 175
     }

+ 6
- 6
react/features/recording/actions.any.js 查看文件

@@ -6,7 +6,7 @@ import { getLocalParticipant, getParticipantDisplayName } from '../base/particip
6 6
 import { copyText } from '../base/util/helpers';
7 7
 import { getVpaasTenant, isVpaasMeeting } from '../jaas/functions';
8 8
 import {
9
-    NOTIFICATION_TIMEOUT,
9
+    NOTIFICATION_TIMEOUT_TYPE,
10 10
     hideNotification,
11 11
     showErrorNotification,
12 12
     showNotification,
@@ -98,7 +98,7 @@ export function showPendingRecordingNotification(streamType: string) {
98 98
         const notification = await dispatch(showNotification({
99 99
             isDismissAllowed: false,
100 100
             ...dialogProps
101
-        }));
101
+        }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
102 102
 
103 103
         if (notification) {
104 104
             dispatch(_setPendingRecordingNotificationUid(notification.uid, streamType));
@@ -113,7 +113,7 @@ export function showPendingRecordingNotification(streamType: string) {
113 113
  * @returns {showErrorNotification}
114 114
  */
115 115
 export function showRecordingError(props: Object) {
116
-    return showErrorNotification(props);
116
+    return showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG);
117 117
 }
118 118
 
119 119
 /**
@@ -149,7 +149,7 @@ export function showStoppedRecordingNotification(streamType: string, participant
149 149
         titleKey: 'dialog.recording'
150 150
     };
151 151
 
152
-    return showNotification(dialogProps, NOTIFICATION_TIMEOUT);
152
+    return showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT);
153 153
 }
154 154
 
155 155
 /**
@@ -214,14 +214,14 @@ export function showStartedRecordingNotification(
214 214
                 } catch (err) {
215 215
                     dispatch(showErrorNotification({
216 216
                         titleKey: 'recording.errorFetchingLink'
217
-                    }));
217
+                    }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
218 218
 
219 219
                     return logger.error('Could not fetch recording link', err);
220 220
                 }
221 221
             }
222 222
         }
223 223
 
224
-        dispatch(showNotification(dialogProps, NOTIFICATION_TIMEOUT));
224
+        dispatch(showNotification(dialogProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
225 225
     };
226 226
 }
227 227
 

+ 2
- 2
react/features/recording/actions.native.js 查看文件

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import JitsiMeetJS from '../base/lib-jitsi-meet';
4
-import { showNotification } from '../notifications';
4
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
5 5
 
6 6
 export * from './actions.any';
7 7
 
@@ -37,6 +37,6 @@ export function showRecordingLimitNotification(streamType: string) {
37 37
             descriptionKey,
38 38
             titleKey,
39 39
             maxLines: 2
40
-        }, 10000));
40
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
41 41
     };
42 42
 }

+ 2
- 2
react/features/recording/actions.web.js 查看文件

@@ -3,7 +3,7 @@
3 3
 import React from 'react';
4 4
 
5 5
 import JitsiMeetJS from '../base/lib-jitsi-meet';
6
-import { showNotification } from '../notifications';
6
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
7 7
 
8 8
 import { RecordingLimitNotificationDescription } from './components';
9 9
 
@@ -23,5 +23,5 @@ export function showRecordingLimitNotification(streamType: string) {
23 23
     return showNotification({
24 24
         description: <RecordingLimitNotificationDescription isLiveStreaming = { isLiveStreaming } />,
25 25
         titleKey: isLiveStreaming ? 'dialog.liveStreaming' : 'dialog.recording'
26
-    }, 10000);
26
+    }, NOTIFICATION_TIMEOUT_TYPE.LONG);
27 27
 }

+ 2
- 2
react/features/recording/components/Recording/AbstractStartRecordingDialog.js 查看文件

@@ -13,7 +13,7 @@ import {
13 13
     getNewAccessToken,
14 14
     updateDropboxToken
15 15
 } from '../../../dropbox';
16
-import { showErrorNotification } from '../../../notifications';
16
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../../notifications';
17 17
 import { toggleRequestingSubtitles } from '../../../subtitles';
18 18
 import { setSelectedRecordingService } from '../../actions';
19 19
 import { RECORDING_TYPES } from '../../constants';
@@ -298,7 +298,7 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
298 298
             } else {
299 299
                 dispatch(showErrorNotification({
300 300
                     titleKey: 'dialog.noDropboxToken'
301
-                }));
301
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
302 302
 
303 303
                 return;
304 304
             }

+ 5
- 5
react/features/remote-control/actions.js 查看文件

@@ -4,7 +4,7 @@ import { openDialog } from '../base/dialog';
4 4
 import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
5 5
 import { getParticipantDisplayName, getPinnedParticipant, pinParticipant } from '../base/participants';
6 6
 import { getLocalVideoTrack } from '../base/tracks';
7
-import { showNotification } from '../notifications';
7
+import { NOTIFICATION_TIMEOUT_TYPE, showNotification } from '../notifications';
8 8
 
9 9
 import {
10 10
     CAPTURE_EVENTS,
@@ -190,7 +190,7 @@ export function processPermissionRequestReply(participantId: string, event: Obje
190 190
                 descriptionArguments: { user: getParticipantDisplayName(state, participantId) },
191 191
                 descriptionKey,
192 192
                 titleKey: 'dialog.remoteControlTitle'
193
-            }));
193
+            }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
194 194
 
195 195
             if (permissionGranted) {
196 196
                 // the remote control permissions has been granted
@@ -269,7 +269,7 @@ export function stopController(notifyRemoteParty: boolean = false) {
269 269
         dispatch(showNotification({
270 270
             descriptionKey: 'dialog.remoteControlStopMessage',
271 271
             titleKey: 'dialog.remoteControlTitle'
272
-        }));
272
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
273 273
     };
274 274
 }
275 275
 
@@ -425,7 +425,7 @@ export function stopReceiver(dontNotifyLocalParty: boolean = false, dontNotifyRe
425 425
             dispatch(showNotification({
426 426
                 descriptionKey: 'dialog.remoteControlStopMessage',
427 427
                 titleKey: 'dialog.remoteControlTitle'
428
-            }));
428
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
429 429
         }
430 430
     };
431 431
 }
@@ -564,7 +564,7 @@ export function grant(participantId: string) {
564 564
                 dispatch(showNotification({
565 565
                     descriptionKey: 'dialog.startRemoteControlErrorMessage',
566 566
                     titleKey: 'dialog.remoteControlTitle'
567
-                }));
567
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
568 568
 
569 569
                 dispatch(stopReceiver(true));
570 570
             });

+ 3
- 3
react/features/room-lock/middleware.js 查看文件

@@ -11,7 +11,7 @@ import { hideDialog } from '../base/dialog';
11 11
 import { JitsiConferenceErrors } from '../base/lib-jitsi-meet';
12 12
 import { MiddlewareRegistry } from '../base/redux';
13 13
 import {
14
-    NOTIFICATION_TIMEOUT,
14
+    NOTIFICATION_TIMEOUT_TYPE,
15 15
     showNotification
16 16
 } from '../notifications';
17 17
 
@@ -54,12 +54,12 @@ MiddlewareRegistry.register(store => next => action => {
54 54
             store.dispatch(
55 55
                 showNotification({
56 56
                     titleKey: 'notify.passwordSetRemotely'
57
-                }, NOTIFICATION_TIMEOUT));
57
+                }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
58 58
         } else if (previousLockedState === LOCKED_REMOTELY && !currentLockedState) {
59 59
             store.dispatch(
60 60
                 showNotification({
61 61
                     titleKey: 'notify.passwordRemovedRemotely'
62
-                }, NOTIFICATION_TIMEOUT));
62
+                }, NOTIFICATION_TIMEOUT_TYPE.SHORT));
63 63
         }
64 64
 
65 65
         return result;

+ 2
- 1
react/features/shared-video/components/web/AbstractVideoManager.js 查看文件

@@ -9,6 +9,7 @@ import { getCurrentConference } from '../../../base/conference';
9 9
 import { MEDIA_TYPE } from '../../../base/media';
10 10
 import { getLocalParticipant } from '../../../base/participants';
11 11
 import { isLocalTrackMuted } from '../../../base/tracks';
12
+import { NOTIFICATION_TIMEOUT_TYPE } from '../../../notifications';
12 13
 import { showWarningNotification } from '../../../notifications/actions';
13 14
 import { dockToolbox } from '../../../toolbox/actions.web';
14 15
 import { muteLocal } from '../../../video-menu/actions.any';
@@ -424,7 +425,7 @@ export function _mapDispatchToProps(dispatch: Function): $Shape<Props> {
424 425
         _displayWarning: () => {
425 426
             dispatch(showWarningNotification({
426 427
                 titleKey: 'dialog.shareVideoLinkError'
427
-            }));
428
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG));
428 429
         },
429 430
         _dockToolbox: value => {
430 431
             dispatch(dockToolbox(value));

+ 3
- 2
react/features/stream-effects/virtual-background/index.js 查看文件

@@ -1,5 +1,6 @@
1 1
 // @flow
2 2
 
3
+import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
3 4
 import { showWarningNotification } from '../../notifications/actions';
4 5
 import { timeout } from '../../virtual-background/functions';
5 6
 import logger from '../../virtual-background/logger';
@@ -62,13 +63,13 @@ export async function createVirtualBackgroundEffect(virtualBackground: Object, d
62 63
                 logger.error('Failed to download tflite model!');
63 64
                 dispatch(showWarningNotification({
64 65
                     titleKey: 'virtualBackground.backgroundEffectError'
65
-                }));
66
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
66 67
             } else {
67 68
                 logger.error('Looks like WebAssembly is disabled or not supported on this browser');
68 69
                 dispatch(showWarningNotification({
69 70
                     titleKey: 'virtualBackground.webAssemblyWarning',
70 71
                     description: 'WebAssembly disabled or not supported by this browser'
71
-                }));
72
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
72 73
             }
73 74
 
74 75
             return;

+ 2
- 1
react/features/talk-while-muted/middleware.js 查看文件

@@ -8,6 +8,7 @@ import { getLocalParticipant, raiseHand } from '../base/participants';
8 8
 import { MiddlewareRegistry } from '../base/redux';
9 9
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
10 10
 import {
11
+    NOTIFICATION_TIMEOUT_TYPE,
11 12
     hideNotification,
12 13
     showNotification
13 14
 } from '../notifications';
@@ -50,7 +51,7 @@ MiddlewareRegistry.register(store => next => action => {
50 51
                     titleKey: 'toolbar.talkWhileMutedPopup',
51 52
                     customActionNameKey: forceMuted ? 'notify.raiseHandAction' : 'notify.unmute',
52 53
                     customActionHandler: () => dispatch(forceMuted ? raiseHand(true) : setAudioMuted(false))
53
-                }));
54
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
54 55
 
55 56
                 const { soundsTalkWhileMuted } = getState()['features/base/settings'];
56 57
 

+ 4
- 4
react/features/transcribing/actions.js 查看文件

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import {
4
-    NOTIFICATION_TIMEOUT,
4
+    NOTIFICATION_TIMEOUT_TYPE,
5 5
     hideNotification,
6 6
     showErrorNotification,
7 7
     showNotification
@@ -74,7 +74,7 @@ export function showPendingTranscribingNotification() {
74 74
             descriptionKey: 'transcribing.pending',
75 75
             isDismissAllowed: false,
76 76
             titleKey: 'dialog.transcribing'
77
-        }));
77
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG));
78 78
 
79 79
         if (notification) {
80 80
             dispatch(setPendingTranscribingNotificationUid(notification.uid));
@@ -127,7 +127,7 @@ export function showStoppedTranscribingNotification() {
127 127
     return showNotification({
128 128
         descriptionKey: 'transcribing.off',
129 129
         titleKey: 'dialog.transcribing'
130
-    }, NOTIFICATION_TIMEOUT);
130
+    }, NOTIFICATION_TIMEOUT_TYPE.SHORT);
131 131
 }
132 132
 
133 133
 
@@ -140,5 +140,5 @@ export function showTranscribingError() {
140 140
     return showErrorNotification({
141 141
         descriptionKey: 'transcribing.error',
142 142
         titleKey: 'transcribing.failedToStart'
143
-    });
143
+    }, NOTIFICATION_TIMEOUT_TYPE.LONG);
144 144
 }

+ 6
- 5
react/features/videosipgw/middleware.js 查看文件

@@ -7,6 +7,7 @@ import {
7 7
 } from '../base/lib-jitsi-meet';
8 8
 import { MiddlewareRegistry } from '../base/redux';
9 9
 import {
10
+    NOTIFICATION_TIMEOUT_TYPE,
10 11
     showErrorNotification,
11 12
     showNotification,
12 13
     showWarningNotification
@@ -103,7 +104,7 @@ function _inviteRooms(rooms, conference, dispatch) {
103 104
                     dispatch(showErrorNotification({
104 105
                         descriptionKey: 'videoSIPGW.errorInvite',
105 106
                         titleKey: 'videoSIPGW.errorInviteTitle'
106
-                    }));
107
+                    }, NOTIFICATION_TIMEOUT_TYPE.LONG));
107 108
 
108 109
                     return;
109 110
                 }
@@ -111,7 +112,7 @@ function _inviteRooms(rooms, conference, dispatch) {
111 112
                     dispatch(showWarningNotification({
112 113
                         titleKey: 'videoSIPGW.errorAlreadyInvited',
113 114
                         titleArguments: { displayName }
114
-                    }));
115
+                    }, NOTIFICATION_TIMEOUT_TYPE.LONG));
115 116
 
116 117
                     return;
117 118
                 }
@@ -148,7 +149,7 @@ function _sessionStateChanged(
148 149
             titleArguments: {
149 150
                 displayName: event.displayName
150 151
             }
151
-        }, 2000);
152
+        }, NOTIFICATION_TIMEOUT_TYPE.SHORT);
152 153
     }
153 154
     case JitsiSIPVideoGWStatus.STATE_FAILED: {
154 155
         return showErrorNotification({
@@ -157,14 +158,14 @@ function _sessionStateChanged(
157 158
                 displayName: event.displayName
158 159
             },
159 160
             descriptionKey: 'videoSIPGW.errorInviteFailed'
160
-        });
161
+        }, NOTIFICATION_TIMEOUT_TYPE.LONG);
161 162
     }
162 163
     case JitsiSIPVideoGWStatus.STATE_OFF: {
163 164
         if (event.failureReason === JitsiSIPVideoGWStatus.STATUS_BUSY) {
164 165
             return showErrorNotification({
165 166
                 descriptionKey: 'videoSIPGW.busy',
166 167
                 titleKey: 'videoSIPGW.busyTitle'
167
-            });
168
+            }, NOTIFICATION_TIMEOUT_TYPE.LONG);
168 169
         } else if (event.failureReason) {
169 170
             logger.error(`Unknown sip videogw error ${event.newState} ${
170 171
                 event.failureReason}`);

+ 2
- 2
react/features/virtual-background/components/VirtualBackgroundDialog.js 查看文件

@@ -16,7 +16,7 @@ import { connect } from '../../base/redux';
16 16
 import { updateSettings } from '../../base/settings';
17 17
 import { Tooltip } from '../../base/tooltip';
18 18
 import { getLocalVideoTrack } from '../../base/tracks';
19
-import { showErrorNotification } from '../../notifications';
19
+import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification } from '../../notifications';
20 20
 import { toggleBackgroundEffect, virtualBackgroundTrackChanged } from '../actions';
21 21
 import { IMAGES, BACKGROUNDS_LIMIT, VIRTUAL_BACKGROUND_TYPE, type Image } from '../constants';
22 22
 import { toDataURL } from '../functions';
@@ -219,7 +219,7 @@ function VirtualBackground({
219 219
             if (!isCancelled) {
220 220
                 dispatch(showErrorNotification({
221 221
                     titleKey: 'virtualBackground.desktopShareError'
222
-                }));
222
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG));
223 223
                 logger.error('Could not create desktop share as a virtual background!');
224 224
             }
225 225
 

+ 2
- 1
react/features/virtual-background/components/VirtualBackgroundPreview.js 查看文件

@@ -10,6 +10,7 @@ import Video from '../../base/media/components/Video';
10 10
 import { connect, equals } from '../../base/redux';
11 11
 import { getCurrentCameraDeviceId } from '../../base/settings';
12 12
 import { createLocalTracksF } from '../../base/tracks/functions';
13
+import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
13 14
 import { showWarningNotification } from '../../notifications/actions';
14 15
 import { toggleBackgroundEffect } from '../actions';
15 16
 import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
@@ -140,7 +141,7 @@ class VirtualBackgroundPreview extends PureComponent<Props, State> {
140 141
                 showWarningNotification({
141 142
                     titleKey: 'virtualBackground.backgroundEffectError',
142 143
                     description: 'Failed to access camera device.'
143
-                })
144
+                }, NOTIFICATION_TIMEOUT_TYPE.LONG)
144 145
             );
145 146
             logger.error('Failed to access camera device. Error on apply background effect.');
146 147
 

正在加载...
取消
保存