Skip to content
This repository has been archived by the owner on Nov 27, 2023. It is now read-only.

Commit

Permalink
feat: add pan callback
Browse files Browse the repository at this point in the history
  • Loading branch information
alantoa committed Mar 20, 2022
1 parent 26b1976 commit 0ca7c7c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 55 deletions.
75 changes: 59 additions & 16 deletions example/src/screens/example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
BottomSheetScrollView,
} from '@gorhom/bottom-sheet';
import { useTheme } from '@react-navigation/native';
import React, { useCallback, useRef } from 'react';
import { useState } from 'react';
import React, { useCallback, useRef, useState } from 'react';
import {
Dimensions,
Image,
Expand All @@ -19,22 +18,25 @@ import {
View,
ViewStyle,
} from 'react-native';
import { clamp } from 'react-native-awesome-slider/src/utils';
import { Gesture } from 'react-native-gesture-handler';
import InkWell from 'react-native-inkwell';
import Animated, {
runOnJS,
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated';
import {
SafeAreaView,
useSafeAreaInsets,
} from 'react-native-safe-area-context';
import { mb, mr, mt } from '../utils/ui-tools';
import VideoPlayer, { VideoPlayerRef, VideoProps } from '../../../src';
import VideoPlayer, { VideoPlayerRef } from '../../../src';
import { Text, ThemeView } from '../components';
import { Icon } from '../components/icon';
import type { IconNames } from '../components/iconfont';
import { palette } from '../theme/palette';
import InkWell from 'react-native-inkwell';
import { clamp } from 'react-native-awesome-slider/src/utils';
import { mb, mr, mt } from '../utils/ui-tools';
const px2dp = (px: number) => PixelRatio.roundToNearestPixel(px);
export const { width, height, scale, fontScale } = Dimensions.get('window');
const VIDEO_DEFAULT_HEIGHT = width * (9 / 16);
Expand Down Expand Up @@ -76,7 +78,8 @@ const options: { icon: IconNames; title: string }[] = [
title: 'Setting',
},
];

const MIN_OPEN_SNAP_POINT = 0;
const MAX_SNAP_POINT = height - 400;
export const Example = () => {
const [paused, setPaused] = useState(true);
const insets = useSafeAreaInsets();
Expand All @@ -90,28 +93,37 @@ export const Example = () => {
const isTapPaused = useRef(paused);
const sheetPrevIndex = useRef(-1);
const indexValue = useSharedValue(0);

const sheetTranslationY = useSharedValue(0);
const panTranslationY = useSharedValue(0);
const panVelocityY = useSharedValue(0);

const videoPlayerRef = useRef<VideoPlayerRef>(null);
const videoHeight = useSharedValue(VIDEO_DEFAULT_HEIGHT);
const pageStyle = useAnimatedStyle(() => {
// console.log(panTranslationY.value, panVelocityY.value);

const panIsVertical = useSharedValue(false);

const pageStyle = useAnimatedStyle(() => {
const translateY = panTranslationY.value + sheetTranslationY.value;
panTranslationY.value;
return {
transform: [
{
translateY: clamp(panTranslationY.value, 0, height),
translateY: clamp(translateY, MIN_OPEN_SNAP_POINT, MAX_SNAP_POINT),
},
],
};
});

const customContainerAnimationStyle = useAnimatedStyle(() => {
const customAnimationStyle = useAnimatedStyle(() => {
const translateY = panTranslationY.value + sheetTranslationY.value;
return {
transform: [
{
translateY: clamp(panTranslationY.value, 0, height),
translateY: clamp(
translateY * 0.3,
MIN_OPEN_SNAP_POINT,
MAX_SNAP_POINT,
),
},
],
height: videoHeight.value,
Expand Down Expand Up @@ -237,6 +249,38 @@ export const Example = () => {
),
[],
);
const seek = () => {
videoPlayerRef.current?.setSeekTo(100);
};

/**
* on pan event
*/
const panGesture = Gesture.Pan()
.onStart(({ velocityY, velocityX }) => {
panIsVertical.value = Math.abs(velocityY) > Math.abs(velocityX);
videoPlayerRef.current?.toggleControlViewOpacity(false);
runOnJS(seek)();
})
.onUpdate(({ translationY }) => {
if (!panIsVertical.value) {
return;
}
panTranslationY.value = translationY;
})
.onEnd(({ velocityY }, success) => {
// TODO
if (!success && velocityY < 300) return;
sheetTranslationY.value = sheetTranslationY.value + panTranslationY.value;
panTranslationY.value = 0;
const destSnapPoint =
sheetTranslationY.value < MAX_SNAP_POINT
? MAX_SNAP_POINT
: MIN_OPEN_SNAP_POINT;
sheetTranslationY.value = withSpring(destSnapPoint, {
mass: 0.5,
});
});
return (
<BottomSheetModalProvider>
<SafeAreaView style={styles.view} edges={['left', 'right']}>
Expand Down Expand Up @@ -271,10 +315,9 @@ export const Example = () => {
bubbleWidth: 120,
bubbleMaxWidth: 120,
}}
panTranslationY={panTranslationY}
panVelocityY={panVelocityY}
videoHeight={videoHeight}
customContainerAnimationStyle={customContainerAnimationStyle}
customAnimationStyle={customAnimationStyle}
onCustomPanGesture={panGesture}
/>
<View
style={[
Expand Down
83 changes: 44 additions & 39 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
AwesomeSliderProps,
} from 'react-native-awesome-slider/src/index';
import { clamp } from 'react-native-awesome-slider/src/utils';
import type { PanGesture } from 'react-native-gesture-handler';
import { Gesture } from 'react-native-gesture-handler';
import { GestureDetector } from 'react-native-gesture-handler';
import Orientation, { OrientationType } from 'react-native-orientation-locker';
Expand Down Expand Up @@ -87,14 +88,16 @@ export type VideoProps = VideoProperties & {
| 'bubbleWidth'
| 'bubbleTranslateY'
>;
panTranslationY?: Animated.SharedValue<number>;
panVelocityY?: Animated.SharedValue<number>;
videoHeight: Animated.SharedValue<number>;
customContainerAnimationStyle?: AnimatedStyleProp<ViewStyle>;
customAnimationStyle?: AnimatedStyleProp<ViewStyle>;
onCustomPanGesture?: PanGesture;
};
export type VideoPlayerRef = {
setPlay: () => void;
setPause: () => void;
toggleFullSreen: (isFullScreen: boolean) => void;
toggleControlViewOpacity: (isShow: boolean) => void;
setSeekTo: (second: number) => void;
};

const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
Expand Down Expand Up @@ -129,10 +132,9 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
onPausedChange,
onTapPause,
sliderProps,
panTranslationY,
panVelocityY,
videoHeight,
customContainerAnimationStyle,
customAnimationStyle,
onCustomPanGesture,
...rest
},
ref,
Expand Down Expand Up @@ -178,6 +180,16 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
checkTapTakesEffect();
pause();
},
toggleFullSreen: (isFullScrren: boolean) => {
isFullScrren ? enterFullScreen() : exitFullScreen();
},
toggleControlViewOpacity: (isShow: boolean) => {
'worklet';
isShow ? showControlAnimation() : hideControlAnimation();
},
setSeekTo: (seconds: number) => {
seekTo(seconds);
},
}));
/**
* refs
Expand Down Expand Up @@ -205,7 +217,6 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
const videoScale = useSharedValue(1);
const videoTransY = useSharedValue(0);
const panIsVertical = useSharedValue(false);
const panIsToTop = useSharedValue(false);

const doubleTapIsAlive = useSharedValue(false);

Expand All @@ -214,14 +225,7 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
const isScrubbing = useSharedValue(false);
const isSeeking = useRef(false);
const progress = useSharedValue(0);
const defaultContainerStyle = useAnimatedStyle(() => {
return { height: videoHeight.value };
}, []);
const containerStyle = customContainerAnimationStyle
? customContainerAnimationStyle
: defaultContainerStyle;

const videoStyle = useAnimatedStyle(() => {
const defaultVideoStyle = useAnimatedStyle(() => {
return {
transform: [
{
Expand All @@ -231,8 +235,12 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
translateY: videoTransY.value,
},
],
height: videoHeight.value,
};
}, []);
const videoStyle = customAnimationStyle
? customAnimationStyle
: defaultVideoStyle;

const bottomControlStyle = useAnimatedStyle(() => {
return {
Expand Down Expand Up @@ -371,15 +379,22 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
};

/**
* Animation to show controls...opposite of
* above...move onto the screen and then
* Animation to show controls
* fade in.
*/
const showControlAnimation = () => {
'worklet';
controlViewOpacity.value = withTiming(1, controlAnimteConfig);
setControlTimeout();
};
/**
* Animation to show controls
* fade out.
*/
const hideControlAnimation = () => {
'worklet';
controlViewOpacity.value = withTiming(0, controlAnimteConfig);
};
/**
* check on tap icon
* @returns bool
Expand Down Expand Up @@ -451,14 +466,12 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
/**
* on pan event
*/
const onPanGesture = Gesture.Pan()
.onStart(({ velocityY, velocityX, translationY }) => {
const defalutPanGesture = Gesture.Pan()
.onStart(({ velocityY, velocityX }) => {
panIsVertical.value = Math.abs(velocityY) > Math.abs(velocityX);
panIsToTop.value = translationY < 0;
})
.onUpdate(({ translationY, velocityY }) => {
.onUpdate(({ translationY }) => {
controlViewOpacity.value = withTiming(0, { duration: 100 });

if (fullScreen.value) {
if (translationY > 0 && Math.abs(translationY) < 100) {
videoScale.value = clamp(
Expand All @@ -469,32 +482,20 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
videoTransY.value = translationY;
}
} else {
if (panTranslationY && !panIsToTop.value) {
panTranslationY.value = translationY;
}
if (panVelocityY && !panIsToTop.value) {
panVelocityY.value = velocityY;
}
if (!panIsToTop.value) {
return;
}
if (translationY < 0 && Math.abs(translationY) < 40) {
videoScale.value = Math.abs(translationY) * 0.012 + 1;
}
}
})
.onEnd(({ translationY }) => {
if (!panIsVertical.value) {
.onEnd(({ translationY }, success) => {
if (!panIsVertical.value && !success) {
return;
}
if (fullScreen.value) {
if (translationY >= 100) {
runOnJS(exitFullScreen)();
}
} else {
if (!panIsToTop.value) {
return;
}
if (-translationY >= 40) {
runOnJS(enterFullScreen)();
}
Expand All @@ -503,6 +504,10 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
videoScale.value = withTiming(1);
});

const onPanGesture = onCustomPanGesture
? onCustomPanGesture
: defalutPanGesture;

const singleTapHandler = Gesture.Tap().onEnd((_event, success) => {
if (success) {
if (controlViewOpacity.value === 0) {
Expand Down Expand Up @@ -771,8 +776,8 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
/>
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.container, { paddingTop: insets.top }]}>
<Animated.View style={[styles.viewContainer]}>
<Animated.View style={[containerStyle, videoStyle]}>
<View style={styles.viewContainer}>
<Animated.View style={[videoStyle]}>
<Video
{...rest}
ref={videoPlayer}
Expand Down Expand Up @@ -1026,7 +1031,7 @@ const VideoPlayer = forwardRef<VideoPlayerRef, VideoProps>(
</Animated.View>
</Ripple>
</Animated.View>
</Animated.View>
</View>

{isIos && (
<View
Expand Down

0 comments on commit 0ca7c7c

Please sign in to comment.