import React, {useEffect, useCallback, useState, useRef} from 'react';
import {
Image,
useWindowDimensions,
View,
AppState,
StatusBar,
Platform,
TouchableOpacity,
Modal,
} from 'react-native';
import Orientation from 'react-native-orientation-locker';
import SystemNavigationBar from 'react-native-system-navigation-bar';
import {SourceType} from '../../source';
import {PlayerView} from '../../components/PlayerView';
import {usePlayer} from '../../hooks';
import {AdSourceType} from '../../advertising';
import {FullscreenHandler} from '../../ui';
import {useNavigation} from '@react-navigation/native';
import IonIcon from 'react-native-vector-icons/Ionicons';
import {ReplayIcon} from '../Icons';
import {styles, fullscreenBlock, landscapeBlock} from './styles';
class SampleFullscreenHandler implements FullscreenHandler {
isFullscreenActive: boolean = true;
onFullscreen: (fullscreenMode: boolean) => void;
constructor(
isFullscreenActive: boolean,
onFullscreen: (fullscreenMode: boolean) => void,
) {
this.isFullscreenActive = isFullscreenActive;
this.onFullscreen = onFullscreen;
}
enterFullscreen(): void {
if (Platform.OS === 'android') {
SystemNavigationBar.stickyImmersive(true);
} else {
StatusBar.setHidden(true);
}
this.onFullscreen(true);
this.isFullscreenActive = true;
Orientation.lockToLandscape();
}
exitFullscreen(): void {
if (Platform.OS === 'android') {
SystemNavigationBar.stickyImmersive(false);
} else {
StatusBar.setHidden(false);
}
this.onFullscreen(false);
this.isFullscreenActive = false;
Orientation.lockToPortrait();
}
}
interface BitmovinConfig {
playerKey: string;
analyticsKey: string;
supplementalPlayerUiCss: string;
}
export interface VideoPlayerProps {
bitmovinConfig?: BitmovinConfig;
onAdStarted?: () => void;
onAdCompleted?: () => void;
onPlay?: () => void;
onPaused?: () => void;
onEnd?: () => void;
setActivePlayerID?: (ref: string) => void;
onError?: (err: any) => void;
adTagUrl?: string;
videoUri?: string;
thumbUrl?: string;
testID?: string;
allowUseNavigation?: boolean;
autostart?: boolean;
autoPlayNextEnabled?: boolean;
activePlayerID?: string;
playerID?: string;
width?: number;
galleryIndex?: number;
selectedGalleryIndex?: number;
externalStyles?: any;
setFullscreenModeRedux?: (data: boolean) => void;
isExpandedAlerts?: boolean;
}
const VideoPlayer = ({
videoUri,
onAdCompleted,
onAdStarted,
onError,
onPlay,
onPaused,
thumbUrl,
onEnd,
adTagUrl,
autostart,
allowUseNavigation,
setActivePlayerID,
activePlayerID,
playerID,
setFullscreenModeRedux,
galleryIndex,
selectedGalleryIndex,
bitmovinConfig,
autoPlayNextEnabled,
externalStyles,
isExpandedAlerts,
}: VideoPlayerProps): React.ReactElement | null => {
const [isOverlayVisible, setIsOverlayVisible] = useState(!autostart);
const [isReplayButtonVisible, setIsReplayButtonVisible] = useState(false);
const [fullscreenMode, setFullscreenMode] = useState(false);
const fullscreenHandler = useRef(
new SampleFullscreenHandler(
fullscreenMode,
(isFullscreenModeActive: boolean) => {
setFullscreenModeRedux?.(isFullscreenModeActive);
setFullscreenMode(isFullscreenModeActive);
},
),
).current;
const {width, height} = useWindowDimensions();
const navigation = allowUseNavigation && useNavigation();
const player = bitmovinConfig?.analyticsKey && usePlayer({
licenseKey: bitmovinConfig?.playerKey,
analyticsConfig: {
key: bitmovinConfig.analyticsKey,
playerKey: bitmovinConfig?.playerKey,
},
styleConfig: {
supplementalPlayerUiCss:
bitmovinConfig?.supplementalPlayerUiCss,
},
});
useEffect(() => {
const subscription = AppState.addEventListener(
'change',
(nextAppState) => {
if (nextAppState === 'background' && player) {
player.pause();
}
},
);
return () => {
subscription.remove();
};
}, []);
useEffect(() => {
if (videoUri && player) {
player.load({
url: videoUri,
type: SourceType.HLS,
});
}
return () => {
player && player.destroy();
};
}, [player]);
useEffect(() => {
if (
playerID !== activePlayerID ||
galleryIndex !== selectedGalleryIndex
) {
player && player.pause();
}
if (autostart) {
setTimeout(() => {
setIsOverlayVisible(false);
if (videoUri && player) {
player.load({
url: videoUri,
type: SourceType.HLS,
});
}
player && player.play();
}, 1);
}
if (navigation) {
return navigation.addListener('blur', () => {
player && player.pause();
});
}
}, [
activePlayerID,
playerID,
player,
galleryIndex,
selectedGalleryIndex,
navigation,
videoUri,
autostart,
]);
useEffect(()=>{
player && player.pause();
}, [player, isExpandedAlerts])
const onReady = useCallback(() => {
if (player) {
if (adTagUrl) {
player.scheduleAd({
sources: [
{
tag: adTagUrl,
type: AdSourceType.IMA,
},
],
});
}
if (autostart) {
setIsOverlayVisible(false);
player && player.play();
}
}
}, [player, autostart, adTagUrl]);
const onPlayerError = useCallback(
(err: any) => {
onError?.(err);
},
[onError],
);
const onPlaybackFinished = useCallback(() => {
if (fullscreenMode) {
if (Platform.OS === 'android') {
SystemNavigationBar.stickyImmersive(false);
} else {
StatusBar.setHidden(false);
}
setFullscreenModeRedux?.(false);
setFullscreenMode(false);
Orientation.lockToPortrait();
}
if (!autoPlayNextEnabled) {
setIsReplayButtonVisible(true);
}
onEnd?.();
}, [onEnd, fullscreenMode, autoPlayNextEnabled, setFullscreenModeRedux, setFullscreenMode, setIsReplayButtonVisible]);
const handlePlay = useCallback(() => {
setIsOverlayVisible(false);
player && player.play();
}, [player]);
const handlePlaying = useCallback(() => {
if (playerID) {
setActivePlayerID?.(playerID);
}
}, [setActivePlayerID, playerID]);
const handleAdStarted = useCallback(()=>{
onAdStarted?.();
if (playerID) {
setActivePlayerID?.(playerID);
}
}, [onAdStarted, setActivePlayerID, playerID])
const handleReplay = useCallback(()=>{
player && player.seek(0);
player && player.play();
setIsReplayButtonVisible(false);
}, [player, setIsReplayButtonVisible]);
const renderPlayer = () => {
return player && fullscreenHandler && (
);
};
return (
{!fullscreenMode && (
{renderPlayer()}
{isOverlayVisible && (
)}
{isReplayButtonVisible && (
)}
)}
{renderPlayer()}
);
};
export default VideoPlayer;