[RN] Don't press on Conference in preparation for 'pinch to zoom'

TouchableWithoutFeedback and TouchableHighlight interfere with the
implementation of 'pinch to zoom' to come. We prepare for it by driving
the onClick/onPress handler(s) out of Conference, through LargeVideo and
ParticipantView into Video itself where the bulk of 'pinch to zoom' will
be implemented.
This commit is contained in:
Zoltan Bettenbuk 2018-04-06 16:11:01 -05:00 committed by Lyubo Marinov
parent cb70c084b3
commit decbcefbd4
7 changed files with 110 additions and 32 deletions

View File

@ -21,6 +21,12 @@ export default class AbstractVideoTrack extends Component {
static propTypes = {
dispatch: PropTypes.func,
/**
* Callback to invoke when the {@link Video} of
* {@code AbstractVideoTrack} is clicked/pressed.
*/
onPress: PropTypes.func,
videoTrack: PropTypes.object,
waitForVideoStarted: PropTypes.bool,
@ -106,6 +112,7 @@ export default class AbstractVideoTrack extends Component {
<Video
mirror = { videoTrack && videoTrack.mirror }
onPlaying = { this._onVideoPlaying }
onPress = { this.props.onPress }
stream = { stream }
zOrder = { this.props.zOrder } />
);
@ -120,8 +127,7 @@ export default class AbstractVideoTrack extends Component {
_onVideoPlaying() {
const videoTrack = this.props.videoTrack;
if (videoTrack
&& !videoTrack.videoStarted) {
if (videoTrack && !videoTrack.videoStarted) {
this.props.dispatch(trackVideoStarted(videoTrack.jitsiTrack));
}
}

View File

@ -1,9 +1,11 @@
/* @flow */
// @flow
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { RTCView } from 'react-native-webrtc';
import { Pressable } from '../../../react';
import styles from './styles';
/**
@ -19,7 +21,14 @@ export default class Video extends Component<*> {
*/
static propTypes = {
mirror: PropTypes.bool,
onPlaying: PropTypes.func,
/**
* Callback to invoke when the {@code Video} is clicked/pressed.
*/
onPress: PropTypes.func,
stream: PropTypes.object,
/**
@ -82,14 +91,15 @@ export default class Video extends Component<*> {
const style = styles.video;
const objectFit = (style && style.objectFit) || 'cover';
// eslint-disable-next-line no-extra-parens
return (
<RTCView
mirror = { this.props.mirror }
objectFit = { objectFit }
streamURL = { streamURL }
style = { style }
zOrder = { this.props.zOrder } />
<Pressable onPress = { this.props.onPress }>
<RTCView
mirror = { this.props.mirror }
objectFit = { objectFit }
streamURL = { streamURL }
style = { style }
zOrder = { this.props.zOrder } />
</Pressable>
);
}

View File

@ -70,6 +70,11 @@ type Props = {
*/
avatarSize: number,
/**
* Callback to invoke when the {@code ParticipantView} is clicked/pressed.
*/
onPress: Function,
/**
* The ID of the participant (to be) depicted by {@link ParticipantView}.
*
@ -176,6 +181,7 @@ class ParticipantView extends Component<Props> {
*/
render() {
const {
onPress,
_avatar: avatar,
_connectionStatus: connectionStatus,
_videoTrack: videoTrack
@ -190,16 +196,26 @@ class ParticipantView extends Component<Props> {
// doesn't retain the last frame forever, so we would end up with a
// black screen.
const waitForVideoStarted = false;
const renderVideo
let renderVideo
= !this.props._audioOnly
&& (connectionStatus
=== JitsiParticipantConnectionStatus.ACTIVE)
&& shouldRenderVideoTrack(videoTrack, waitForVideoStarted);
// Is the avatar to be rendered?
const renderAvatar = Boolean(!renderVideo && avatar);
let renderAvatar = Boolean(!renderVideo && avatar);
// If the connection has problems we will "tint" the video / avatar.
// The consumer of this ParticipantView is allowed to forbid showing the
// video if the private logic of this ParticipantView determines that
// the video could be rendered.
renderVideo = renderVideo && _toBoolean(this.props.showVideo, true);
// The consumer of this ParticipantView is allowed to forbid showing the
// avatar if the private logic of this ParticipantView determines that
// the avatar could be rendered.
renderAvatar = renderAvatar && _toBoolean(this.props.showAvatar, true);
// If the connection has problems, we will "tint" the video / avatar.
const useTint
= connectionStatus === JitsiParticipantConnectionStatus.INACTIVE
|| connectionStatus
@ -207,30 +223,21 @@ class ParticipantView extends Component<Props> {
return (
<Container
onClick = { renderVideo ? undefined : onPress }
style = {{
...styles.participantView,
...this.props.style
}}>
}}
touchFeedback = { false }>
{ renderVideo
// The consumer of this ParticipantView is allowed to forbid
// showing the video if the private logic of this
// ParticipantView determines that the video could be
// rendered.
&& _toBoolean(this.props.showVideo, true)
&& <VideoTrack
onPress = { renderVideo ? onPress : undefined }
videoTrack = { videoTrack }
waitForVideoStarted = { waitForVideoStarted }
zOrder = { this.props.zOrder } /> }
{ renderAvatar
// The consumer of this ParticipantView is allowed to forbid
// showing the avatar if the private logic of this
// ParticipantView determines that the avatar could be
// rendered.
&& _toBoolean(this.props.showAvatar, true)
&& <Avatar
size = { this.props.avatarSize }
uri = { avatar } /> }

View File

@ -0,0 +1,46 @@
// @flow
import React, { Component } from 'react';
import { TouchableWithoutFeedback } from 'react-native';
/**
* The type of the React {@link Component} props of {@link Pressable}.
*/
type Props = {
children: React$Node,
/**
* Called when the touch is released, but not if cancelled (e.g. by a scroll
* that steals the responder lock).
*/
onPress: Function
};
/**
* Adds support for {@code onPress} to a child React {@link Component} (which
* should probably not support the prop in question; otherwise, there's little
* point of using {@code Pressable} then in the first place).
*/
export default class Pressable extends Component<Props> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {React$Node}
*/
render() {
// onPress
const { children, onPress } = this.props;
if (onPress) {
return (
<TouchableWithoutFeedback onPress = { onPress }>
{ children }
</TouchableWithoutFeedback>
);
}
// A Pressable without an onPress is a "no-op".
return children;
}
}

View File

@ -3,6 +3,7 @@ export { default as Header } from './Header';
export { default as NavigateSectionList } from './NavigateSectionList';
export { default as Link } from './Link';
export { default as LoadingIndicator } from './LoadingIndicator';
export { default as Pressable } from './Pressable';
export { default as SideBar } from './SideBar';
export { default as Text } from './Text';
export { default as TintedView } from './TintedView';

View File

@ -190,9 +190,7 @@ class Conference extends Component<Props> {
<Container
accessibilityLabel = 'Conference'
accessible = { false }
onClick = { this._onClick }
style = { styles.conference }
touchFeedback = { false }>
style = { styles.conference }>
<StatusBar
hidden = { true }
translucent = { true } />
@ -200,7 +198,7 @@ class Conference extends Component<Props> {
{/*
* The LargeVideo is the lowermost stacking layer.
*/}
<LargeVideo />
<LargeVideo onPress = { this._onClick } />
{/*
* If there is a ringing call, show the callee's info.

View File

@ -13,6 +13,11 @@ import styles, { AVATAR_SIZE } from './styles';
*/
type Props = {
/**
* Callback to invoke when the {@code LargeVideo} is clicked/pressed.
*/
onPress: Function,
/**
* The ID of the participant (to be) depicted by LargeVideo.
*
@ -107,13 +112,18 @@ class LargeVideo extends Component<Props, State> {
avatarSize,
useConnectivityInfoLabel
} = this.state;
const {
onPress,
_participantId
} = this.props;
return (
<DimensionsDetector
onDimensionsChanged = { this._onDimensionsChanged } >
onDimensionsChanged = { this._onDimensionsChanged }>
<ParticipantView
avatarSize = { avatarSize }
participantId = { this.props._participantId }
onPress = { onPress }
participantId = { _participantId }
style = { styles.largeVideo }
useConnectivityInfoLabel = { useConnectivityInfoLabel }
zOrder = { 0 } />