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;