Add recording file sharing switch

This commit is contained in:
Bettenbuk Zoltan 2019-04-23 14:30:46 +02:00 committed by Дамян Минков
parent 2180d33e3d
commit b7198ba4b3
9 changed files with 150 additions and 16 deletions

BIN
images/icon-users.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -515,6 +515,7 @@
"expandedOn": "The meeting is currently being recorded.", "expandedOn": "The meeting is currently being recorded.",
"expandedPending": "Recording is being started...", "expandedPending": "Recording is being started...",
"failedToStart": "Recording failed to start", "failedToStart": "Recording failed to start",
"fileSharingdescription": "Share recording with meeting participants",
"live": "LIVE", "live": "LIVE",
"loggedIn": "Logged in as __userName__", "loggedIn": "Logged in as __userName__",
"off": "Recording stopped", "off": "Recording stopped",

View File

@ -243,5 +243,10 @@ ColorSchemeRegistry.register('Dialog', {
text: { text: {
...brandedDialogText ...brandedDialogText
},
topBorderContainer: {
borderTopColor: schemeColor('border'),
borderTopWidth: 1
} }
}); });

View File

@ -31,6 +31,12 @@ type Props = {
*/ */
_fileRecordingsServiceEnabled: boolean, _fileRecordingsServiceEnabled: boolean,
/**
* Whether to show the possibility to share file recording with other people (e.g. meeting participants), based on
* the actual implementation on the backend.
*/
_fileRecordingsServiceSharingEnabled: boolean,
/** /**
* If true the dropbox integration is enabled, otherwise - disabled. * If true the dropbox integration is enabled, otherwise - disabled.
*/ */
@ -69,6 +75,11 @@ type State = {
*/ */
selectedRecordingService: ?string, selectedRecordingService: ?string,
/**
* True if the user requested the service to share the recording with others.
*/
sharingEnabled: boolean,
/** /**
* Number of MiB of available space in user's Dropbox account. * Number of MiB of available space in user's Dropbox account.
*/ */
@ -96,6 +107,7 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
this._onSubmit = this._onSubmit.bind(this); this._onSubmit = this._onSubmit.bind(this);
this._onSelectedRecordingServiceChanged this._onSelectedRecordingServiceChanged
= this._onSelectedRecordingServiceChanged.bind(this); = this._onSelectedRecordingServiceChanged.bind(this);
this._onSharingSettingChanged = this._onSharingSettingChanged.bind(this);
let selectedRecordingService; let selectedRecordingService;
@ -112,6 +124,7 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
isTokenValid: false, isTokenValid: false,
isValidating: false, isValidating: false,
userName: undefined, userName: undefined,
sharingEnabled: true,
spaceLeft: undefined, spaceLeft: undefined,
selectedRecordingService selectedRecordingService
}; };
@ -154,6 +167,19 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
return this.props._isDropboxEnabled; return this.props._isDropboxEnabled;
} }
_onSharingSettingChanged: () => void;
/**
* Callback to handle sharing setting change from the dialog.
*
* @returns {void}
*/
_onSharingSettingChanged() {
this.setState({
sharingEnabled: !this.state.sharingEnabled
});
}
_onSelectedRecordingServiceChanged: (string) => void; _onSelectedRecordingServiceChanged: (string) => void;
/** /**
@ -233,6 +259,11 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
}); });
attributes.type = RECORDING_TYPES.DROPBOX; attributes.type = RECORDING_TYPES.DROPBOX;
} else { } else {
appData = JSON.stringify({
'file_recording_metadata': {
'share': this.state.sharingEnabled
}
});
attributes.type = RECORDING_TYPES.JITSI_REC_SERVICE; attributes.type = RECORDING_TYPES.JITSI_REC_SERVICE;
} }
@ -266,12 +297,16 @@ class AbstractStartRecordingDialog extends Component<Props, State> {
* @returns {{ * @returns {{
* _appKey: string, * _appKey: string,
* _conference: JitsiConference, * _conference: JitsiConference,
* _fileRecordingsServiceEnabled: boolean,
* _fileRecordingsServiceSharingEnabled: boolean,
* _isDropboxEnabled: boolean,
* _token: string * _token: string
* }} * }}
*/ */
export function mapStateToProps(state: Object) { export function mapStateToProps(state: Object) {
const { const {
fileRecordingsServiceEnabled = false, fileRecordingsServiceEnabled = false,
fileRecordingsServiceSharingEnabled = false,
dropbox = {} dropbox = {}
} = state['features/base/config']; } = state['features/base/config'];
@ -279,6 +314,7 @@ export function mapStateToProps(state: Object) {
_appKey: dropbox.appKey, _appKey: dropbox.appKey,
_conference: state['features/base/conference'].conference, _conference: state['features/base/conference'].conference,
_fileRecordingsServiceEnabled: fileRecordingsServiceEnabled, _fileRecordingsServiceEnabled: fileRecordingsServiceEnabled,
_fileRecordingsServiceSharingEnabled: fileRecordingsServiceSharingEnabled,
_isDropboxEnabled: isDropboxEnabled(state), _isDropboxEnabled: isDropboxEnabled(state),
_token: state['features/dropbox'].token _token: state['features/dropbox'].token
}; };

View File

@ -25,6 +25,7 @@ import { authorizeDropbox, updateDropboxToken } from '../../../dropbox';
import { import {
default as styles, default as styles,
DROPBOX_LOGO, DROPBOX_LOGO,
ICON_SHARE,
JITSI_LOGO JITSI_LOGO
} from './styles'; } from './styles';
@ -49,6 +50,12 @@ type Props = {
*/ */
fileRecordingsServiceEnabled: boolean, fileRecordingsServiceEnabled: boolean,
/**
* Whether to show the possibility to share file recording with other people (e.g. meeting participants), based on
* the actual implementation on the backend.
*/
fileRecordingsServiceSharingEnabled: boolean,
/** /**
* If true the content related to the integrations will be shown. * If true the content related to the integrations will be shown.
*/ */
@ -70,11 +77,21 @@ type Props = {
*/ */
onChange: Function, onChange: Function,
/**
* Callback to be invoked on sharing setting change.
*/
onSharingSettingChanged: Function,
/** /**
* The currently selected recording service of type: RECORDING_TYPES. * The currently selected recording service of type: RECORDING_TYPES.
*/ */
selectedRecordingService: ?string, selectedRecordingService: ?string,
/**
* Boolean to set file recording sharing on or off.
*/
sharingSetting: boolean,
/** /**
* Number of MiB of available space in user's Dropbox account. * Number of MiB of available space in user's Dropbox account.
*/ */
@ -131,6 +148,60 @@ class StartRecordingDialogContent extends Component<Props> {
); );
} }
/**
* Renders the file recording service sharing options, if enabled.
*
* @returns {React$Component}
*/
_renderFileSharingContent() {
if (!this.props.fileRecordingsServiceSharingEnabled) {
return null;
}
const {
_dialogStyles,
isValidating,
onSharingSettingChanged,
selectedRecordingService,
sharingSetting, t } = this.props;
const controlDisabled = selectedRecordingService !== RECORDING_TYPES.JITSI_REC_SERVICE;
return (
<Container
className = 'recording-header'
key = 'fileSharingSetting'
style = { [
styles.header,
_dialogStyles.topBorderContainer,
controlDisabled ? styles.controlDisabled : null
] }>
<Container className = 'recording-icon-container'>
<Image
className = 'recording-icon'
src = { ICON_SHARE }
style = { styles.recordingIcon } />
</Container>
<Text
className = 'recording-title'
style = {{
..._dialogStyles.text,
...styles.title
}}>
{ t('recording.fileSharingdescription') }
</Text>
<Switch
className = 'recording-switch'
disabled = { controlDisabled || isValidating }
onValueChange
= { onSharingSettingChanged }
style = { styles.switch }
trackColor = {{ false: ColorPalette.lightGrey }}
value = { !controlDisabled && sharingSetting } />
</Container>
);
}
/** /**
* Renders the content in case no integrations were enabled. * Renders the content in case no integrations were enabled.
* *
@ -162,9 +233,10 @@ class StartRecordingDialogContent extends Component<Props> {
=== RECORDING_TYPES.JITSI_REC_SERVICE } /> === RECORDING_TYPES.JITSI_REC_SERVICE } />
) : null; ) : null;
return ( return [
<Container <Container
className = 'recording-header' className = 'recording-header'
key = 'noIntegrationSetting'
style = { styles.header }> style = { styles.header }>
<Container className = 'recording-icon-container'> <Container className = 'recording-icon-container'>
<Image <Image
@ -181,8 +253,9 @@ class StartRecordingDialogContent extends Component<Props> {
{ t('recording.serviceDescription') } { t('recording.serviceDescription') }
</Text> </Text>
{ switchContent } { switchContent }
</Container> </Container>,
); this._renderFileSharingContent()
];
} }
/** /**
@ -267,6 +340,7 @@ class StartRecordingDialogContent extends Component<Props> {
className = 'authorization-panel'> className = 'authorization-panel'>
{ content } { content }
</Container> </Container>
{ this._renderFileSharingContent() }
</Container> </Container>
); );
} }

View File

@ -28,10 +28,15 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
isTokenValid, isTokenValid,
isValidating, isValidating,
selectedRecordingService, selectedRecordingService,
sharingEnabled,
spaceLeft, spaceLeft,
userName userName
} = this.state; } = this.state;
const { _fileRecordingsServiceEnabled, _isDropboxEnabled } = this.props; const {
_fileRecordingsServiceEnabled,
_fileRecordingsServiceSharingEnabled,
_isDropboxEnabled
} = this.props;
// disable ok button id recording service is shown only, when // disable ok button id recording service is shown only, when
// validating dropbox token, if that is not enabled we either always // validating dropbox token, if that is not enabled we either always
@ -46,13 +51,15 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
okDisabled = { isOkDisabled } okDisabled = { isOkDisabled }
onSubmit = { this._onSubmit } > onSubmit = { this._onSubmit } >
<StartRecordingDialogContent <StartRecordingDialogContent
fileRecordingsServiceEnabled fileRecordingsServiceEnabled = { _fileRecordingsServiceEnabled }
= { _fileRecordingsServiceEnabled } fileRecordingsServiceSharingEnabled = { _fileRecordingsServiceSharingEnabled }
integrationsEnabled = { this._areIntegrationsEnabled() } integrationsEnabled = { this._areIntegrationsEnabled() }
isTokenValid = { isTokenValid } isTokenValid = { isTokenValid }
isValidating = { isValidating } isValidating = { isValidating }
onChange = { this._onSelectedRecordingServiceChanged } onChange = { this._onSelectedRecordingServiceChanged }
onSharingSettingChanged = { this._onSharingSettingChanged }
selectedRecordingService = { selectedRecordingService } selectedRecordingService = { selectedRecordingService }
sharingSetting = { sharingEnabled }
spaceLeft = { spaceLeft } spaceLeft = { spaceLeft }
userName = { userName } /> userName = { userName } />
</CustomSubmitDialog> </CustomSubmitDialog>
@ -62,6 +69,7 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
_areIntegrationsEnabled: () => boolean; _areIntegrationsEnabled: () => boolean;
_onSubmit: () => boolean _onSubmit: () => boolean
_onSelectedRecordingServiceChanged: (string) => void; _onSelectedRecordingServiceChanged: (string) => void;
_onSharingSettingChanged: () => void;
} }
export default translate(connect(mapStateToProps)(StartRecordingDialog)); export default translate(connect(mapStateToProps)(StartRecordingDialog));

View File

@ -1,26 +1,30 @@
// @flow // @flow
import { BoxModel, createStyleSheet, ColorPalette } from '../../../base/styles'; import { BoxModel, ColorPalette } from '../../../base/styles';
// XXX The "standard" {@code BoxModel.padding} has been deemed insufficient in // XXX The "standard" {@code BoxModel.padding} has been deemed insufficient in
// the special case(s) of the recording feature bellow. // the special case(s) of the recording feature bellow.
const _PADDING = BoxModel.padding * 1.5; const _PADDING = BoxModel.padding * 1.5;
export const DROPBOX_LOGO export const DROPBOX_LOGO = require('../../../../../images/dropboxLogo_square.png');
= require('../../../../../images/dropboxLogo_square.png');
export const JITSI_LOGO export const ICON_SHARE = require('../../../../../images/icon-users.png');
= require('../../../../../images/jitsiLogo_square.png');
export const JITSI_LOGO = require('../../../../../images/jitsiLogo_square.png');
/** /**
* The styles of the React {@code Components} of the feature recording. * The styles of the React {@code Components} of the feature recording.
*/ */
export default createStyleSheet({ export default {
container: { container: {
flex: 0, flex: 0,
flexDirection: 'column' flexDirection: 'column'
}, },
controlDisabled: {
opacity: 0.5
},
header: { header: {
alignItems: 'center', alignItems: 'center',
flex: 0, flex: 0,
@ -62,4 +66,4 @@ export default createStyleSheet({
text: { text: {
color: ColorPalette.white color: ColorPalette.white
} }
}); };

View File

@ -4,4 +4,6 @@ export default {};
export const DROPBOX_LOGO = 'images/dropboxLogo_square.png'; export const DROPBOX_LOGO = 'images/dropboxLogo_square.png';
export const ICON_SHARE = 'images/icon-users.png';
export const JITSI_LOGO = 'images/jitsiLogo_square.png'; export const JITSI_LOGO = 'images/jitsiLogo_square.png';

View File

@ -28,10 +28,11 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
isTokenValid, isTokenValid,
isValidating, isValidating,
selectedRecordingService, selectedRecordingService,
sharingEnabled,
spaceLeft, spaceLeft,
userName userName
} = this.state; } = this.state;
const { _fileRecordingsServiceEnabled, _isDropboxEnabled } = this.props; const { _fileRecordingsServiceEnabled, _fileRecordingsServiceSharingEnabled, _isDropboxEnabled } = this.props;
// disable ok button id recording service is shown only, when // disable ok button id recording service is shown only, when
// validating dropbox token, if that is not enabled we either always // validating dropbox token, if that is not enabled we either always
@ -49,13 +50,15 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
titleKey = 'dialog.startRecording' titleKey = 'dialog.startRecording'
width = 'small'> width = 'small'>
<StartRecordingDialogContent <StartRecordingDialogContent
fileRecordingsServiceEnabled fileRecordingsServiceEnabled = { _fileRecordingsServiceEnabled }
= { _fileRecordingsServiceEnabled } fileRecordingsServiceSharingEnabled = { _fileRecordingsServiceSharingEnabled }
integrationsEnabled = { this._areIntegrationsEnabled() } integrationsEnabled = { this._areIntegrationsEnabled() }
isTokenValid = { isTokenValid } isTokenValid = { isTokenValid }
isValidating = { isValidating } isValidating = { isValidating }
onChange = { this._onSelectedRecordingServiceChanged } onChange = { this._onSelectedRecordingServiceChanged }
onSharingSettingChanged = { this._onSharingSettingChanged }
selectedRecordingService = { selectedRecordingService } selectedRecordingService = { selectedRecordingService }
sharingSetting = { sharingEnabled }
spaceLeft = { spaceLeft } spaceLeft = { spaceLeft }
userName = { userName } /> userName = { userName } />
</Dialog> </Dialog>
@ -65,6 +68,7 @@ class StartRecordingDialog extends AbstractStartRecordingDialog {
_areIntegrationsEnabled: () => boolean; _areIntegrationsEnabled: () => boolean;
_onSubmit: () => boolean; _onSubmit: () => boolean;
_onSelectedRecordingServiceChanged: (string) => void; _onSelectedRecordingServiceChanged: (string) => void;
_onSharingSettingChanged: () => void;
} }
export default translate(connect(mapStateToProps)(StartRecordingDialog)); export default translate(connect(mapStateToProps)(StartRecordingDialog));