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

View File

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

View File

@ -70,6 +70,11 @@ type Props = {
*/ */
avatarSize: number, 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}. * The ID of the participant (to be) depicted by {@link ParticipantView}.
* *
@ -176,6 +181,7 @@ class ParticipantView extends Component<Props> {
*/ */
render() { render() {
const { const {
onPress,
_avatar: avatar, _avatar: avatar,
_connectionStatus: connectionStatus, _connectionStatus: connectionStatus,
_videoTrack: videoTrack _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 // doesn't retain the last frame forever, so we would end up with a
// black screen. // black screen.
const waitForVideoStarted = false; const waitForVideoStarted = false;
const renderVideo let renderVideo
= !this.props._audioOnly = !this.props._audioOnly
&& (connectionStatus && (connectionStatus
=== JitsiParticipantConnectionStatus.ACTIVE) === JitsiParticipantConnectionStatus.ACTIVE)
&& shouldRenderVideoTrack(videoTrack, waitForVideoStarted); && shouldRenderVideoTrack(videoTrack, waitForVideoStarted);
// Is the avatar to be rendered? // 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 const useTint
= connectionStatus === JitsiParticipantConnectionStatus.INACTIVE = connectionStatus === JitsiParticipantConnectionStatus.INACTIVE
|| connectionStatus || connectionStatus
@ -207,30 +223,21 @@ class ParticipantView extends Component<Props> {
return ( return (
<Container <Container
onClick = { renderVideo ? undefined : onPress }
style = {{ style = {{
...styles.participantView, ...styles.participantView,
...this.props.style ...this.props.style
}}> }}
touchFeedback = { false }>
{ renderVideo { 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 && <VideoTrack
onPress = { renderVideo ? onPress : undefined }
videoTrack = { videoTrack } videoTrack = { videoTrack }
waitForVideoStarted = { waitForVideoStarted } waitForVideoStarted = { waitForVideoStarted }
zOrder = { this.props.zOrder } /> } zOrder = { this.props.zOrder } /> }
{ renderAvatar { 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 && <Avatar
size = { this.props.avatarSize } size = { this.props.avatarSize }
uri = { avatar } /> } 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 NavigateSectionList } from './NavigateSectionList';
export { default as Link } from './Link'; export { default as Link } from './Link';
export { default as LoadingIndicator } from './LoadingIndicator'; export { default as LoadingIndicator } from './LoadingIndicator';
export { default as Pressable } from './Pressable';
export { default as SideBar } from './SideBar'; export { default as SideBar } from './SideBar';
export { default as Text } from './Text'; export { default as Text } from './Text';
export { default as TintedView } from './TintedView'; export { default as TintedView } from './TintedView';

View File

@ -190,9 +190,7 @@ class Conference extends Component<Props> {
<Container <Container
accessibilityLabel = 'Conference' accessibilityLabel = 'Conference'
accessible = { false } accessible = { false }
onClick = { this._onClick } style = { styles.conference }>
style = { styles.conference }
touchFeedback = { false }>
<StatusBar <StatusBar
hidden = { true } hidden = { true }
translucent = { true } /> translucent = { true } />
@ -200,7 +198,7 @@ class Conference extends Component<Props> {
{/* {/*
* The LargeVideo is the lowermost stacking layer. * The LargeVideo is the lowermost stacking layer.
*/} */}
<LargeVideo /> <LargeVideo onPress = { this._onClick } />
{/* {/*
* If there is a ringing call, show the callee's info. * 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 = { type Props = {
/**
* Callback to invoke when the {@code LargeVideo} is clicked/pressed.
*/
onPress: Function,
/** /**
* The ID of the participant (to be) depicted by LargeVideo. * The ID of the participant (to be) depicted by LargeVideo.
* *
@ -107,13 +112,18 @@ class LargeVideo extends Component<Props, State> {
avatarSize, avatarSize,
useConnectivityInfoLabel useConnectivityInfoLabel
} = this.state; } = this.state;
const {
onPress,
_participantId
} = this.props;
return ( return (
<DimensionsDetector <DimensionsDetector
onDimensionsChanged = { this._onDimensionsChanged } > onDimensionsChanged = { this._onDimensionsChanged }>
<ParticipantView <ParticipantView
avatarSize = { avatarSize } avatarSize = { avatarSize }
participantId = { this.props._participantId } onPress = { onPress }
participantId = { _participantId }
style = { styles.largeVideo } style = { styles.largeVideo }
useConnectivityInfoLabel = { useConnectivityInfoLabel } useConnectivityInfoLabel = { useConnectivityInfoLabel }
zOrder = { 0 } /> zOrder = { 0 } />