[RN] Add RecordingLabel indicator for mobile

This commit is contained in:
Bettenbuk Zoltan 2018-05-23 15:44:58 +02:00 committed by Saúl Ibarra Corretgé
parent 118250750a
commit 5499599720
6 changed files with 231 additions and 11 deletions

View File

@ -10,6 +10,7 @@ import { appNavigate } from '../../app';
import { connect, disconnect } from '../../base/connection'; import { connect, disconnect } from '../../base/connection';
import { DialogContainer } from '../../base/dialog'; import { DialogContainer } from '../../base/dialog';
import { CalleeInfoContainer } from '../../base/jwt'; import { CalleeInfoContainer } from '../../base/jwt';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
import { getParticipantCount } from '../../base/participants'; import { getParticipantCount } from '../../base/participants';
import { Container, LoadingIndicator, TintedView } from '../../base/react'; import { Container, LoadingIndicator, TintedView } from '../../base/react';
import { TestConnectionInfo } from '../../base/testing'; import { TestConnectionInfo } from '../../base/testing';
@ -17,6 +18,7 @@ import { createDesiredLocalTracks } from '../../base/tracks';
import { ConferenceNotification } from '../../calendar-sync'; import { ConferenceNotification } from '../../calendar-sync';
import { Filmstrip } from '../../filmstrip'; import { Filmstrip } from '../../filmstrip';
import { LargeVideo } from '../../large-video'; import { LargeVideo } from '../../large-video';
import { RecordingLabel } from '../../recording';
import { setToolboxVisible, Toolbox } from '../../toolbox'; import { setToolboxVisible, Toolbox } from '../../toolbox';
import { VideoQualityLabel } from '../../video-quality'; import { VideoQualityLabel } from '../../video-quality';
@ -246,7 +248,14 @@ class Conference extends Component<Props> {
* participants. * participants.
*/} */}
<Filmstrip /> <Filmstrip />
<VideoQualityLabel style = { styles.videoQualityLabel } />
<View style = { styles.indicatorContainer }>
<RecordingLabel
mode = { JitsiRecordingConstants.mode.FILE } />
<RecordingLabel
mode = { JitsiRecordingConstants.mode.STREAM } />
<VideoQualityLabel />
</View>
</View> </View>
<TestConnectionInfo /> <TestConnectionInfo />

View File

