Files
jitsi-meet/react/features/recording/components/RecordingLabel.web.js
virtuacoplenny ee74f11c3d feat(recording): frontend logic can support live streaming and recording (#2952)
* feat(recording): frontend logic can support live streaming and recording

Instead of either live streaming or recording, now both can live together. The
changes to facilitate such include the following:
- Killing the state storing in Recording.js. Instead state is stored in the lib
  and updated in redux for labels to display the necessary state updates.
- Creating a new container, Labels, for recording labels. Previously labels were
  manually created and positioned. The container can create a reasonable number
  of labels and only the container itself needs to be positioned with CSS. The
  VideoQualityLabel has been shoved into the container as well because it moves
  along with the recording labels.
- The action for updating recording state has been modified to enable updating
  an array of recording sessions to support having multiple sessions.
- Confirmation dialogs for stopping and starting a file recording session have
  been created, as they previously were jquery modals opened by Recording.js.
- Toolbox.web displays live streaming and recording buttons based on
  configuration instead of recording availability.
- VideoQualityLabel and RecordingLabel have been simplified to remove any
  positioning logic, as the Labels container handles such.
- Previous recording state update logic has been moved into the RecordingLabel
  component. Each RecordingLabel is in charge of displaying state for a
  recording session. The display UX has been left alone.
- Sipgw availability is no longer broadcast so remove logic depending on its
  state. Some moving around of code was necessary to get around linting errors
  about the existing code being too deeply nested (even though I didn't touch
  it).

* work around lib-jitsi-meet circular dependency issues

* refactor labels to use html base

* pass in translation keys to video quality label

* add video quality classnames for torture tests

* break up, rearrange recorder session update listener

* add comment about disabling startup resize animation

* rename session to sessionData

* chore(deps): update to latest lib for recording changes
2018-05-16 07:00:16 -07:00

223 lines
5.8 KiB
JavaScript

// @flow
import React, { Component } from 'react';
import { CircularLabel } from '../../base/label';
import { translate } from '../../base/i18n';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
/**
* The translation keys to use when displaying messages. The values are set
* lazily to work around circular dependency issues with lib-jitsi-meet causing
* undefined imports.
*
* @private
* @type {Object}
*/
let TRANSLATION_KEYS_BY_MODE = null;
/**
* Lazily initializes TRANSLATION_KEYS_BY_MODE with translation keys to be used
* by the {@code RecordingLabel} for messaging recording session state.
*
* @private
* @returns {Object}
*/
function _getTranslationKeysByMode() {
if (!TRANSLATION_KEYS_BY_MODE) {
const {
error: errorConstants,
mode: modeConstants,
status: statusConstants
} = JitsiRecordingConstants;
TRANSLATION_KEYS_BY_MODE = {
[modeConstants.FILE]: {
status: {
[statusConstants.PENDING]: 'recording.pending',
[statusConstants.OFF]: 'recording.off'
},
errors: {
[errorConstants.BUSY]: 'recording.failedToStart',
[errorConstants.ERROR]: 'recording.error'
}
},
[modeConstants.STREAM]: {
status: {
[statusConstants.PENDING]: 'liveStreaming.pending',
[statusConstants.OFF]: 'liveStreaming.off'
},
errors: {
[errorConstants.BUSY]: 'liveStreaming.busy',
[errorConstants.ERROR]: 'liveStreaming.error'
}
}
};
}
return TRANSLATION_KEYS_BY_MODE;
}
/**
* The type of the React {@code Component} props of {@link RecordingLabel}.
*/
type Props = {
/**
* The redux representation of a recording session.
*/
session: Object,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/**
* The type of the React {@code Component} state of {@link RecordingLabel}.
*/
type State = {
/**
* Whether or not the {@link RecordingLabel} should be invisible.
*/
hidden: boolean
};
/**
* Implements a React {@link Component} which displays the current state of
* conference recording.
*
* @extends {Component}
*/
class RecordingLabel extends Component<Props, State> {
_autohideTimeout: number;
state = {
hidden: false
};
static defaultProps = {
session: {}
};
/**
* Sets a timeout to automatically hide the {@link RecordingLabel} if the
* recording session started as failed.
*
* @inheritdoc
*/
componentDidMount() {
if (this.props.session.status === JitsiRecordingConstants.status.OFF) {
this._setHideTimeout();
}
}
/**
* Sets a timeout to automatically hide {the @link RecordingLabel} if it has
* transitioned to off.
*
* @inheritdoc
*/
componentWillReceiveProps(nextProps) {
const { status } = this.props.session;
const nextStatus = nextProps.session.status;
if (status !== JitsiRecordingConstants.status.OFF
&& nextStatus === JitsiRecordingConstants.status.OFF) {
this._setHideTimeout();
}
}
/**
* Clears the timeout for automatically hiding the {@link RecordingLabel}.
*
* @inheritdoc
*/
componentWillUnmount() {
this._clearAutoHideTimeout();
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
if (this.state.hidden) {
return null;
}
const {
error: errorConstants,
mode: modeConstants,
status: statusConstants
} = JitsiRecordingConstants;
const { session } = this.props;
const allTranslationKeys = _getTranslationKeysByMode();
const translationKeys = allTranslationKeys[session.mode];
let circularLabelClass, circularLabelKey, messageKey;
switch (session.status) {
case statusConstants.OFF: {
if (session.error) {
messageKey = translationKeys.errors[session.error]
|| translationKeys.errors[errorConstants.ERROR];
} else {
messageKey = translationKeys.status[statusConstants.OFF];
}
break;
}
case statusConstants.ON:
circularLabelClass = session.mode;
circularLabelKey = session.mode === modeConstants.STREAM
? 'recording.live' : 'recording.rec';
break;
case statusConstants.PENDING:
messageKey = translationKeys.status[statusConstants.PENDING];
break;
}
const className = `recording-label ${
messageKey ? 'center-message' : ''}`;
return (
<div className = { className }>
{ messageKey
? <div>
{ this.props.t(messageKey) }
</div>
: <CircularLabel className = { circularLabelClass }>
{ this.props.t(circularLabelKey) }
</CircularLabel> }
</div>
);
}
/**
* Clears the timeout for automatically hiding {@link RecordingLabel}.
*
* @private
* @returns {void}
*/
_clearAutoHideTimeout() {
clearTimeout(this._autohideTimeout);
}
/**
* Sets a timeout to automatically hide {@link RecordingLabel}.
*
* @private
* @returns {void}
*/
_setHideTimeout() {
this._autohideTimeout = setTimeout(() => {
this.setState({ hidden: true });
}, 5000);
}
}
export default translate(RecordingLabel);