import { useDoubleTapGesture, useLongPressGesture, usePanGesture, useSingleTapGesture } from '../hooks';
import React, { type FC, type ReactNode } from 'react';
import { StyleSheet, Text, View, type StyleProp, type ViewStyle } from 'react-native';
import { GestureDetector, Gesture, type ComposedGesture, type TapGesture } from 'react-native-gesture-handler';
import Animated, { FadeInUp, FadeOutDown } from 'react-native-reanimated';
import { useVideo } from '../providers';
import type { GestureHandlerProps } from '../types';
/**
* A component that displays the seek time text.
*/
export const SeekText: FC<{ children: ReactNode }> = ({ children }) => {
return {children};
};
/**
* A component that displays an overlayed view.
*/
export const OverlayedView = React.forwardRef<
any,
{
children: ReactNode;
style: StyleProp;
}
>(({ children, style }, ref) => {
return (
{children}
);
});
/**
* A component that handles gestures for the video player.
*
* This component is responsible for handling single-tap, double-tap, and pan gestures.
*/
export const GestureHandler: FC = ({
doubleTapSeekInterval = 10,
onDoubleTapSeekStart,
onDoubleTapSeekEnd,
onSingleTap,
onLongPressStart,
onLongPressEnd,
onLeftVerticalPan,
onRightVerticalPan,
onGlobalVerticalPan,
children,
}) => {
const { state } = useVideo();
const { fullscreen, videoRef, config, theme } = state;
const {
doubleTapGesture,
isDoubleTap,
doubleTapValue,
backwardRippleRef,
forwardRippleRef,
backwardAnimatedRipple,
forwardAnimatedRipple,
forwardAnimatedStyle,
backwardAnimatedStyle,
} = useDoubleTapGesture({
videoRef,
doubleTapSeekInterval,
onDoubleTapSeekStart,
onDoubleTapSeekEnd,
});
const { singleTapGesture } = useSingleTapGesture({ onSingleTap });
const { longPressGesture, isPlaybackRateIncreased } = useLongPressGesture({ onLongPressStart, onLongPressEnd });
const { verticalPanGesture } = usePanGesture({ onLeftVerticalPan, onRightVerticalPan, onGlobalVerticalPan });
let composedGesture: ComposedGesture | TapGesture;
if (config.enableDoubleTapGestures && config.enablePanGestures) {
composedGesture = Gesture.Exclusive(doubleTapGesture, singleTapGesture, verticalPanGesture, longPressGesture);
} else if (config.enableDoubleTapGestures) {
composedGesture = Gesture.Exclusive(doubleTapGesture, singleTapGesture, longPressGesture);
} else if (config.enablePanGestures) {
composedGesture = Gesture.Exclusive(verticalPanGesture, singleTapGesture, longPressGesture);
} else {
composedGesture = singleTapGesture;
}
const FULLSCREEN_HEIGHT = fullscreen ? '50%' : '100%';
return (
{isPlaybackRateIncreased && (
2x
)}
-{doubleTapValue.backward}s
+{doubleTapValue.forward}s
{children}
);
};
export default GestureHandler;
const styles = StyleSheet.create({
seekText: {
fontSize: 10,
fontWeight: 'bold',
color: 'white',
padding: 10,
backgroundColor: 'rgba(0,0,0,0.3)',
borderRadius: 8,
},
overlayedView: {
position: 'absolute',
top: 0,
width: '50%',
justifyContent: 'center',
alignItems: 'center',
pointerEvents: 'none',
zIndex: 10,
overflow: 'hidden',
borderRadius: '50%',
transform: [{ scale: 1.5 }],
// backgroundColor: 'red', //for debugging purposes
},
badgeContainer: {
...StyleSheet.absoluteFillObject,
alignItems: 'center',
zIndex: 99,
top: '5%',
},
badgeText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
paddingHorizontal: 16,
textAlign: 'center',
borderRadius: 6,
},
});