UNPKG

@zezosoft/zezo-ott-react-native-video-player

Version:

React Native OTT Video Player for Android & iOS. Supports playlists, seasons, auto-next playback, subtitles, theming, analytics, fullscreen mode, and custom controls. 🚀 Powered by ZezoSoft.

208 lines (207 loc) • 5.87 kB
"use strict"; /* eslint-disable react-native/no-inline-styles */ import React, { useState, useRef } from 'react'; import { ActivityIndicator, StyleSheet, Text, TouchableOpacity, View, Animated, Easing } from 'react-native'; import { moderateScale, scale } from 'react-native-size-matters'; import { RFValue } from 'react-native-responsive-fontsize'; import { Play, Pause, RotateCcw, RotateCw } from 'lucide-react-native'; import { useVideoPlayerStore } from "../store/videoPlayerStore.js"; import { videoRef } from "../utils/videoRef.js"; import { handlePause } from "../utils/index.js"; import { useVideoPlayerConfig } from "../context/index.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const BUTTON_SIZE = moderateScale(80); const SMALL_BUTTON_SIZE = moderateScale(60); const FEEDBACK_DURATION = 500; const MOVE_DISTANCE = 60; const MiddleControls = () => { const { isPaused, isBuffering, setStartWatchTime, error, setIsPaused, duration, currentTime, setCurrentTime } = useVideoPlayerStore(); const { colors } = useVideoPlayerConfig(); if (error) { return /*#__PURE__*/_jsx(View, { style: [StyleSheet.absoluteFillObject, styles.container], children: /*#__PURE__*/_jsx(Text, { style: [styles.errorText, { color: colors.text }], children: error }) }); } const handleSkip = delta => { let newTime = currentTime + delta; if (newTime < 0) newTime = 0; if (newTime > duration) newTime = duration; videoRef?.current?.seek(newTime); setCurrentTime(newTime); }; const isVideoEnded = duration > 0 && currentTime >= duration; return /*#__PURE__*/_jsxs(View, { style: [StyleSheet.absoluteFillObject, styles.container], children: [/*#__PURE__*/_jsx(SkipButton, { direction: "backward", onPress: ({ second }) => handleSkip(-second), colors: colors, disabled: currentTime <= 0 }), /*#__PURE__*/_jsx(TouchableOpacity, { onPress: () => { if (isBuffering) return; if (isVideoEnded) { videoRef.current?.seek(0); setCurrentTime(0); setIsPaused(false); setStartWatchTime(Date.now()); return; } if (!isPaused) { handlePause(); setIsPaused(true); } else { setIsPaused(false); setStartWatchTime(Date.now()); } }, style: [styles.button, styles.playButton], activeOpacity: 0.8, children: isBuffering ? /*#__PURE__*/_jsx(ActivityIndicator, { size: scale(50), color: colors.text }) : isPaused ? /*#__PURE__*/_jsx(Play, { size: scale(50), color: colors.text }) : /*#__PURE__*/_jsx(Pause, { size: scale(50), color: colors.text }) }), /*#__PURE__*/_jsx(SkipButton, { direction: "forward", onPress: ({ second }) => handleSkip(second), colors: colors, disabled: currentTime >= duration })] }); }; export default MiddleControls; const SkipButton = ({ direction, onPress, colors, disabled }) => { const [step, setStep] = useState(0); const anim = useRef(new Animated.Value(0)).current; const timeoutRef = useRef(null); const handlePress = () => { if (disabled) return; const newStep = step + 10; setStep(newStep); onPress({ second: newStep }); anim.setValue(0); Animated.timing(anim, { toValue: 1, duration: FEEDBACK_DURATION, easing: Easing.out(Easing.quad), useNativeDriver: true }).start(); if (timeoutRef.current) clearTimeout(timeoutRef.current); timeoutRef.current = setTimeout(() => setStep(0), FEEDBACK_DURATION); }; const translateX = anim.interpolate({ inputRange: [0, 1], outputRange: direction === 'forward' ? [SMALL_BUTTON_SIZE, SMALL_BUTTON_SIZE + MOVE_DISTANCE] : [-SMALL_BUTTON_SIZE, -SMALL_BUTTON_SIZE - MOVE_DISTANCE] }); const opacity = anim.interpolate({ inputRange: [0, 0.8, 1], outputRange: [1, 1, 0] }); const scaleAnim = anim.interpolate({ inputRange: [0, 0.5, 1], outputRange: [1, 1.3, 1] }); return /*#__PURE__*/_jsxs(TouchableOpacity, { onPress: handlePress, style: [styles.button, styles.smallButton, disabled && { opacity: 0.3 }], activeOpacity: disabled ? 1 : 0.7, disabled: disabled, children: [direction === 'forward' ? /*#__PURE__*/_jsx(RotateCw, { size: scale(35), color: colors.text }) : /*#__PURE__*/_jsx(RotateCcw, { size: scale(35), color: colors.text }), step > 0 && !disabled && /*#__PURE__*/_jsx(Animated.View, { style: [styles.feedbackOverlay, { transform: [{ translateX }, { scale: scaleAnim }], opacity }], children: /*#__PURE__*/_jsxs(Text, { style: [styles.feedbackText, { color: colors.text }], children: [step, "s"] }) })] }); }; const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }, button: { justifyContent: 'center', alignItems: 'center', borderRadius: 100 }, playButton: { width: BUTTON_SIZE, height: BUTTON_SIZE, marginHorizontal: moderateScale(14) }, smallButton: { width: SMALL_BUTTON_SIZE, height: SMALL_BUTTON_SIZE, marginHorizontal: moderateScale(10) }, errorText: { fontSize: RFValue(18), fontWeight: '600', textAlign: 'center', paddingHorizontal: scale(20) }, feedbackOverlay: { position: 'absolute', justifyContent: 'center', alignItems: 'center' }, feedbackText: { fontSize: RFValue(15), fontWeight: '600' } }); //# sourceMappingURL=MiddleControls.js.map