Skip to content

Commit

Permalink
VC-1416 - Fullscreen player orientation (#629)
Browse files Browse the repository at this point in the history
https://jesusfilmmedia.atlassian.net/browse/VC-1416

Co-authored-by: Vlad Mitkovsky <vlad@mitkovsky.com>
  • Loading branch information
lumberman and Vlad Mitkovsky authored Apr 16, 2021
1 parent 17eb73d commit 113965e
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 181 deletions.
209 changes: 60 additions & 149 deletions src/components/Video/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@ import React, {
useState,
useRef,
useEffect,
ReactElement,
useCallback,
ReactElement,
MutableRefObject,
useLayoutEffect,
} from 'react';
import RNVideo from 'react-native-video';
// https://github.com/react-native-community/react-native-video#usage
import YoutubePlayer from 'react-native-youtube-iframe';
import YoutubePlayer, { YoutubeIframeRef } from 'react-native-youtube-iframe';
import Slider from '@react-native-community/slider';
import {
View,
useWindowDimensions,
ImageBackground,
ActivityIndicator,
Platform,
StyleProp,
ViewStyle,
Modal,
} from 'react-native';
import Orientation, { OrientationType } from 'react-native-orientation-locker';
import Orientation from 'react-native-orientation-locker';
import { useFocusEffect } from '@react-navigation/native';
import { useDispatch } from 'react-redux';
import { useMount, youtubeParser, lockToPortrait } from 'utils';
import useInterval from 'utils/useInterval';
import st from 'utils/st';
import theme from 'utils/theme';
import { ui } from 'assets';
import { TStep } from 'utils/types';
import Flex from 'components/Flex';
import VokeIcon from 'components/VokeIcon';
import Touchable from 'components/Touchable';
import Text from 'components/Text';
import { TStep } from 'utils/types';
import useOrientation from 'hooks/useOrientation';

import BackButton from '../BackButton';
import { updateVideoIsPlayingState } from '../../actions/requests';
Expand All @@ -50,18 +50,17 @@ function convertTime(time: number): string {
}

interface RefYouTube {
current: object | null;
current: Record<string, unknown> | null;
seekTo: (value: number) => void;
getCurrentTime: () => Promise<void>;
}

interface RefArcLight {
current: object | null;
current: Record<string, unknown> | null;
seek: (value: number) => void;
}

interface Props {
onOrientationChange?: (orientation: string) => void;
onPlay?: (time: number) => void;
onPause?: (time: number) => void;
onStop?: (time: number) => void;
Expand All @@ -73,9 +72,6 @@ interface Props {
}

function Video({
onOrientationChange = (): void => {
//void
},
onPlay = (): void => {
//void
},
Expand All @@ -91,15 +87,14 @@ function Video({
lockOrientation = false,
children, // Used to create custom overlay/play button. Ex: "Watch Trailer".
}: Props): ReactElement {
let youtubeVideo = useRef<RefYouTube>(null);
let arclightVideo = useRef<RefArcLight>(null);
const lockOrientationRef = useRef<boolean>(lockOrientation);
const youtubeVideo = useRef<MutableRefObject<YoutubeIframeRef | null>>(null);
const arclightVideo = useRef<RefArcLight>(null);

const orientation = useOrientation();

// System lock (android only).
// const [rotationLock, setRotationLock] = useState(false);
const [screenOrientation, setScreenOrientation] = useState<string>(
'portrait',
);

const [isBuffering, setIsBuffering] = useState<boolean>(false);
const [videoReady, setVideoReady] = useState<boolean>(false);
const [started, setStarted] = useState<boolean>(false);
Expand All @@ -111,9 +106,6 @@ function Video({
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);

// const time = youtubeVideo.current.getCurrentTime();
// const duration = youtubeVideo.current.getDuration();

// Update progress slider every second.
useInterval(() => {
if (!youtubeVideo.current) return;
Expand All @@ -128,108 +120,36 @@ function Video({
setRefreshInterval(isPlaying ? 1000 : null);
}, [dispatch, isPlaying]);

useEffect(() => {
const shortSize =
window.width > window.height ? window.height : window.width;
const longSize =
window.width > window.height ? window.width : window.height;

setWidth(screenOrientation === 'portrait' ? shortSize : longSize);
setHeight(
screenOrientation === 'portrait' ? shortSize / 1.75 : longSize / 1.75,
);
}, [lockOrientation, screenOrientation, window.height, window.width]);
const udpateDimensions = useCallback(
(newOrientation = orientation) => {
const shortSize =
window.width > window.height ? window.height : window.width;
const longSize =
window.width > window.height ? window.width : window.height;

const getLandscapeOrPortrait = useCallback(
(orientation: string): string => {
let newOrientation = screenOrientation;

if (
lockOrientationRef.current ||
orientation === 'PORTRAIT' ||
orientation === 'PORTRAIT-UPSIDEDOWN' // ot supported on iOS
) {
newOrientation = 'portrait';
} else if (
orientation === 'LANDSCAPE-LEFT' ||
orientation === 'LANDSCAPE-RIGHT'
) {
newOrientation = 'landscape';
}

// In all other cases (FACE-UP,FACE-DOWN,UNKNOWN) leave current value as is.
setScreenOrientation(newOrientation);
return newOrientation;
setWidth(newOrientation === 'portrait' ? shortSize : longSize);
setHeight(
newOrientation === 'portrait' ? shortSize / 1.75 : longSize / 1.75,
);
},
[screenOrientation],
[orientation, window.height, window.width],
);

const handleOrientationChange = useCallback(
(orientation: OrientationType): void => {
if (!lockOrientationRef.current) {
onOrientationChange(getLandscapeOrPortrait(orientation));
} else {
onOrientationChange(getLandscapeOrPortrait('PORTRAIT'));
}
},
[getLandscapeOrPortrait, onOrientationChange],
);
useEffect(() => {
udpateDimensions(orientation);
}, [orientation, udpateDimensions]);

useMount(() => {
if (lockOrientation) {
lockToPortrait();
}

if (autoPlay && !lockOrientation) {
if (Platform.OS === 'ios') {
Orientation.lockToAllOrientationsButUpsideDown(); // iOS only
} else {
Orientation.unlockAllOrientations();
}
const initial = Orientation.getInitialOrientation();
onOrientationChange(getLandscapeOrPortrait(initial)); // TODO: Add delay here.
} else {
lockToPortrait();
onOrientationChange('portrait');
}

/* if (Platform.OS === 'android' && Platform.Version < 26 ) { */
if (Platform.OS === 'android') {
// Only Device Orientation Listener works on older Android models.
Orientation.addDeviceOrientationListener(handleOrientationChange);
} else {
Orientation.addOrientationListener(handleOrientationChange);
Orientation.unlockAllOrientations();
}

return function cleanup() {
Orientation.removeOrientationListener(handleOrientationChange);
Orientation.lockToPortrait();
};
});

useEffect(() => {
lockOrientationRef.current = lockOrientation;
if (lockOrientation) {
lockToPortrait();
handleOrientationChange('PORTRAIT'); // Need for Android.
} else {
if (Platform.OS === 'ios') {
Orientation.lockToAllOrientationsButUpsideDown(); // iOS only
} else {
Orientation.unlockAllOrientations();
}

Orientation.getOrientation(orientation => {
onOrientationChange(getLandscapeOrPortrait(orientation));
});
}
}, [
getLandscapeOrPortrait,
handleOrientationChange,
lockOrientation,
onOrientationChange,
]);

// Events firing when user leaves the screen with player or comes back.
useFocusEffect(
React.useCallback(() => {
Expand All @@ -239,8 +159,6 @@ function Video({
// When the screen with a player is unfocused:
// - Pause video.
setIsPlaying(false);
youtubeVideo = null;
arclightVideo = null;
};
}, []),
);
Expand Down Expand Up @@ -305,7 +223,7 @@ function Video({
style={{
backgroundColor: '#000',
overflow: 'hidden',
width: width,
width: '100%',
height: height,
}}
>
Expand All @@ -315,30 +233,27 @@ function Video({
<ImageBackground
resizeMode="cover"
source={{ uri: item?.thumbnails?.large }}
style={[
st.aic,
st.jcc,
st.bgDeepBlack,
{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 1,
},
]}
style={{
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.colors.black,
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
zIndex: 1,
}}
/>
)}
{item?.type === 'youtube' ? (
<YoutubePlayer
ref={youtubeVideo}
videoId={youtubeParser(item?.url)}
width={width}
height={height}
play={isPlaying}
onChangeState={(state): void => {
handleVideoStateChange(state);
handleVideoStateChange(state as string);
}}
onReady={(): void => {
handleVideoStateChange('ready');
Expand Down Expand Up @@ -393,7 +308,7 @@ function Video({
// resizeMode="cover"
repeat={true}
style={{
width: '100%',
width: width,
height: '100%',
}}
// fullscreen={false} // Platforms: iOS - Controls whether the player enters fullscreen on play.
Expand All @@ -402,16 +317,14 @@ function Video({
)}
<Flex
direction="column"
style={[
st.absblr,
st.bgTransparent,
st.w100,
{
top: 0,
bottom: 0,
zIndex: 2,
},
]}
style={{
position: 'absolute',
backgroundColor: 'transparent',
width: '100%',
top: 0,
bottom: 0,
zIndex: 2,
}}
self="stretch"
>
{/* Custom overlay to be used instead of play/pause button. */}
Expand Down Expand Up @@ -487,17 +400,15 @@ function Video({
direction="row"
justify="between"
align="center"
style={[
st.ph5,
{
backgroundColor:
item?.type === 'youtube'
? 'rgba(0,0,0,1)'
: 'rgba(0,0,0,0.4)',
opacity: isPlaying ? 0 : 1,
minHeight: 50,
},
]}
style={{
paddingHorizontal: 10,
backgroundColor:
item?.type === 'youtube'
? 'rgba(0,0,0,1)'
: 'rgba(0,0,0,0.4)',
opacity: isPlaying ? 0 : 1,
minHeight: 50,
}}
>
<Flex value={1}>
<Touchable onPress={togglePlayState}>
Expand Down
2 changes: 1 addition & 1 deletion src/domain/Adventure/Active/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function AdventureActive({ navigation, route }: Props): React.ReactElement {
animated={false}
barStyle="light-content"
translucent={false}
// translucent={ isPortrait && insets.top > 0 ? false : true } // Android. The app will draw under the status bar.
// translucent={ orientation === 'portrait' && insets.top > 0 ? false : true } // Android. The app will draw under the status bar.
backgroundColor="#000" // Android. The background color of the status bar.
/>
</View>
Expand Down
Loading

0 comments on commit 113965e

Please sign in to comment.