Compare commits

..

1 Commits

Author SHA1 Message Date
Saúl Ibarra Corretgé
8c68f78db3 rn,responsive-ui: refactor dimensions detection
Use a dimensions detecting root component. The Dimensions module does not
measure the app's view size, but the Window, which may not be the same, for
example on iOS when PiP is used.

Also refactor the aspect ratio wrap component since it can be taken directly
from the store.

Last, remove the use of DimensionsDetector on LargeVideo and TileView since they
occupy the full-screen anyway.

Fixes PiP mode on iOS.
2020-06-02 13:30:07 +02:00
14 changed files with 12 additions and 319 deletions

View File

@@ -217,21 +217,6 @@ var config = {
// Default value for the channel "last N" attribute. -1 for unlimited.
channelLastN: -1,
// // Options for the recording limit notification.
// recordingLimit: {
//
// // The recording limit in minutes. Note: This number appears in the notification text
// // but doesn't enforce the actual recording time limit. This should be configured in
// // jibri!
// limit: 60,
//
// // The name of the app with unlimited recordings.
// appName: 'Unlimited recordings APP',
//
// // The URL of the app with unlimited recordings.
// appURL: 'https://unlimited.recordings.app.com/'
// },
// Disables or enables RTX (RFC 4588) (defaults to false).
// disableRtx: false,

View File

@@ -395,8 +395,6 @@
"videoQuality": "Manage call quality"
},
"liveStreaming": {
"limitNotificationDescriptionWeb": "Due to high demand your streaming will be limited to {{limit}} min. For unlimited streaming try <a href={{url}} rel='noopener noreferrer' target='_blank'>{{app}}</a>.",
"limitNotificationDescriptionNative": "Your streaming will be limited to {{limit}} min. For unlimited streaming try {{app}}.",
"busy": "We're working on freeing streaming resources. Please try again in a few minutes.",
"busyTitle": "All streamers are currently busy",
"changeSignIn": "Switch accounts.",
@@ -554,8 +552,6 @@
},
"raisedHand": "Would like to speak",
"recording": {
"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>.",
"limitNotificationDescriptionNative": "Due to high demand your recording will be limited to {{limit}} min. For unlimited recordings try <3>{{app}}</3>.",
"authDropboxText": "Upload to Dropbox",
"availableSpace": "Available space: {{spaceLeft}} MB (approximately {{duration}} minutes of recording)",
"beta": "BETA",

View File

@@ -8,21 +8,16 @@ import {
sendAnalytics
} from '../../react/features/analytics';
import {
getCurrentConference,
sendTones,
setPassword,
setSubject
} from '../../react/features/base/conference';
import { parseJWTFromURLParams } from '../../react/features/base/jwt';
import { JitsiRecordingConstants } from '../../react/features/base/lib-jitsi-meet';
import {
processExternalDeviceRequest
} from '../../react/features/device-selection/functions';
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
import { setE2EEKey } from '../../react/features/e2ee';
import { invite } from '../../react/features/invite';
import { RECORDING_TYPES } from '../../react/features/recording/constants';
import { getActiveSession } from '../../react/features/recording/functions';
import { muteAllParticipants } from '../../react/features/remote-video-menu/actions';
import { toggleTileView } from '../../react/features/video-layout';
import { setVideoQuality } from '../../react/features/video-quality';
@@ -195,114 +190,6 @@ function initCommands() {
logger.debug('Set video quality command received');
sendAnalytics(createApiEvent('set.video.quality'));
APP.store.dispatch(setVideoQuality(frameHeight));
},
/**
* Starts a file recording or streaming depending on the passed on params.
* For youtube streams, `youtubeStreamKey` must be passed on. `youtubeBroadcastID` is optional.
* For dropbox recording, recording `mode` should be `file` and a dropbox oauth2 token must be provided.
* For file recording, recording `mode` should be `file` and optionally `shouldShare` could be passed on.
* No other params should be passed.
*
* @param { string } arg.mode - Recording mode, either `file` or `stream`.
* @param { string } arg.dropboxToken - Dropbox oauth2 token.
* @param { boolean } arg.shouldShare - Whether the recording should be shared with the participants or not.
* Only applies to certain jitsi meet deploys.
* @param { string } arg.youtubeStreamKey - The youtube stream key.
* @param { string } arg.youtubeBroadcastID - The youtube broacast ID.
* @returns {void}
*/
'start-recording': ({ mode, dropboxToken, shouldShare, youtubeStreamKey, youtubeBroadcastID }) => {
const state = APP.store.getState();
const conference = getCurrentConference(state);
if (!conference) {
logger.error('Conference is not defined');
return;
}
if (dropboxToken && !isDropboxEnabled(state)) {
logger.error('Failed starting recording: dropbox is not enabled on this deployment');
return;
}
if (mode === JitsiRecordingConstants.mode.STREAM && !youtubeStreamKey) {
logger.error('Failed starting recording: missing youtube stream key');
return;
}
let recordingConfig;
if (mode === JitsiRecordingConstants.mode.FILE) {
if (dropboxToken) {
recordingConfig = {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
'upload_credentials': {
'service_name': RECORDING_TYPES.DROPBOX,
'token': dropboxToken
}
}
})
};
} else {
recordingConfig = {
mode: JitsiRecordingConstants.mode.FILE,
appData: JSON.stringify({
'file_recording_metadata': {
'share': shouldShare
}
})
};
}
} else if (mode === JitsiRecordingConstants.mode.STREAM) {
recordingConfig = {
broadcastId: youtubeBroadcastID,
mode: JitsiRecordingConstants.mode.STREAM,
streamId: youtubeStreamKey
};
} else {
logger.error('Invalid recording mode provided');
return;
}
conference.startRecording(recordingConfig);
},
/**
* Stops a recording or streaming in progress.
*
* @param {string} mode - `file` or `stream`.
* @returns {void}
*/
'stop-recording': mode => {
const state = APP.store.getState();
const conference = getCurrentConference(state);
if (!conference) {
logger.error('Conference is not defined');
return;
}
if (![ JitsiRecordingConstants.mode.FILE, JitsiRecordingConstants.mode.STREAM ].includes(mode)) {
logger.error('Invalid recording mode provided!');
return;
}
const activeSession = getActiveSession(state, mode);
if (activeSession && activeSession.id) {
conference.stopRecording(activeSession.id);
} else {
logger.error('No recording or streaming session found');
}
}
};
transport.on('event', ({ data, name }) => {
@@ -627,8 +514,7 @@ class API {
notifyDeviceListChanged(devices: Object) {
this._sendEvent({
name: 'device-list-changed',
devices
});
devices });
}
/**

View File

@@ -37,8 +37,6 @@ const commands = {
sendEndpointTextMessage: 'send-endpoint-text-message',
sendTones: 'send-tones',
setVideoQuality: 'set-video-quality',
startRecording: 'start-recording',
stopRecording: 'stop-recording',
subject: 'subject',
submitFeedback: 'submit-feedback',
toggleAudio: 'toggle-audio',

View File

@@ -31,7 +31,7 @@ export const SHARED_VIDEO_CONTAINER_TYPE = 'sharedvideo';
* Example shared video link.
* @type {string}
*/
const defaultSharedVideoLink = 'https://youtu.be/TB7LlM4erx8';
const defaultSharedVideoLink = 'https://www.youtube.com/watch?v=xNXN7CZk8X0';
const updateInterval = 5000; // milliseconds
/**

View File

@@ -55,11 +55,6 @@ export type Props = {
*/
isDismissAllowed: boolean,
/**
* Maximum lines of the description.
*/
maxLines: ?number,
/**
* Callback invoked when the user clicks to dismiss the notification.
*/

View File

@@ -11,13 +11,6 @@ import AbstractNotification, {
import styles from './styles';
/**
* Default value for the maxLines prop.
*
* @type {number}
*/
const DEFAULT_MAX_LINES = 1;
/**
* Implements a React {@link Component} to display a notification.
*
@@ -31,7 +24,9 @@ class Notification extends AbstractNotification<Props> {
* @returns {ReactElement}
*/
render() {
const { isDismissAllowed } = this.props;
const {
isDismissAllowed
} = this.props;
return (
<View
@@ -66,7 +61,7 @@ class Notification extends AbstractNotification<Props> {
* @private
*/
_renderContent() {
const { maxLines = DEFAULT_MAX_LINES, t, title, titleArguments, titleKey } = this.props;
const { t, title, titleArguments, titleKey } = this.props;
const titleText = title || (titleKey && t(titleKey, titleArguments));
const description = this._getDescription();
@@ -74,7 +69,7 @@ class Notification extends AbstractNotification<Props> {
return description.map((line, index) => (
<Text
key = { index }
numberOfLines = { maxLines }
numberOfLines = { 1 }
style = { styles.contentText }>
{ line }
</Text>
@@ -83,7 +78,7 @@ class Notification extends AbstractNotification<Props> {
return (
<Text
numberOfLines = { maxLines }
numberOfLines = { 1 }
style = { styles.contentText } >
{ titleText }
</Text>

View File

@@ -40,7 +40,7 @@ export default {
notification: {
backgroundColor: '#768898',
flexDirection: 'row',
minHeight: 48,
height: 48,
marginTop: 0.5 * BoxModel.margin
},

View File

@@ -1,42 +0,0 @@
// @flow
import JitsiMeetJS from '../base/lib-jitsi-meet';
import { showNotification } from '../notifications';
export * from './actions.any';
/**
* Signals that a started recording notification should be shown on the
* screen for a given period.
*
* @param {string} streamType - The type of the stream ({@code file} or
* {@code stream}).
* @returns {showNotification}
*/
export function showRecordingLimitNotification(streamType: string) {
return (dispatch: Function, getState: Function) => {
const isLiveStreaming = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
let descriptionKey, titleKey;
if (isLiveStreaming) {
descriptionKey = 'liveStreaming.limitNotificationDescriptionNative';
titleKey = 'dialog.liveStreaming';
} else {
descriptionKey = 'recording.limitNotificationDescriptionNative';
titleKey = 'dialog.recording';
}
const { recordingLimit = {} } = getState()['features/base/config'];
const { limit, appName } = recordingLimit;
return dispatch(showNotification({
descriptionArguments: {
limit,
app: appName
},
descriptionKey,
titleKey,
maxLines: 2
}, 10000));
};
}

View File

@@ -1,27 +0,0 @@
// @flow
import React from 'react';
import JitsiMeetJS from '../base/lib-jitsi-meet';
import { showNotification } from '../notifications';
import { RecordingLimitNotificationDescription } from './components';
export * from './actions.any';
/**
* Signals that a started recording notification should be shown on the
* screen for a given period.
*
* @param {string} streamType - The type of the stream ({@code file} or
* {@code stream}).
* @returns {showNotification}
*/
export function showRecordingLimitNotification(streamType: string) {
const isLiveStreaming = streamType === JitsiMeetJS.constants.recording.mode.STREAM;
return showNotification({
description: <RecordingLimitNotificationDescription isLiveStreaming = { isLiveStreaming } />,
titleKey: isLiveStreaming ? 'dialog.liveStreaming' : 'dialog.recording'
}, 10000);
}

View File

@@ -1,81 +0,0 @@
// @flow
import React from 'react';
import { translate, translateToHTML } from '../../../base/i18n';
import { connect } from '../../../base/redux';
/**
* The type of the React {@code Component} props of {@link RecordingLimitNotificationDescription}.
*/
type Props = {
/**
* The limit of time in minutes for the recording.
*/
_limit: number,
/**
* The name of the app with unlimited recordings.
*/
_appName: string,
/**
* The URL to the app with unlimited recordings.
*/
_appURL: string,
/**
* True if the notification is related to the livestreaming and false if not.
*/
isLiveStreaming: Boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
/**
* A component that renders the description of the notification for the recording initiator.
*
* @param {Props} props - The props of the component.
* @returns {Component}
*/
function RecordingLimitNotificationDescription(props: Props) {
const { _limit, _appName, _appURL, isLiveStreaming, t } = props;
return (
<span>
{
translateToHTML(
t,
`${isLiveStreaming ? 'liveStreaming' : 'recording'}.limitNotificationDescriptionWeb`, {
limit: _limit,
app: _appName,
url: _appURL
})
}
</span>
);
}
/**
* Maps part of the Redix state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {Props}
*/
function _mapStateToProps(state): $Shape<Props> {
const { recordingLimit = {} } = state['features/base/config'];
const { limit: _limit, appName: _appName, appURL: _appURL } = recordingLimit;
return {
_limit,
_appName,
_appURL
};
}
export default translate(connect(_mapStateToProps)(RecordingLimitNotificationDescription));

View File

@@ -1,4 +1,3 @@
// @flow
export { default as RecordingLabel } from './RecordingLabel';
export { default as RecordingLimitNotificationDescription } from './RecordingLimitNotificationDescription';

View File

@@ -26,7 +26,6 @@ import {
hidePendingRecordingNotification,
showPendingRecordingNotification,
showRecordingError,
showRecordingLimitNotification,
showStartedRecordingNotification,
showStoppedRecordingNotification,
updateRecordingSessionData
@@ -45,8 +44,6 @@ import {
RECORDING_ON_SOUND_FILE
} from './sounds';
declare var interfaceConfig: Object;
/**
* StateListenerRegistry provides a reliable way to detect the leaving of a
* conference, where we need to clean up the recording sessions.
@@ -134,8 +131,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const {
iAmRecorder,
iAmSipGateway,
disableRecordAudioNotification,
recordingLimit
disableRecordAudioNotification
} = getState()['features/base/config'];
if (iAmRecorder && !iAmSipGateway) {
@@ -155,16 +151,9 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
if (updatedSessionData.status === ON
&& (!oldSessionData || oldSessionData.status !== ON)) {
if (initiator) {
const initiatorName = initiator && getParticipantDisplayName(getState, initiator.getId());
initiatorName && dispatch(showStartedRecordingNotification(mode, initiatorName));
} else if (typeof recordingLimit === 'object') {
// Show notification with additional information to the initiator.
dispatch(showRecordingLimitNotification(mode));
}
const initiatorName = initiator && getParticipantDisplayName(getState, initiator.getId());
initiatorName && dispatch(showStartedRecordingNotification(mode, initiatorName));
sendAnalytics(createRecordingEvent('start', mode));
if (disableRecordAudioNotification) {