[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:
parent
cb70c084b3
commit
decbcefbd4
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 } /> }
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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';
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 } />
|
||||||
|
|
Loading…
Reference in New Issue