feat(notifications) coalesce participant left and raised hand notifications
This commit is contained in:
parent
40a76940ac
commit
c172a27f24
|
@ -585,6 +585,9 @@
|
|||
"invitedThreePlusMembers": "{{name}} and {{count}} others have been invited",
|
||||
"invitedTwoMembers": "{{first}} and {{second}} have been invited",
|
||||
"kickParticipant": "{{kicked}} was kicked by {{kicker}}",
|
||||
"leftOneMember": "{{name}} left the meeting",
|
||||
"leftThreePlusMembers": "{{name}} and many others left the meeting",
|
||||
"leftTwoMembers": "{{first}} and {{second}} left the meeting",
|
||||
"me": "Me",
|
||||
"moderator": "You're now a moderator",
|
||||
"muted": "You have started the conversation muted.",
|
||||
|
@ -596,6 +599,7 @@
|
|||
"passwordRemovedRemotely": "$t(lockRoomPasswordUppercase) removed by another participant",
|
||||
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
|
||||
"raisedHand": "Would like to speak.",
|
||||
"raisedHands": "{{participantName}} and {{raisedHands}} more people",
|
||||
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
|
||||
"screenShareNoAudioTitle": "Couldn't share system audio!",
|
||||
"somebody": "Somebody",
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
// @flow
|
||||
|
||||
import i18n from 'i18next';
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
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_TYPE, showNotification } from '../../notifications';
|
||||
import {
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
RAISE_HAND_NOTIFICATION_ID,
|
||||
showNotification
|
||||
} from '../../notifications';
|
||||
import { isForceMuted } from '../../participants-pane/functions';
|
||||
import { CALLING, INVITED } from '../../presence-status';
|
||||
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
|
||||
|
@ -555,12 +560,27 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
|
|||
} : {};
|
||||
|
||||
if (raisedHandTimestamp) {
|
||||
let notificationTitle;
|
||||
const participantName = getParticipantDisplayName(state, participantId);
|
||||
const { raisedHandsQueue } = state['features/base/participants'];
|
||||
|
||||
if (raisedHandsQueue.length > 1) {
|
||||
const raisedHands = raisedHandsQueue.length - 1;
|
||||
|
||||
notificationTitle = i18n.t('notify.raisedHands', {
|
||||
participantName,
|
||||
raisedHands
|
||||
});
|
||||
} else {
|
||||
notificationTitle = participantName;
|
||||
}
|
||||
dispatch(showNotification({
|
||||
titleKey: 'notify.somebody',
|
||||
title: getParticipantDisplayName(state, participantId),
|
||||
title: notificationTitle,
|
||||
descriptionKey: 'notify.raisedHand',
|
||||
raiseHandNotification: true,
|
||||
concatText: true,
|
||||
uid: RAISE_HAND_NOTIFICATION_ID,
|
||||
...action
|
||||
}, shouldDisplayAllowAction ? NOTIFICATION_TIMEOUT_TYPE.MEDIUM : NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
dispatch(playSound(RAISE_HAND_SOUND_ID));
|
||||
|
|
|
@ -17,7 +17,8 @@ import {
|
|||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
NOTIFICATION_TIMEOUT,
|
||||
NOTIFICATION_TYPE,
|
||||
SILENT_JOIN_THRESHOLD
|
||||
SILENT_JOIN_THRESHOLD,
|
||||
SILENT_LEFT_THRESHOLD
|
||||
} from './constants';
|
||||
|
||||
/**
|
||||
|
@ -219,6 +220,70 @@ const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch<any>,
|
|||
|
||||
}, 2000, { leading: false });
|
||||
|
||||
/**
|
||||
* An array of names of participants that have left the conference. The array
|
||||
* is replaced with an empty array as notifications are displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {string[]}
|
||||
*/
|
||||
let leftParticipantsNames = [];
|
||||
|
||||
/**
|
||||
* A throttled internal function that takes the internal list of participant
|
||||
* names, {@code leftParticipantsNames}, and triggers the display of a
|
||||
* notification informing of their leaving.
|
||||
*
|
||||
* @private
|
||||
* @type {Function}
|
||||
*/
|
||||
const _throttledNotifyParticipantLeft = throttle((dispatch: Dispatch<any>, getState: Function) => {
|
||||
const participantCount = getParticipantCount(getState());
|
||||
|
||||
// Skip left notifications altogether for large meetings.
|
||||
if (participantCount > SILENT_LEFT_THRESHOLD) {
|
||||
leftParticipantsNames = [];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const leftParticipantsCount = leftParticipantsNames.length;
|
||||
|
||||
let notificationProps;
|
||||
|
||||
if (leftParticipantsCount >= 3) {
|
||||
notificationProps = {
|
||||
titleArguments: {
|
||||
name: leftParticipantsNames[0]
|
||||
},
|
||||
titleKey: 'notify.leftThreePlusMembers'
|
||||
};
|
||||
} else if (leftParticipantsCount === 2) {
|
||||
notificationProps = {
|
||||
titleArguments: {
|
||||
first: leftParticipantsNames[0],
|
||||
second: leftParticipantsNames[1]
|
||||
},
|
||||
titleKey: 'notify.leftTwoMembers'
|
||||
};
|
||||
} else if (leftParticipantsCount) {
|
||||
notificationProps = {
|
||||
titleArguments: {
|
||||
name: leftParticipantsNames[0]
|
||||
},
|
||||
titleKey: 'notify.leftOneMember'
|
||||
};
|
||||
}
|
||||
|
||||
if (notificationProps) {
|
||||
dispatch(
|
||||
showNotification(notificationProps, NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
}
|
||||
|
||||
leftParticipantsNames = [];
|
||||
|
||||
}, 2000, { leading: false });
|
||||
|
||||
/**
|
||||
* Queues the display of a notification of a participant having connected to
|
||||
* the meeting. The notifications are batched so that quick consecutive
|
||||
|
@ -228,7 +293,21 @@ const _throttledNotifyParticipantConnected = throttle((dispatch: Dispatch<any>,
|
|||
* @returns {Function}
|
||||
*/
|
||||
export function showParticipantJoinedNotification(displayName: string) {
|
||||
joinedParticipantsNames.push(displayName);
|
||||
leftParticipantsNames.push(displayName);
|
||||
|
||||
return (dispatch: Dispatch<any>, getState: Function) => _throttledNotifyParticipantConnected(dispatch, getState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the display of a notification of a participant having left to
|
||||
* the meeting. The notifications are batched so that quick consecutive
|
||||
* connection events are shown in one notification.
|
||||
*
|
||||
* @param {string} displayName - The name of the participant that left.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function showParticipantLeftNotification(displayName: string) {
|
||||
joinedParticipantsNames.push(displayName);
|
||||
|
||||
return (dispatch: Dispatch<any>, getState: Function) => _throttledNotifyParticipantLeft(dispatch, getState);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,19 @@ export const NOTIFICATION_TYPE_PRIORITIES = {
|
|||
[NOTIFICATION_TYPE.WARNING]: 4
|
||||
};
|
||||
|
||||
/**
|
||||
* The identifier of the raise hand notification.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const RAISE_HAND_NOTIFICATION_ID = 'RAISE_HAND_NOTIFICATION';
|
||||
|
||||
/**
|
||||
* Amount of participants beyond which no join notification will be emitted.
|
||||
*/
|
||||
export const SILENT_JOIN_THRESHOLD = 30;
|
||||
|
||||
/**
|
||||
* Amount of participants beyond which no left notification will be emitted.
|
||||
*/
|
||||
export const SILENT_LEFT_THRESHOLD = 30;
|
||||
|
|
|
@ -17,13 +17,12 @@ import {
|
|||
clearNotifications,
|
||||
hideRaiseHandNotifications,
|
||||
showNotification,
|
||||
showParticipantJoinedNotification
|
||||
showParticipantJoinedNotification,
|
||||
showParticipantLeftNotification
|
||||
} from './actions';
|
||||
import { NOTIFICATION_TIMEOUT_TYPE } from './constants';
|
||||
import { joinLeaveNotificationsDisabled } from './functions';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
/**
|
||||
* Middleware that captures actions to display notifications.
|
||||
*
|
||||
|
@ -49,17 +48,17 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
}
|
||||
case PARTICIPANT_LEFT: {
|
||||
if (!joinLeaveNotificationsDisabled()) {
|
||||
const { dispatch, getState } = store;
|
||||
const state = getState();
|
||||
const participant = getParticipantById(
|
||||
store.getState(),
|
||||
action.participant.id
|
||||
);
|
||||
|
||||
if (participant && !participant.local && !action.participant.isReplaced) {
|
||||
store.dispatch(showNotification({
|
||||
descriptionKey: 'notify.disconnected',
|
||||
titleKey: 'notify.somebody',
|
||||
title: participant.name
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
|
||||
dispatch(showParticipantLeftNotification(
|
||||
getParticipantDisplayName(state, participant.id)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue