fix(local-recording) Add notification config and style fixes (#11728)

Add analytics
This commit is contained in:
Robert Pintilii 2022-06-22 10:52:22 +01:00 committed by GitHub
parent 31348179d4
commit 7dca91a50a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 25 deletions

View File

@ -295,8 +295,13 @@ var config = {
// Whether to enable live streaming or not. // Whether to enable live streaming or not.
// liveStreamingEnabled: false, // liveStreamingEnabled: false,
// Whether to enable local recording or not. // Local recording configuration.
// enableLocalRecording: false, // localRecording: {
// // Whether to enable local recording or not.
// enable: false,
// // Whether to notify all participants when a participant is recording locally.
// notifyAllParticipants: false
// },
// Transcription (in interface_config, // Transcription (in interface_config,
// subtitles and buttons can be configured) // subtitles and buttons can be configured)

View File

@ -28,8 +28,21 @@
} }
.local-recording-warning { .local-recording-warning {
margin-top: 4px; margin-top: 8px;
display: block; display: block;
font-size: 14px;
line-height: 20px;
padding: 8px 16px;
&.text {
color: #fff;
background-color: #3D3D3D;
}
&.notification {
color: #040404;
background-color: #F8AE1A;
}
} }
.recording-switch-disabled { .recording-switch-disabled {
@ -46,7 +59,7 @@
border-radius: 4px; border-radius: 4px;
height: 40px; height: 40px;
justify-content: center; justify-content: center;
width: 56px; width: 42px;
} }
.cloud-content-recording-icon-container { .cloud-content-recording-icon-container {
@ -58,7 +71,7 @@
} }
.jitsi-recording-header { .jitsi-recording-header {
margin-bottom: 32px; margin-bottom: 16px;
} }
.jitsi-content-recording-icon-container-with-switch { .jitsi-content-recording-icon-container-with-switch {

View File

@ -894,6 +894,7 @@
"limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.", "limitNotificationDescriptionWeb": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"linkGenerated": "We have generated a link to your recording.", "linkGenerated": "We have generated a link to your recording.",
"live": "LIVE", "live": "LIVE",
"localRecordingNoNotificationWarning": "The recording will not be announced to other participants. You will need to let them know that the meeting is recorded.",
"localRecordingWarning": "Make sure you select the current tab in order to use the right video and audio. The recording is currently limited to 1GB, which is around 100 minutes.", "localRecordingWarning": "Make sure you select the current tab in order to use the right video and audio. The recording is currently limited to 1GB, which is around 100 minutes.",
"loggedIn": "Logged in as {{userName}}", "loggedIn": "Logged in as {{userName}}",
"off": "Recording stopped", "off": "Recording stopped",

View File

@ -143,7 +143,6 @@ export default [
'enableLayerSuspension', 'enableLayerSuspension',
'enableLipSync', 'enableLipSync',
'enableLobbyChat', 'enableLobbyChat',
'enableLocalRecording',
'enableOpusRed', 'enableOpusRed',
'enableRemb', 'enableRemb',
'enableSaveLogs', 'enableSaveLogs',
@ -185,6 +184,7 @@ export default [
'ignoreStartMuted', 'ignoreStartMuted',
'inviteAppName', 'inviteAppName',
'liveStreamingEnabled', 'liveStreamingEnabled',
'localRecording',
'localSubject', 'localSubject',
'maxFullResolutionParticipants', 'maxFullResolutionParticipants',
'mouseMoveCallbackInterval', 'mouseMoveCallbackInterval',

View File

@ -178,9 +178,12 @@ MiddlewareRegistry.register(store => next => action => {
} }
case SET_LOCAL_PARTICIPANT_RECORDING_STATUS: { case SET_LOCAL_PARTICIPANT_RECORDING_STATUS: {
const state = store.getState();
const { recording } = action; const { recording } = action;
const localId = getLocalParticipant(store.getState())?.id; const localId = getLocalParticipant(state)?.id;
const { localRecording } = state['features/base/config'];
if (localRecording.notifyAllParticipants) {
store.dispatch(participantUpdated({ store.dispatch(participantUpdated({
// XXX Only the local participant is allowed to update without // XXX Only the local participant is allowed to update without
// stating the JitsiConference instance (i.e. participant property // stating the JitsiConference instance (i.e. participant property
@ -192,6 +195,7 @@ MiddlewareRegistry.register(store => next => action => {
local: true, local: true,
localRecording: recording localRecording: recording
})); }));
}
break; break;
} }

View File

@ -49,6 +49,11 @@ type Props = {
*/ */
_localRecordingEnabled: boolean, _localRecordingEnabled: boolean,
/**
* Whether we won't notify the other participants about the recording.
*/
_localRecordingNoNotification: boolean,
/** /**
* The color-schemed stylesheet of this component. * The color-schemed stylesheet of this component.
*/ */
@ -442,7 +447,8 @@ class StartRecordingDialogContent extends Component<Props> {
return ( return (
<Container> <Container>
<Container <Container
className = 'recording-header' className = { `recording-header ${this._shouldRenderNoIntegrationsContent()
? 'recording-header-line' : ''}` }
style = { styles.headerIntegrations }> style = { styles.headerIntegrations }>
<Container <Container
className = 'recording-icon-container'> className = 'recording-icon-container'>
@ -609,7 +615,14 @@ class StartRecordingDialogContent extends Component<Props> {
* @returns {React$Component} * @returns {React$Component}
*/ */
_renderLocalRecordingContent() { _renderLocalRecordingContent() {
const { _styles: styles, isValidating, t, _dialogStyles, selectedRecordingService } = this.props; const {
_styles: styles,
isValidating,
t,
_dialogStyles,
selectedRecordingService,
_localRecordingNoNotification
} = this.props;
if (!this._localRecordingAvailable) { if (!this._localRecordingAvailable) {
return null; return null;
@ -645,9 +658,14 @@ class StartRecordingDialogContent extends Component<Props> {
=== RECORDING_TYPES.LOCAL } /> === RECORDING_TYPES.LOCAL } />
</Container> </Container>
{selectedRecordingService === RECORDING_TYPES.LOCAL {selectedRecordingService === RECORDING_TYPES.LOCAL
&& <Text className = 'local-recording-warning'> && <>
<Text className = 'local-recording-warning text'>
{t('recording.localRecordingWarning')} {t('recording.localRecordingWarning')}
</Text> </Text>
{_localRecordingNoNotification && <Text className = 'local-recording-warning notification'>
{t('recording.localRecordingNoNotificationWarning')}
</Text>}
</>
} }
</Container> </Container>
@ -689,7 +707,8 @@ function _mapStateToProps(state) {
return { return {
..._abstractMapStateToProps(state), ..._abstractMapStateToProps(state),
isVpaas: isVpaasMeeting(state), isVpaas: isVpaasMeeting(state),
_localRecordingEnabled: state['features/base/config'].enableLocalRecording, _localRecordingEnabled: state['features/base/config'].localRecording.enable,
_localRecordingNoNotification: !state['features/base/config'].localRecording.notifyAllParticipants,
_styles: ColorSchemeRegistry.get(state, 'StartRecordingDialogContent') _styles: ColorSchemeRegistry.get(state, 'StartRecordingDialogContent')
}; };
} }

View File

@ -132,6 +132,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
} }
case START_LOCAL_RECORDING: { case START_LOCAL_RECORDING: {
const { localRecording } = getState()['features/base/config'];
try { try {
await LocalRecordingManager.startLocalRecording({ dispatch, await LocalRecordingManager.startLocalRecording({ dispatch,
getState }); getState });
@ -140,9 +142,12 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
titleKey: 'dialog.recording' titleKey: 'dialog.recording'
}; };
if (localRecording.notifyAllParticipants) {
dispatch(playSound(RECORDING_ON_SOUND_ID)); dispatch(playSound(RECORDING_ON_SOUND_ID));
}
dispatch(showNotification(props, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); dispatch(showNotification(props, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
dispatch(updateLocalRecordingStatus(true)); dispatch(updateLocalRecordingStatus(true));
sendAnalytics(createRecordingEvent('started', 'local'));
} catch (err) { } catch (err) {
logger.error('Capture failed', err); logger.error('Capture failed', err);
@ -158,10 +163,14 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => async action =>
} }
case STOP_LOCAL_RECORDING: { case STOP_LOCAL_RECORDING: {
const { localRecording } = getState()['features/base/config'];
if (LocalRecordingManager.isRecordingLocally()) { if (LocalRecordingManager.isRecordingLocally()) {
LocalRecordingManager.stopLocalRecording(); LocalRecordingManager.stopLocalRecording();
dispatch(playSound(RECORDING_OFF_SOUND_ID));
dispatch(updateLocalRecordingStatus(false)); dispatch(updateLocalRecordingStatus(false));
if (localRecording.notifyAllParticipants) {
dispatch(playSound(RECORDING_OFF_SOUND_ID));
}
} }
break; break;
} }