[RN] Dynamically adjust LargeView's Avatar to available size (Coding style: comments, flow)
Flow caught an incorrect function call.
This commit is contained in:
parent
1419247801
commit
cacc4bd769
|
@ -42,7 +42,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* I18n key to put as body title.
|
* I18n key to put as body title.
|
||||||
*/
|
*/
|
||||||
bodyKey: String,
|
bodyKey: string,
|
||||||
|
|
||||||
textInputProps: Object
|
textInputProps: Object
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import PropTypes from 'prop-types';
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Image, View } from 'react-native';
|
import { Image, View } from 'react-native';
|
||||||
|
|
||||||
|
@ -23,36 +24,48 @@ import styles from './styles';
|
||||||
*/
|
*/
|
||||||
const _DEFAULT_SOURCE = require('../../../../../images/avatar.png');
|
const _DEFAULT_SOURCE = require('../../../../../images/avatar.png');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} props of {@link Avatar}.
|
||||||
|
*/
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size for the {@link Avatar}.
|
||||||
|
*/
|
||||||
|
size: number,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URI of the {@link Avatar}.
|
||||||
|
*/
|
||||||
|
uri: string
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} state of {@link Avatar}.
|
||||||
|
*/
|
||||||
|
type State = {
|
||||||
|
backgroundColor: string,
|
||||||
|
source: number | { uri: string }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements an avatar as a React Native/mobile {@link Component}.
|
* Implements an avatar as a React Native/mobile {@link Component}.
|
||||||
*/
|
*/
|
||||||
export default class Avatar extends Component {
|
export default class Avatar extends Component<Props, State> {
|
||||||
/**
|
/**
|
||||||
* Avatar component's property types.
|
* The indicator which determines whether this {@code Avatar} has been
|
||||||
*
|
* unmounted.
|
||||||
* @static
|
|
||||||
*/
|
*/
|
||||||
static propTypes = {
|
_unmounted: ?boolean;
|
||||||
/**
|
|
||||||
* The size for the {@link Avatar}.
|
|
||||||
*/
|
|
||||||
size: PropTypes.number,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URI of the {@link Avatar}.
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
uri: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new Avatar instance.
|
* Initializes a new Avatar instance.
|
||||||
*
|
*
|
||||||
* @param {Object} props - The read-only React Component props with which
|
* @param {Props} props - The read-only React Component props with which
|
||||||
* the new instance is to be initialized.
|
* the new instance is to be initialized.
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
// Fork (in Facebook/React speak) the prop uri because Image will
|
// Fork (in Facebook/React speak) the prop uri because Image will
|
||||||
|
@ -68,11 +81,11 @@ export default class Avatar extends Component {
|
||||||
* Additionally, other props may be forked as well.
|
* Additionally, other props may be forked as well.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* @param {Object} nextProps - The read-only React Component props that this
|
* @param {Props} nextProps - The read-only React Component props that this
|
||||||
* instance will receive.
|
* instance will receive.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
// uri
|
// uri
|
||||||
const prevURI = this.props && this.props.uri;
|
const prevURI = this.props && this.props.uri;
|
||||||
const nextURI = nextProps && nextProps.uri;
|
const nextURI = nextProps && nextProps.uri;
|
||||||
|
@ -226,14 +239,17 @@ export default class Avatar extends Component {
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
// Compute the base style
|
// Compute the base style
|
||||||
|
const borderRadius = size / 2;
|
||||||
const style = {
|
const style = {
|
||||||
...styles.avatar,
|
...styles.avatar,
|
||||||
|
|
||||||
// XXX Workaround for Android: for radii < 80 the border radius
|
// XXX Workaround for Android: for radii < 80 the border radius
|
||||||
// doesn't work properly, but applying a radius twice as big
|
// doesn't work properly, but applying a radius twice as big seems
|
||||||
// seems to do the trick.
|
// to do the trick.
|
||||||
borderRadius: size / 2 < 80
|
borderRadius:
|
||||||
? Platform.OS === 'android' ? size * 2 : size / 2 : size / 2,
|
Platform.OS === 'android' && borderRadius < 80
|
||||||
|
? size * 2
|
||||||
|
: borderRadius,
|
||||||
height: size,
|
height: size,
|
||||||
width: size
|
width: size
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
import PropTypes from 'prop-types';
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} props of {@link Avatar}.
|
||||||
|
*/
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URI of the {@link Avatar}.
|
||||||
|
*/
|
||||||
|
uri: string
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements an avatar as a React/Web {@link Component}.
|
* Implements an avatar as a React/Web {@link Component}.
|
||||||
*/
|
*/
|
||||||
export default class Avatar extends Component {
|
export default class Avatar extends Component<Props> {
|
||||||
/**
|
|
||||||
* Avatar component's property types.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
static propTypes = {
|
|
||||||
/**
|
|
||||||
* The URI of the {@link Avatar}.
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
uri: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements React's {@link Component#render()}.
|
* Implements React's {@link Component#render()}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import PropTypes from 'prop-types';
|
// @flow
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { prefetch } from '../../../mobile/image-cache';
|
|
||||||
|
|
||||||
import { translate } from '../../i18n';
|
import { translate } from '../../i18n';
|
||||||
import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet';
|
import { JitsiParticipantConnectionStatus } from '../../lib-jitsi-meet';
|
||||||
import {
|
import {
|
||||||
|
@ -12,116 +11,117 @@ import {
|
||||||
shouldRenderVideoTrack,
|
shouldRenderVideoTrack,
|
||||||
VideoTrack
|
VideoTrack
|
||||||
} from '../../media';
|
} from '../../media';
|
||||||
|
import { prefetch } from '../../../mobile/image-cache';
|
||||||
import { Container, TintedView } from '../../react';
|
import { Container, TintedView } from '../../react';
|
||||||
import { getTrackByMediaTypeAndParticipant } from '../../tracks';
|
import { getTrackByMediaTypeAndParticipant } from '../../tracks';
|
||||||
|
|
||||||
import {
|
|
||||||
getAvatarURL, getParticipantById, getParticipantDisplayName
|
|
||||||
} from '../functions';
|
|
||||||
|
|
||||||
import Avatar from './Avatar';
|
import Avatar from './Avatar';
|
||||||
|
import {
|
||||||
|
getAvatarURL,
|
||||||
|
getParticipantById,
|
||||||
|
getParticipantDisplayName
|
||||||
|
} from '../functions';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} props of {@link ParticipantView}.
|
||||||
|
*/
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The indicator which determines whether conferencing is in audio-only
|
||||||
|
* mode.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_audioOnly: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source (e.g. URI, URL) of the avatar image of the participant with
|
||||||
|
* {@link #participantId}.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_avatar: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection status of the participant. Her video will only be rendered
|
||||||
|
* if the connection status is 'active'; otherwise, the avatar will be
|
||||||
|
* rendered. If undefined, 'active' is presumed.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_connectionStatus: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the participant which this component represents.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_participantName: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The video Track of the participant with {@link #participantId}.
|
||||||
|
*/
|
||||||
|
_videoTrack: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The avatar size.
|
||||||
|
*/
|
||||||
|
avatarSize: number,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the participant (to be) depicted by {@link ParticipantView}.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
participantId: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the avatar of the depicted participant is to be shown should the
|
||||||
|
* avatar be available and the video of the participant is not to be shown;
|
||||||
|
* otherwise, false. If undefined, defaults to true.
|
||||||
|
*/
|
||||||
|
showAvatar: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the video of the depicted participant is to be shown should the
|
||||||
|
* video be available. If undefined, defaults to true.
|
||||||
|
*/
|
||||||
|
showVideo: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The style, if any, to apply to {@link ParticipantView} in addition to its
|
||||||
|
* default style.
|
||||||
|
*/
|
||||||
|
style: Object,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to translate human-readable text.
|
||||||
|
*/
|
||||||
|
t: Function,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the connectivity info label should be shown, if appropriate.
|
||||||
|
* It will be shown in case the connection is interrupted.
|
||||||
|
*/
|
||||||
|
useConnectivityInfoLabel: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The z-order of the {@link Video} of {@link ParticipantView} in the
|
||||||
|
* stacking space of all {@code Video}s. For more details, refer to the
|
||||||
|
* {@code zOrder} property of the {@code Video} class for React Native.
|
||||||
|
*/
|
||||||
|
zOrder: number
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a React Component which depicts a specific participant's avatar
|
* Implements a React Component which depicts a specific participant's avatar
|
||||||
* and video.
|
* and video.
|
||||||
*
|
*
|
||||||
* @extends Component
|
* @extends Component
|
||||||
*/
|
*/
|
||||||
class ParticipantView extends Component {
|
class ParticipantView extends Component<Props> {
|
||||||
/**
|
|
||||||
* ParticipantView component's property types.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
static propTypes = {
|
|
||||||
/**
|
|
||||||
* The indicator which determines whether conferencing is in audio-only
|
|
||||||
* mode.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_audioOnly: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The source (e.g. URI, URL) of the avatar image of the participant
|
|
||||||
* with {@link #participantId}.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_avatar: PropTypes.string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The connection status of the participant. Her video will only be
|
|
||||||
* rendered if the connection status is 'active'; otherwise, the avatar
|
|
||||||
* will be rendered. If undefined, 'active' is presumed.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_connectionStatus: PropTypes.string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the participant which this component represents.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_participantName: PropTypes.string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The video Track of the participant with {@link #participantId}.
|
|
||||||
*/
|
|
||||||
_videoTrack: PropTypes.object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The avatar size.
|
|
||||||
*/
|
|
||||||
avatarSize: PropTypes.number,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ID of the participant (to be) depicted by ParticipantView.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
participantId: PropTypes.string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the avatar of the depicted participant is to be shown should
|
|
||||||
* the avatar be available and the video of the participant is not to be
|
|
||||||
* shown; otherwise, false. If undefined, defaults to true.
|
|
||||||
*/
|
|
||||||
showAvatar: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the video of the depicted participant is to be shown should
|
|
||||||
* the video be available. If undefined, defaults to true.
|
|
||||||
*/
|
|
||||||
showVideo: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The style, if any, to apply to ParticipantView in addition to its
|
|
||||||
* default style.
|
|
||||||
*/
|
|
||||||
style: PropTypes.object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The function to translate human-readable text.
|
|
||||||
*/
|
|
||||||
t: PropTypes.func,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the connectivity info label should be shown, if
|
|
||||||
* appropriate. It will be shown in case the connection is interrupted.
|
|
||||||
*/
|
|
||||||
useConnectivityInfoLabel: PropTypes.bool,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The z-order of the Video of ParticipantView in the stacking space of
|
|
||||||
* all Videos. For more details, refer to the zOrder property of the
|
|
||||||
* Video class for React Native.
|
|
||||||
*/
|
|
||||||
zOrder: PropTypes.number
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the connection status label, if appropriate.
|
* Renders the connection status label, if appropriate.
|
||||||
*
|
*
|
||||||
|
@ -150,8 +150,8 @@ class ParticipantView extends Component {
|
||||||
t
|
t
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// XXX Consider splitting this component into 2: one for the large
|
// XXX Consider splitting this component into 2: one for the large view
|
||||||
// view and one for the thumbnail. Some of these don't apply to both.
|
// and one for the thumbnail. Some of these don't apply to both.
|
||||||
const containerStyle = {
|
const containerStyle = {
|
||||||
...styles.connectionInfoContainer,
|
...styles.connectionInfoContainer,
|
||||||
width: avatarSize * 1.5
|
width: avatarSize * 1.5
|
||||||
|
@ -261,16 +261,18 @@ function _toBoolean(value, undefinedValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps (parts of) the Redux state to the associated ParticipantView's props.
|
* Maps (parts of) the redux state to the associated {@link ParticipantView}'s
|
||||||
|
* props.
|
||||||
*
|
*
|
||||||
* @param {Object} state - The Redux state.
|
* @param {Object} state - The redux state.
|
||||||
* @param {Object} ownProps - The React Component props passed to the associated
|
* @param {Object} ownProps - The React {@code Component} props passed to the
|
||||||
* (instance of) ParticipantView.
|
* associated (instance of) {@code ParticipantView}.
|
||||||
* @private
|
* @private
|
||||||
* @returns {{
|
* @returns {{
|
||||||
* _audioOnly: boolean,
|
* _audioOnly: boolean,
|
||||||
* _avatar: string,
|
* _avatar: string,
|
||||||
* _connectionStatus: string,
|
* _connectionStatus: string,
|
||||||
|
* _participantName: string,
|
||||||
* _videoTrack: Track
|
* _videoTrack: Track
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
|
@ -287,7 +289,7 @@ function _mapStateToProps(state, ownProps) {
|
||||||
if (participant) {
|
if (participant) {
|
||||||
avatar = getAvatarURL(participant);
|
avatar = getAvatarURL(participant);
|
||||||
connectionStatus = participant.connectionStatus;
|
connectionStatus = participant.connectionStatus;
|
||||||
participantName = getParticipantDisplayName(state);
|
participantName = getParticipantDisplayName(state, participant.id);
|
||||||
|
|
||||||
// Avatar (on React Native) now has the ability to generate an
|
// Avatar (on React Native) now has the ability to generate an
|
||||||
// automatically-colored default image when no URI/URL is specified or
|
// automatically-colored default image when no URI/URL is specified or
|
||||||
|
|
|
@ -160,7 +160,8 @@ export function getParticipantCount(stateful: Object | Function) {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getParticipantDisplayName(
|
export function getParticipantDisplayName(
|
||||||
stateful: Object | Function, id: string) {
|
stateful: Object | Function,
|
||||||
|
id: string) {
|
||||||
const participant = getParticipantById(stateful, id);
|
const participant = getParticipantById(stateful, id);
|
||||||
|
|
||||||
if (participant) {
|
if (participant) {
|
||||||
|
|
|
@ -18,11 +18,11 @@ import {
|
||||||
styles,
|
styles,
|
||||||
VideoMutedIndicator
|
VideoMutedIndicator
|
||||||
} from './_';
|
} from './_';
|
||||||
|
|
||||||
import { AVATAR_SIZE } from './styles';
|
import { AVATAR_SIZE } from './styles';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React component for video thumbnail.
|
* React component for video thumbnail.
|
||||||
|
*
|
||||||
* @extends Component
|
* @extends Component
|
||||||
*/
|
*/
|
||||||
class Thumbnail extends Component {
|
class Thumbnail extends Component {
|
||||||
|
|
|
@ -8,6 +8,9 @@ import { DimensionsDetector } from '../../base/responsive-ui';
|
||||||
|
|
||||||
import styles, { AVATAR_SIZE } from './styles';
|
import styles, { AVATAR_SIZE } from './styles';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} props of {@link LargeVideo}.
|
||||||
|
*/
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +21,9 @@ type Props = {
|
||||||
_participantId: string
|
_participantId: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the React {@link Component} state of {@link LargeVideo}.
|
||||||
|
*/
|
||||||
type State = {
|
type State = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +63,7 @@ class LargeVideo extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
|
this._onDimensionsChanged = this._onDimensionsChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,19 +82,18 @@ class LargeVideo extends Component<Props, State> {
|
||||||
_onDimensionsChanged(width: number, height: number) {
|
_onDimensionsChanged(width: number, height: number) {
|
||||||
// Get the size, rounded to the nearest even number.
|
// Get the size, rounded to the nearest even number.
|
||||||
const size = 2 * Math.round(Math.min(height, width) / 2);
|
const size = 2 * Math.round(Math.min(height, width) / 2);
|
||||||
|
let nextState;
|
||||||
let newState;
|
|
||||||
|
|
||||||
if (size < AVATAR_SIZE * 1.5) {
|
if (size < AVATAR_SIZE * 1.5) {
|
||||||
newState = {
|
nextState = {
|
||||||
avatarSize: size - 15, // Leave some margin.
|
avatarSize: size - 15, // Leave some margin.
|
||||||
useConnectivityInfoLabel: false
|
useConnectivityInfoLabel: false
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
newState = DEFAULT_STATE;
|
nextState = DEFAULT_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(newState);
|
this.setState(nextState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue