fix(rn,participants) fix not rendering connection info messages
Also move shouldRenderParticipantVideo to the only place it's used.
This commit is contained in:
parent
e8df8f75a8
commit
eda3e620d3
|
@ -1,19 +1,23 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import {
|
||||||
|
isParticipantConnectionStatusActive,
|
||||||
|
isParticipantConnectionStatusInactive,
|
||||||
|
isTrackStreamingStatusActive,
|
||||||
|
isTrackStreamingStatusInactive
|
||||||
|
} from '../../../connection-indicator/functions';
|
||||||
import { SharedVideo } from '../../../shared-video/components/native';
|
import { SharedVideo } from '../../../shared-video/components/native';
|
||||||
import { Avatar } from '../../avatar';
|
import Avatar from '../../avatar/components/Avatar';
|
||||||
import { translate } from '../../i18n';
|
import { getSourceNameSignalingFeatureFlag } from '../../config/functions.any';
|
||||||
import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet';
|
import { translate } from '../../i18n/functions';
|
||||||
import { VideoTrack } from '../../media';
|
import VideoTrack from '../../media/components/native/VideoTrack';
|
||||||
import { Container, TintedView } from '../../react';
|
import { shouldRenderVideoTrack } from '../../media/functions';
|
||||||
import { connect } from '../../redux';
|
import { Container } from '../../react';
|
||||||
|
import { connect, toState } from '../../redux/functions';
|
||||||
import { TestHint } from '../../testing/components';
|
import { TestHint } from '../../testing/components';
|
||||||
import { getVideoTrackByParticipant } from '../../tracks';
|
import { getVideoTrackByParticipant } from '../../tracks/functions';
|
||||||
import { getParticipantById, isSharedVideoParticipant, shouldRenderParticipantVideo } from '../functions';
|
import { getParticipantById, getParticipantDisplayName, isSharedVideoParticipant } from '../functions';
|
||||||
import { FakeParticipant } from '../types';
|
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
@ -23,20 +27,11 @@ import styles from './styles';
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The connection status of the participant. Her video will only be rendered
|
* Whether the connection is inactive or not.
|
||||||
* if the connection status is 'active'; otherwise, the avatar will be
|
|
||||||
* rendered. If undefined, 'active' is presumed.
|
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_connectionStatus: string,
|
_isConnectionInactive: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of participant if the participant which this component represents is fake.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_fakeParticipant?: FakeParticipant,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the participant is a shared video participant.
|
* Whether the participant is a shared video participant.
|
||||||
|
@ -129,24 +124,12 @@ type Props = {
|
||||||
class ParticipantView extends Component<Props> {
|
class ParticipantView extends Component<Props> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the connection status label, if appropriate.
|
* Renders the inactive connection status label.
|
||||||
*
|
*
|
||||||
* @param {string} connectionStatus - The status of the participant's
|
|
||||||
* connection.
|
|
||||||
* @private
|
* @private
|
||||||
* @returns {ReactElement|null}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
_renderConnectionInfo(connectionStatus) {
|
_renderInactiveConnectionInfo() {
|
||||||
let messageKey;
|
|
||||||
|
|
||||||
switch (connectionStatus) {
|
|
||||||
case JitsiParticipantConnectionStatus.INACTIVE:
|
|
||||||
messageKey = 'connection.LOW_BANDWIDTH';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
avatarSize,
|
avatarSize,
|
||||||
_participantName: displayName,
|
_participantName: displayName,
|
||||||
|
@ -165,7 +148,7 @@ class ParticipantView extends Component<Props> {
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { containerStyle }>
|
style = { containerStyle }>
|
||||||
<Text style = { styles.connectionInfoText }>
|
<Text style = { styles.connectionInfoText }>
|
||||||
{ t(messageKey, { displayName }) }
|
{ t('connection.LOW_BANDWIDTH', { displayName }) }
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -179,8 +162,7 @@ class ParticipantView extends Component<Props> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
_connectionStatus: connectionStatus,
|
_isConnectionInactive,
|
||||||
_fakeParticipant,
|
|
||||||
_isSharedVideoParticipant,
|
_isSharedVideoParticipant,
|
||||||
_renderVideo: renderVideo,
|
_renderVideo: renderVideo,
|
||||||
_videoTrack: videoTrack,
|
_videoTrack: videoTrack,
|
||||||
|
@ -188,10 +170,6 @@ class ParticipantView extends Component<Props> {
|
||||||
onPress
|
onPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// If the connection has problems, we will "tint" the video / avatar.
|
|
||||||
const connectionProblem
|
|
||||||
= connectionStatus !== JitsiParticipantConnectionStatus.ACTIVE;
|
|
||||||
|
|
||||||
const testHintId
|
const testHintId
|
||||||
= this.props.testHintId
|
= this.props.testHintId
|
||||||
? this.props.testHintId
|
? this.props.testHintId
|
||||||
|
@ -230,13 +208,8 @@ class ParticipantView extends Component<Props> {
|
||||||
size = { this.props.avatarSize } />
|
size = { this.props.avatarSize } />
|
||||||
</View> }
|
</View> }
|
||||||
|
|
||||||
{ connectionProblem
|
{ _isConnectionInactive && this.props.useConnectivityInfoLabel
|
||||||
|
&& this._renderInactiveConnectionInfo() }
|
||||||
// If the connection has problems, tint the video / avatar.
|
|
||||||
&& <TintedView /> }
|
|
||||||
|
|
||||||
{ this.props.useConnectivityInfoLabel
|
|
||||||
&& this._renderConnectionInfo(connectionStatus) }
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -256,19 +229,69 @@ function _mapStateToProps(state, ownProps) {
|
||||||
const { disableVideo, participantId } = ownProps;
|
const { disableVideo, participantId } = ownProps;
|
||||||
const participant = getParticipantById(state, participantId);
|
const participant = getParticipantById(state, participantId);
|
||||||
const videoTrack = getVideoTrackByParticipant(state, participant);
|
const videoTrack = getVideoTrackByParticipant(state, participant);
|
||||||
let connectionStatus;
|
|
||||||
let participantName;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_connectionStatus:
|
_isConnectionInactive: getSourceNameSignalingFeatureFlag(state)
|
||||||
connectionStatus
|
? isTrackStreamingStatusInactive(videoTrack) : isParticipantConnectionStatusInactive(participant),
|
||||||
|| JitsiParticipantConnectionStatus.ACTIVE,
|
|
||||||
_isSharedVideoParticipant: isSharedVideoParticipant(participant),
|
_isSharedVideoParticipant: isSharedVideoParticipant(participant),
|
||||||
_fakeParticipant: participant?.fakeParticipant,
|
_participantName: getParticipantDisplayName(state, participantId),
|
||||||
_participantName: participantName,
|
|
||||||
_renderVideo: shouldRenderParticipantVideo(state, participantId) && !disableVideo,
|
_renderVideo: shouldRenderParticipantVideo(state, participantId) && !disableVideo,
|
||||||
_videoTrack: videoTrack
|
_videoTrack: videoTrack
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the video of the participant should be rendered.
|
||||||
|
*
|
||||||
|
* @param {Object|Function} stateful - Object or function that can be resolved
|
||||||
|
* to the Redux state.
|
||||||
|
* @param {string} id - The ID of the participant.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function shouldRenderParticipantVideo(stateful, id) {
|
||||||
|
const state = toState(stateful);
|
||||||
|
const participant = getParticipantById(state, id);
|
||||||
|
|
||||||
|
if (!participant) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First check if we have an unmuted video track. */
|
||||||
|
const videoTrack = getVideoTrackByParticipant(state, participant);
|
||||||
|
|
||||||
|
if (!videoTrack) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then check if the participant connection or track streaming status is active. */
|
||||||
|
if (getSourceNameSignalingFeatureFlag(state)) {
|
||||||
|
// Note that this will work only if a listener is registered for the track's TrackStreamingStatus.
|
||||||
|
// The associated TrackStreamingStatusImpl instance is not created or disposed when there are zero listeners.
|
||||||
|
if (!videoTrack.local && !isTrackStreamingStatusActive(videoTrack)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!isParticipantConnectionStatusActive(participant)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then check if audio-only mode is not active. */
|
||||||
|
const audioOnly = state['features/base/audio-only'].enabled;
|
||||||
|
|
||||||
|
if (!audioOnly) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last, check if the participant is sharing their screen and they are on stage. */
|
||||||
|
const remoteScreenShares = state['features/video-layout'].remoteScreenShares || [];
|
||||||
|
const largeVideoParticipantId = state['features/large-video'].participantId;
|
||||||
|
const participantIsInLargeVideoWithScreen
|
||||||
|
= participant.id === largeVideoParticipantId && remoteScreenShares.includes(participant.id);
|
||||||
|
|
||||||
|
return participantIsInLargeVideoWithScreen;
|
||||||
|
}
|
||||||
|
|
||||||
export default translate(connect(_mapStateToProps)(ParticipantView));
|
export default translate(connect(_mapStateToProps)(ParticipantView));
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export { default as ParticipantView } from './ParticipantView';
|
|
|
@ -8,12 +8,10 @@ import { isStageFilmstripAvailable } from '../../filmstrip/functions';
|
||||||
import { IStateful } from '../app/types';
|
import { IStateful } from '../app/types';
|
||||||
import { GRAVATAR_BASE_URL } from '../avatar/constants';
|
import { GRAVATAR_BASE_URL } from '../avatar/constants';
|
||||||
import { isCORSAvatarURL } from '../avatar/functions';
|
import { isCORSAvatarURL } from '../avatar/functions';
|
||||||
import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config/functions.any';
|
import { getMultipleVideoSupportFeatureFlag } from '../config/functions.any';
|
||||||
import i18next from '../i18n/i18next';
|
import i18next from '../i18n/i18next';
|
||||||
import { JitsiParticipantConnectionStatus, JitsiTrackStreamingStatus } from '../lib-jitsi-meet';
|
|
||||||
import { shouldRenderVideoTrack } from '../media/functions';
|
|
||||||
import { toState } from '../redux/functions';
|
import { toState } from '../redux/functions';
|
||||||
import { getScreenShareTrack, getVideoTrackByParticipant } from '../tracks/functions';
|
import { getScreenShareTrack } from '../tracks/functions';
|
||||||
import { createDeferred } from '../util/helpers';
|
import { createDeferred } from '../util/helpers';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -602,63 +600,6 @@ export function isLocalParticipantModerator(stateful: IStateful) {
|
||||||
return isParticipantModerator(local);
|
return isParticipantModerator(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the video of the participant should be rendered.
|
|
||||||
* NOTE: This is currently only used on mobile.
|
|
||||||
*
|
|
||||||
* @param {Object|Function} stateful - Object or function that can be resolved
|
|
||||||
* to the Redux state.
|
|
||||||
* @param {string} id - The ID of the participant.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function shouldRenderParticipantVideo(stateful: IStateful, id: string) {
|
|
||||||
const state = toState(stateful);
|
|
||||||
const participant = getParticipantById(state, id);
|
|
||||||
|
|
||||||
if (!participant) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First check if we have an unmuted video track. */
|
|
||||||
const videoTrack = getVideoTrackByParticipant(state, participant);
|
|
||||||
|
|
||||||
if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then check if the participant connection or track streaming status is active. */
|
|
||||||
if (getSourceNameSignalingFeatureFlag(state)) {
|
|
||||||
// Note that this will work only if a listener is registered for the track's TrackStreamingStatus.
|
|
||||||
// The associated TrackStreamingStatusImpl instance is not created or disposed when there are zero listeners.
|
|
||||||
if (videoTrack
|
|
||||||
&& !videoTrack.local
|
|
||||||
&& videoTrack.jitsiTrack?.getTrackStreamingStatus() !== JitsiTrackStreamingStatus.ACTIVE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const connectionStatus = participant.connectionStatus || JitsiParticipantConnectionStatus.ACTIVE;
|
|
||||||
|
|
||||||
if (connectionStatus !== JitsiParticipantConnectionStatus.ACTIVE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Then check if audio-only mode is not active. */
|
|
||||||
const audioOnly = state['features/base/audio-only'].enabled;
|
|
||||||
|
|
||||||
if (!audioOnly) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last, check if the participant is sharing their screen and they are on stage. */
|
|
||||||
const remoteScreenShares = state['features/video-layout'].remoteScreenShares || [];
|
|
||||||
const largeVideoParticipantId = state['features/large-video'].participantId;
|
|
||||||
const participantIsInLargeVideoWithScreen
|
|
||||||
= participant.id === largeVideoParticipantId && remoteScreenShares.includes(participant.id);
|
|
||||||
|
|
||||||
return participantIsInLargeVideoWithScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the first loadable avatar URL for a participant.
|
* Resolves the first loadable avatar URL for a participant.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
export * from './actionTypes';
|
export * from './actionTypes';
|
||||||
export * from './components';
|
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
export * from './functions';
|
export * from './functions';
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
|
||||||
import { MEDIA_TYPE, VIDEO_TYPE } from '../../../base/media';
|
import { MEDIA_TYPE, VIDEO_TYPE } from '../../../base/media';
|
||||||
import {
|
import {
|
||||||
PARTICIPANT_ROLE,
|
PARTICIPANT_ROLE,
|
||||||
ParticipantView,
|
|
||||||
getLocalParticipant,
|
getLocalParticipant,
|
||||||
getParticipantByIdOrUndefined,
|
getParticipantByIdOrUndefined,
|
||||||
getParticipantCount,
|
getParticipantCount,
|
||||||
|
@ -18,6 +17,7 @@ import {
|
||||||
isScreenShareParticipant,
|
isScreenShareParticipant,
|
||||||
pinParticipant
|
pinParticipant
|
||||||
} from '../../../base/participants';
|
} from '../../../base/participants';
|
||||||
|
import ParticipantView from '../../../base/participants/components/ParticipantView.native';
|
||||||
import { FakeParticipant } from '../../../base/participants/types';
|
import { FakeParticipant } from '../../../base/participants/types';
|
||||||
import { Container } from '../../../base/react';
|
import { Container } from '../../../base/react';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
|
|
|
@ -5,7 +5,8 @@ import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { getSourceNameSignalingFeatureFlag } from '../../base/config/functions.any';
|
import { getSourceNameSignalingFeatureFlag } from '../../base/config/functions.any';
|
||||||
import { JitsiTrackEvents } from '../../base/lib-jitsi-meet';
|
import { JitsiTrackEvents } from '../../base/lib-jitsi-meet';
|
||||||
import { ParticipantView, getParticipantById } from '../../base/participants';
|
import ParticipantView from '../../base/participants/components/ParticipantView.native';
|
||||||
|
import { getParticipantById } from '../../base/participants/functions';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
import {
|
import {
|
||||||
getVideoTrackByParticipant,
|
getVideoTrackByParticipant,
|
||||||
|
|
Loading…
Reference in New Issue