@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.
180 lines (178 loc) • 5.88 kB
JavaScript
;
import React, { useCallback, useEffect } from 'react';
import { AppState, StyleSheet, View } from 'react-native';
import Video from 'react-native-video';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
import { runOnJS } from 'react-native-reanimated';
import { videoRef } from "./utils/videoRef.js";
import { lockToLandscape, lockToPortrait } from "./utils/lockOrientation.js";
import { getVideoSource, handlePause } from "./utils/index.js";
import MediaControlsProvider from "./MediaControls/MediaControlsProvider.js";
import { useVideoPlayerStore } from "./store/videoPlayerStore.js";
import { createPlayerEvents } from "./utils/playerEvents.js";
import globalStyles from "./Styles/globalStyles.js";
import { VideoPlayerConfigProvider } from "./context/index.js";
import { useWatchReporter } from "./utils/useWatchReporter.js";
import { jsx as _jsx } from "react/jsx-runtime";
const controlsStyles = {
hideForward: true,
hideDuration: true,
hideFullscreen: true,
hidePlayPause: true,
hideNavigationBarOnFullScreenMode: true,
hideNotificationBarOnFullScreenMode: true,
hideNext: true,
hidePosition: true,
hidePrevious: true,
hideRewind: true,
hideSeekBar: true,
hideSettingButton: true
};
const VideoPlayer = ({
onClose,
isFocused = true,
mode = 'fullscreen',
seekTime,
event,
autoNext = true,
theme,
onWatchProgress
}) => {
const {
isPaused,
resizeMode,
setResizeMode,
setControlsVisible,
controlsVisible,
playBackRate,
selectedAudioTrack,
selectedSubtitleTrack,
maxBitRate,
selectedVideoTrack,
setIsPaused,
playList,
currentTrackIndex,
activeTrack,
setError
} = useVideoPlayerStore();
const playerEvents = createPlayerEvents();
const {
reportProgress
} = useWatchReporter({
onWatchProgress
});
useEffect(() => {
if (isFocused) {
if (mode === 'fullscreen') {
lockToLandscape();
} else {
lockToPortrait();
}
} else {
lockToPortrait();
}
}, [isFocused, mode]);
const handleCombinedProgress = useCallback(progressEvent => {
playerEvents.onProgress(progressEvent);
}, [playerEvents]);
useEffect(() => {
if (seekTime && !activeTrack?.isTrailer && videoRef?.current) {
videoRef.current?.seek(seekTime);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [seekTime, videoRef?.current]);
useEffect(() => {
const handleAppStateChange = nextState => {
if (nextState === 'inactive' || nextState === 'background') {
handlePause();
setIsPaused(true);
reportProgress('PROGRESS');
}
};
const sub = AppState.addEventListener('change', handleAppStateChange);
return () => sub.remove();
}, [reportProgress, setIsPaused]);
const trigger = type => {
switch (type) {
case 'Pinch':
if (resizeMode === 'cover') {
setResizeMode('contain');
} else {
setResizeMode('cover');
}
break;
case 'Tap':
{
setControlsVisible(!controlsVisible);
}
}
};
const composedGestures = Gesture.Race(Gesture.Pinch().onEnd(() => runOnJS(trigger)('Pinch')), Gesture.Tap().onEnd(() => runOnJS(trigger)('Tap')));
return /*#__PURE__*/_jsx(VideoPlayerConfigProvider, {
theme: theme,
children: /*#__PURE__*/_jsx(SafeAreaProvider, {
style: globalStyles.flexOne,
children: /*#__PURE__*/_jsx(GestureHandlerRootView, {
style: globalStyles.flexOne,
children: /*#__PURE__*/_jsx(MediaControlsProvider, {
onClose: () => {
reportProgress('VIDEO_CLOSE');
onClose?.();
},
onPressEpisode: async ({
episode
}) => {
if (event?.onPressEpisode) {
return await event.onPressEpisode({
episode
});
}
return Promise.resolve(true);
},
reportProgress: reportProgress,
children: /*#__PURE__*/_jsx(GestureDetector, {
gesture: composedGestures,
children: /*#__PURE__*/_jsx(View, {
style: globalStyles.flexOneWithBlackBackground,
children: /*#__PURE__*/_jsx(Video, {
ref: videoRef,
source: getVideoSource({
playList,
currentTrackIndex
}),
paused: isPaused,
onProgress: handleCombinedProgress,
onLoad: playerEvents.onLoad,
onBuffer: playerEvents.onBuffer,
onEnd: () => {
playerEvents.onEnd({
reportProgress,
onPressEpisode: event?.onPressEpisode ?? (async () => true),
autoNext
});
},
onLoadStart: playerEvents.onLoadStart,
onError: () => setError("Video couldn't be loaded"),
controls: false,
resizeMode: resizeMode || 'contain',
rate: playBackRate || 1,
selectedAudioTrack: selectedAudioTrack,
selectedTextTrack: selectedSubtitleTrack?.value === 'Off' ? undefined : selectedSubtitleTrack,
selectedVideoTrack: selectedVideoTrack ? {
type: selectedVideoTrack.type,
value: selectedVideoTrack.value
} : undefined,
maxBitRate: maxBitRate ?? undefined,
style: StyleSheet.absoluteFillObject,
controlsStyles: controlsStyles
})
})
})
})
})
})
});
};
export default VideoPlayer;
//# sourceMappingURL=VideoPlayer.js.map