diff --git a/react/features/base/config/configWhitelist.ts b/react/features/base/config/configWhitelist.ts index 6fbf6eaeb4..dc4e522288 100644 --- a/react/features/base/config/configWhitelist.ts +++ b/react/features/base/config/configWhitelist.ts @@ -201,6 +201,7 @@ export default [ 'remoteVideoMenu', 'roomPasswordNumberOfDigits', 'readOnlyName', + 'recordings', 'replaceParticipant', 'resolution', 'salesforceUrl', diff --git a/react/features/recording/actionTypes.ts b/react/features/recording/actionTypes.ts index 71f5b858bb..9c02f12e51 100644 --- a/react/features/recording/actionTypes.ts +++ b/react/features/recording/actionTypes.ts @@ -83,3 +83,12 @@ export const START_LOCAL_RECORDING = 'START_LOCAL_RECORDING'; * } */ export const STOP_LOCAL_RECORDING = 'STOP_LOCAL_RECORDING'; + +/** + * Indicates that the start recording notification has been shown. + * + * { + * type: SET_START_RECORDING_NOTIFICATION_SHOWN + * } + */ +export const SET_START_RECORDING_NOTIFICATION_SHOWN = 'SET_START_RECORDING_NOTIFICATION_SHOWN'; diff --git a/react/features/recording/actions.any.ts b/react/features/recording/actions.any.ts index 3a92c55dfa..09a6268b0d 100644 --- a/react/features/recording/actions.any.ts +++ b/react/features/recording/actions.any.ts @@ -26,6 +26,7 @@ import { SET_MEETING_HIGHLIGHT_BUTTON_STATE, SET_PENDING_RECORDING_NOTIFICATION_UID, SET_SELECTED_RECORDING_SERVICE, + SET_START_RECORDING_NOTIFICATION_SHOWN, SET_STREAM_KEY, START_LOCAL_RECORDING, STOP_LOCAL_RECORDING @@ -57,6 +58,20 @@ export function clearRecordingSessions() { }; } + +/** + * Marks the start recording notification as shown. + * + * @returns {{ + * type: SET_START_RECORDING_NOTIFICATION_SHOWN + * }} + */ +export function setStartRecordingNotificationShown() { + return { + type: SET_START_RECORDING_NOTIFICATION_SHOWN + }; +} + /** * Sets the meeting highlight button disable state. * @@ -394,14 +409,17 @@ export function showStartRecordingNotificationWithCallback(openRecordingDialog: const { suggestRecording } = recordings || {}; const recordButtonProps = getRecordButtonProps(state); const isAlreadyRecording = isRecordingRunning(state); + const wasNotificationShown = state['features/recording'].wasStartRecordingSuggested; if (!suggestRecording || isAlreadyRecording || !recordButtonProps.visible - || recordButtonProps.disabled) { + || recordButtonProps.disabled + || wasNotificationShown) { return; } + dispatch(setStartRecordingNotificationShown()); dispatch(showNotification({ titleKey: 'notify.suggestRecordingTitle', descriptionKey: 'notify.suggestRecordingDescription', diff --git a/react/features/recording/middleware.ts b/react/features/recording/middleware.ts index a8426d463f..21ad3b27b2 100644 --- a/react/features/recording/middleware.ts +++ b/react/features/recording/middleware.ts @@ -9,8 +9,10 @@ import JitsiMeetJS, { JitsiRecordingConstants } from '../base/lib-jitsi-meet'; import { MEDIA_TYPE } from '../base/media/constants'; +import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes'; import { updateLocalRecordingStatus } from '../base/participants/actions'; -import { getParticipantDisplayName } from '../base/participants/functions'; +import { PARTICIPANT_ROLE } from '../base/participants/constants'; +import { getLocalParticipant, getParticipantDisplayName } from '../base/participants/functions'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import StateListenerRegistry from '../base/redux/StateListenerRegistry'; import { @@ -29,6 +31,7 @@ import { showRecordingError, showRecordingLimitNotification, showRecordingWarning, + showStartRecordingNotification, showStartedRecordingNotification, showStoppedRecordingNotification, updateRecordingSessionData @@ -283,6 +286,21 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action => } break; } + case PARTICIPANT_UPDATED: { + const { id, role } = action.participant; + const state = getState(); + const localParticipant = getLocalParticipant(state); + + if (localParticipant?.id !== id) { + return next(action); + } + + if (role === PARTICIPANT_ROLE.MODERATOR) { + dispatch(showStartRecordingNotification()); + } + + return next(action); + } } return result; diff --git a/react/features/recording/reducer.ts b/react/features/recording/reducer.ts index 9e50a00ba4..6de3825b23 100644 --- a/react/features/recording/reducer.ts +++ b/react/features/recording/reducer.ts @@ -6,6 +6,7 @@ import { SET_MEETING_HIGHLIGHT_BUTTON_STATE, SET_PENDING_RECORDING_NOTIFICATION_UID, SET_SELECTED_RECORDING_SERVICE, + SET_START_RECORDING_NOTIFICATION_SHOWN, SET_STREAM_KEY } from './actionTypes'; @@ -35,6 +36,7 @@ export interface IRecordingState { selectedRecordingService: string; sessionDatas: Array; streamKey?: string; + wasStartRecordingSuggested?: boolean; } /** @@ -94,6 +96,12 @@ ReducerRegistry.register(STORE_NAME, disableHighlightMeetingMoment: action.disabled }; + case SET_START_RECORDING_NOTIFICATION_SHOWN: + return { + ...state, + wasStartRecordingSuggested: true + }; + default: return state; }