@ -18,6 +18,18 @@ export default createStyleSheet({
flex: 1 flex: 1
}), }),
/**
* View that contains the indicators.
*/
indicatorContainer: {
flex: 1,
flexDirection: 'row',
margin: BoxModel.margin,
position: 'absolute',
right: 0,
top: 0
},
/** /**
* The style of the {@link View} which expands over the whole * The style of the {@link View} which expands over the whole
* {@link Conference} area and splits it between the {@link Filmstrip} and * {@link Conference} area and splits it between the {@link Filmstrip} and
@ -35,11 +47,5 @@ export default createStyleSheet({
// On iPhone X there is the notch. In the two cases BoxModel.margin is // On iPhone X there is the notch. In the two cases BoxModel.margin is
// not enough. // not enough.
top: BoxModel.margin * 3 top: BoxModel.margin * 3
},
videoQualityLabel: {
right: 0,
top: 0,
position: 'absolute'
} }
}); });

View File

@ -0,0 +1,66 @@
// @flow
import { Component } from 'react';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
/**
* NOTE: Web currently renders multiple indicators if multiple recording
* sessions are running. This is however may not be a good UX as it's not
* obvious why there are multiple similar 'REC' indicators rendered. Mobile
* only renders one indicator if there is at least one recording session
* running. These boolean are shared across the two components to make it
* easier to align web's behaviour to mobile's later if necessary.
*/
export type Props = {
/**
* True if there is an active recording with the provided mode therefore the
* component must be rendered.
*/
_visible: boolean,
/**
* The recording mode this indicator should display.
*/
mode: string,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/**
* Abstract class for the {@code RecordingLabel} component.
*/
export default class AbstractRecordingLabel<P: Props, S: *>
extends Component<P, S> {
}
/**
* Maps (parts of) the Redux state to the associated
* {@code AbstractRecordingLabel}'s props.
*
* @param {Object} state - The Redux state.
* @param {Props} ownProps - The component's own props.
* @private
* @returns {{
* _visible: boolean
* }}
*/
export function _abstractMapStateToProps(state: Object, ownProps: Props) {
const { mode } = ownProps;
const _recordingSessions = state['features/recording'].sessionDatas;
const _visible
= Array.isArray(_recordingSessions)
&& _recordingSessions.some(
session => session.status === JitsiRecordingConstants.status.ON
&& session.mode === mode
);
return {
_visible
};
}

View File

@ -0,0 +1,91 @@
// @flow
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../base/i18n';
import { CircularLabel } from '../../base/label';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
import { combineStyles } from '../../base/styles';
import AbstractRecordingLabel, {
type Props as AbstractProps,
_abstractMapStateToProps
} from './AbstractRecordingLabel';
import styles from './styles';
type Props = AbstractProps & {
/**
* Style of the component passed as props.
*/
style: ?Object
};
/**
* Implements a React {@link Component} which displays the current state of
* conference recording.
*
* @extends {Component}
*/
class RecordingLabel extends AbstractRecordingLabel<Props, *> {
/**
* Implements React {@code Component}'s render.
*
* @inheritdoc
*/
render() {
const { _visible, mode, style, t } = this.props;
if (!_visible) {
return null;
}
let labelKey;
let indicatorStyle;
switch (mode) {
case JitsiRecordingConstants.mode.STREAM:
labelKey = 'recording.live';
indicatorStyle = styles.indicatorLive;
break;
case JitsiRecordingConstants.mode.FILE:
labelKey = 'recording.rec';
indicatorStyle = styles.indicatorRecording;
break;
default:
// Invalid mode is passed to the component.
return null;
}
return (
<CircularLabel
label = { t(labelKey) }
style = {
combineStyles(indicatorStyle, style)
} />
);
}
}
/**
* Maps (parts of) the Redux state to the associated
* {@code RecordingLabel}'s props.
*
* NOTE: This component has no props other than the abstract ones but keeping
* the coding style the same for consistency reasons.
*
* @param {Object} state - The Redux state.
* @param {Object} ownProps - The component's own props.
* @private
* @returns {{
* }}
*/
function _mapStateToProps(state: Object, ownProps: Object) {
return {
..._abstractMapStateToProps(state, ownProps)
};
}
export default translate(connect(_mapStateToProps)(RecordingLabel));

View File

@ -1,11 +1,17 @@
// @flow // @flow
import React, { Component } from 'react'; import React from 'react';
import { connect } from 'react-redux';
import { CircularLabel } from '../../base/label'; import { CircularLabel } from '../../base/label';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet'; import { JitsiRecordingConstants } from '../../base/lib-jitsi-meet';
import AbstractRecordingLabel, {
type Props as AbstractProps,
_abstractMapStateToProps
} from './AbstractRecordingLabel';
/** /**
* The translation keys to use when displaying messages. The values are set * The translation keys to use when displaying messages. The values are set
* lazily to work around circular dependency issues with lib-jitsi-meet causing * lazily to work around circular dependency issues with lib-jitsi-meet causing
@ -61,7 +67,7 @@ function _getTranslationKeysByMode() {
/** /**
* The type of the React {@code Component} props of {@link RecordingLabel}. * The type of the React {@code Component} props of {@link RecordingLabel}.
*/ */
type Props = { type Props = AbstractProps & {
/** /**
* The redux representation of a recording session. * The redux representation of a recording session.
@ -91,7 +97,7 @@ type State = {
* *
* @extends {Component} * @extends {Component}
*/ */
class RecordingLabel extends Component<Props, State> { class RecordingLabel extends AbstractRecordingLabel<Props, State> {
_autohideTimeout: number; _autohideTimeout: number;
state = { state = {
@ -219,4 +225,23 @@ class RecordingLabel extends Component<Props, State> {
} }
} }
export default translate(RecordingLabel); /**
* Maps (parts of) the Redux state to the associated
* {@code RecordingLabel}'s props.
*
* NOTE: This component has no props other than the abstract ones but keeping
* the coding style the same for consistency reasons.
*
* @param {Object} state - The Redux state.
* @param {Object} ownProps - The component's own props.
* @private
* @returns {{
* }}
*/
function _mapStateToProps(state: Object, ownProps: Object) {
return {
..._abstractMapStateToProps(state, ownProps)
};
}
export default translate(connect(_mapStateToProps)(RecordingLabel));

View File

@ -0,0 +1,23 @@
// @flow
import { ColorPalette, createStyleSheet } from '../../base/styles';
/**
* The styles of the React {@code Components} of the feature recording.
*/
export default createStyleSheet({
/**
* Style for the recording indicator.
*/
indicatorLive: {
backgroundColor: ColorPalette.blue
},
/**
* Style for the recording indicator.
*/
indicatorRecording: {
backgroundColor: ColorPalette.red
}
});