feat: pinch-to-zoom video

This commit is contained in:
Adrian Castro
2024-02-13 20:49:43 +01:00
parent 5c5a8bf64d
commit 0a98e86de1
3 changed files with 42 additions and 17 deletions

View File

@@ -1,2 +1,3 @@
import "expo-router/entry"; import "expo-router/entry";
import "react-native-gesture-handler";
import "@react-native-anywhere/polyfill-base64"; import "@react-native-anywhere/polyfill-base64";

View File

@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { useEffect } from "react"; import { useEffect } from "react";
import { useColorScheme } from "react-native"; import { useColorScheme } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { useFonts } from "expo-font"; import { useFonts } from "expo-font";
import { SplashScreen, Stack } from "expo-router"; import { SplashScreen, Stack } from "expo-router";
import FontAwesome from "@expo/vector-icons/FontAwesome"; import FontAwesome from "@expo/vector-icons/FontAwesome";
@@ -57,7 +58,11 @@ export default function RootLayout() {
return null; return null;
} }
return <RootLayoutNav />; return (
<GestureHandlerRootView style={{ flex: 1 }}>
<RootLayoutNav />
</GestureHandlerRootView>
);
} }
function RootLayoutNav() { function RootLayoutNav() {

View File

@@ -1,6 +1,8 @@
import type { AVPlaybackSource } from "expo-av"; import type { AVPlaybackSource } from "expo-av";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { ActivityIndicator, Platform, StyleSheet, View } from "react-native"; import { ActivityIndicator, Platform, StyleSheet, View } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import { runOnJS, useSharedValue } from "react-native-reanimated";
import { ResizeMode, Video } from "expo-av"; import { ResizeMode, Video } from "expo-av";
import * as NavigationBar from "expo-navigation-bar"; import * as NavigationBar from "expo-navigation-bar";
import { useLocalSearchParams, useRouter } from "expo-router"; import { useLocalSearchParams, useRouter } from "expo-router";
@@ -37,7 +39,9 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
const [videoSrc, setVideoSrc] = useState<AVPlaybackSource>(); const [videoSrc, setVideoSrc] = useState<AVPlaybackSource>();
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [headerData, setHeaderData] = useState<HeaderData>(); const [headerData, setHeaderData] = useState<HeaderData>();
const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN);
const router = useRouter(); const router = useRouter();
const scale = useSharedValue(1);
const setVideoRef = usePlayerStore((state) => state.setVideoRef); const setVideoRef = usePlayerStore((state) => state.setVideoRef);
const setStatus = usePlayerStore((state) => state.setStatus); const setStatus = usePlayerStore((state) => state.setStatus);
const setIsIdle = usePlayerStore((state) => state.setIsIdle); const setIsIdle = usePlayerStore((state) => state.setIsIdle);
@@ -48,6 +52,19 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
(state) => state.dismissFullscreenPlayer, (state) => state.dismissFullscreenPlayer,
); );
const updateResizeMode = (newMode: ResizeMode) => {
setResizeMode(newMode);
};
const pinchGesture = Gesture.Pinch().onUpdate((e) => {
scale.value = e.scale;
if (scale.value > 1 && resizeMode !== ResizeMode.COVER) {
runOnJS(updateResizeMode)(ResizeMode.COVER);
} else if (scale.value <= 1 && resizeMode !== ResizeMode.CONTAIN) {
runOnJS(updateResizeMode)(ResizeMode.CONTAIN);
}
});
useEffect(() => { useEffect(() => {
const initializePlayer = async () => { const initializePlayer = async () => {
StatusBar.setStatusBarHidden(true); StatusBar.setStatusBarHidden(true);
@@ -122,22 +139,24 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
}; };
return ( return (
<View className="flex-1 items-center justify-center bg-black"> <GestureDetector gesture={pinchGesture}>
<Video <View className="flex-1 items-center justify-center bg-black">
ref={setVideoRef} <Video
source={videoSrc} ref={setVideoRef}
shouldPlay source={videoSrc}
resizeMode={ResizeMode.CONTAIN} shouldPlay
onLoadStart={onVideoLoadStart} resizeMode={resizeMode}
onReadyForDisplay={onReadyForDisplay} onLoadStart={onVideoLoadStart}
onPlaybackStatusUpdate={setStatus} onReadyForDisplay={onReadyForDisplay}
style={styles.video} onPlaybackStatusUpdate={setStatus}
onTouchStart={() => setIsIdle(false)} style={styles.video}
/> onTouchStart={() => setIsIdle(false)}
{isLoading && <ActivityIndicator size="large" color="#0000ff" />} />
{!isLoading && data && <Header data={headerData!} />} {isLoading && <ActivityIndicator size="large" color="#0000ff" />}
{!isLoading && <MiddleControls />} {!isLoading && data && <Header data={headerData!} />}
</View> {!isLoading && <MiddleControls />}
</View>
</GestureDetector>
); );
}; };