2021-02-03 21:59:19 +00:00
|
|
|
/**
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
2022-12-01 08:42:50 +00:00
|
|
|
import { Audio, InterruptionModeAndroid, InterruptionModeIOS, Video, VideoFullscreenUpdate } from 'expo-av';
|
2021-10-20 04:43:02 +00:00
|
|
|
import { observer } from 'mobx-react-lite';
|
2021-10-07 05:06:01 +00:00
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
|
|
import { Alert } from 'react-native';
|
2021-02-03 21:59:19 +00:00
|
|
|
|
2021-02-04 06:29:10 +00:00
|
|
|
import MediaTypes from '../constants/MediaTypes';
|
2021-10-07 05:06:01 +00:00
|
|
|
import { useStores } from '../hooks/useStores';
|
2021-02-18 06:08:44 +00:00
|
|
|
import { msToTicks } from '../utils/Time';
|
2021-02-03 21:59:19 +00:00
|
|
|
|
|
|
|
const VideoPlayer = observer(() => {
|
|
|
|
const { rootStore } = useStores();
|
|
|
|
|
|
|
|
const player = useRef(null);
|
2021-02-25 19:41:42 +00:00
|
|
|
// Local player fullscreen state
|
|
|
|
const [ isPresenting, setIsPresenting ] = useState(false);
|
|
|
|
const [ isDismissing, setIsDismissing ] = useState(false);
|
2021-02-03 21:59:19 +00:00
|
|
|
|
2021-02-18 18:32:36 +00:00
|
|
|
// Set the audio mode when the video player is created
|
2021-02-03 21:59:19 +00:00
|
|
|
useEffect(() => {
|
|
|
|
Audio.setAudioModeAsync({
|
2022-11-29 16:17:40 +00:00
|
|
|
interruptionModeAndroid: InterruptionModeAndroid.DoNotMix,
|
|
|
|
interruptionModeIOS: InterruptionModeIOS.DoNotMix,
|
2021-02-03 21:59:19 +00:00
|
|
|
playsInSilentModeIOS: true
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
2021-02-18 18:32:36 +00:00
|
|
|
// Update the player when media type or uri changes
|
2021-02-17 17:41:17 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (rootStore.mediaStore.type === MediaTypes.Video) {
|
2021-02-20 04:11:29 +00:00
|
|
|
rootStore.didPlayerCloseManually = true;
|
2021-02-17 17:41:17 +00:00
|
|
|
player.current?.loadAsync({
|
|
|
|
uri: rootStore.mediaStore.uri
|
|
|
|
}, {
|
|
|
|
positionMillis: rootStore.mediaStore.positionMillis,
|
|
|
|
shouldPlay: true
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, [ rootStore.mediaStore.type, rootStore.mediaStore.uri ]);
|
|
|
|
|
2021-02-18 18:32:36 +00:00
|
|
|
// Update the play/pause state when the store indicates it should
|
|
|
|
useEffect(() => {
|
2021-11-09 19:35:46 +00:00
|
|
|
if (rootStore.mediaStore.type === MediaTypes.Video && rootStore.mediaStore.shouldPlayPause) {
|
2021-02-18 18:32:36 +00:00
|
|
|
if (rootStore.mediaStore.isPlaying) {
|
|
|
|
player.current?.pauseAsync();
|
|
|
|
} else {
|
|
|
|
player.current?.playAsync();
|
|
|
|
}
|
|
|
|
rootStore.mediaStore.shouldPlayPause = false;
|
|
|
|
}
|
|
|
|
}, [ rootStore.mediaStore.shouldPlayPause ]);
|
|
|
|
|
|
|
|
// Close the player when the store indicates it should stop playback
|
|
|
|
useEffect(() => {
|
2021-11-09 19:35:46 +00:00
|
|
|
if (rootStore.mediaStore.type === MediaTypes.Video && rootStore.mediaStore.shouldStop) {
|
2021-02-20 04:11:29 +00:00
|
|
|
rootStore.didPlayerCloseManually = false;
|
2021-02-25 19:41:42 +00:00
|
|
|
closeFullscreen();
|
2021-02-18 18:32:36 +00:00
|
|
|
rootStore.mediaStore.shouldStop = false;
|
|
|
|
}
|
|
|
|
}, [ rootStore.mediaStore.shouldStop ]);
|
|
|
|
|
2021-02-25 19:41:42 +00:00
|
|
|
const openFullscreen = () => {
|
|
|
|
if (!isPresenting) {
|
|
|
|
player.current?.presentFullscreenPlayer()
|
|
|
|
.catch(e => {
|
|
|
|
console.error(e);
|
|
|
|
Alert.alert(e);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const closeFullscreen = () => {
|
|
|
|
if (!isDismissing) {
|
|
|
|
player.current?.dismissFullscreenPlayer()
|
|
|
|
.catch(e => {
|
|
|
|
console.debug(e);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-03 21:59:19 +00:00
|
|
|
return (
|
|
|
|
<Video
|
|
|
|
ref={player}
|
|
|
|
usePoster
|
2022-03-21 13:51:06 +00:00
|
|
|
posterSource={{ uri: rootStore.mediaStore.backdropUri }}
|
2021-02-03 21:59:19 +00:00
|
|
|
resizeMode='contain'
|
|
|
|
useNativeControls
|
2021-02-25 19:41:42 +00:00
|
|
|
onReadyForDisplay={openFullscreen}
|
2021-02-20 04:11:29 +00:00
|
|
|
onPlaybackStatusUpdate={({ isPlaying, positionMillis, didJustFinish }) => {
|
|
|
|
if (didJustFinish) {
|
|
|
|
rootStore.didPlayerCloseManually = false;
|
2021-02-25 19:41:42 +00:00
|
|
|
closeFullscreen();
|
2021-02-20 04:11:29 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-02-18 06:08:44 +00:00
|
|
|
rootStore.mediaStore.isPlaying = isPlaying;
|
|
|
|
rootStore.mediaStore.positionTicks = msToTicks(positionMillis);
|
|
|
|
}}
|
2021-02-03 21:59:19 +00:00
|
|
|
onFullscreenUpdate={({ fullscreenUpdate }) => {
|
2021-02-04 06:29:10 +00:00
|
|
|
switch (fullscreenUpdate) {
|
2022-12-01 08:42:50 +00:00
|
|
|
case VideoFullscreenUpdate.PLAYER_WILL_PRESENT:
|
2021-02-25 19:41:42 +00:00
|
|
|
setIsPresenting(true);
|
2021-02-04 06:29:10 +00:00
|
|
|
rootStore.isFullscreen = true;
|
|
|
|
break;
|
2022-12-01 08:42:50 +00:00
|
|
|
case VideoFullscreenUpdate.PLAYER_DID_PRESENT:
|
2021-02-25 19:41:42 +00:00
|
|
|
setIsPresenting(false);
|
|
|
|
break;
|
2022-12-01 08:42:50 +00:00
|
|
|
case VideoFullscreenUpdate.PLAYER_WILL_DISMISS:
|
2021-02-25 19:41:42 +00:00
|
|
|
setIsDismissing(true);
|
|
|
|
break;
|
2022-12-01 08:42:50 +00:00
|
|
|
case VideoFullscreenUpdate.PLAYER_DID_DISMISS:
|
2021-02-25 19:41:42 +00:00
|
|
|
setIsDismissing(false);
|
2021-02-04 06:29:10 +00:00
|
|
|
rootStore.isFullscreen = false;
|
|
|
|
rootStore.mediaStore.reset();
|
|
|
|
player.current?.unloadAsync()
|
|
|
|
.catch(console.debug);
|
|
|
|
break;
|
2021-02-03 21:59:19 +00:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
onError={e => {
|
|
|
|
console.error(e);
|
|
|
|
Alert.alert(e);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
export default VideoPlayer;
|