feat: gesture controls

This commit is contained in:
Adrian Castro
2024-02-14 14:48:41 +01:00
parent 91d85deccb
commit bd6c2409c3
4 changed files with 90 additions and 3 deletions

View File

@@ -27,6 +27,7 @@ const defineConfig = (): ExpoConfig => ({
foregroundImage: "./assets/images/adaptive-icon.png", foregroundImage: "./assets/images/adaptive-icon.png",
backgroundColor: "#FFFFFF", backgroundColor: "#FFFFFF",
}, },
permissions: ["WRITE_SETTINGS"],
}, },
web: { web: {
favicon: "./assets/images/favicon.png", favicon: "./assets/images/favicon.png",

View File

@@ -27,6 +27,7 @@
"clsx": "^2.1.0", "clsx": "^2.1.0",
"expo": "~50.0.5", "expo": "~50.0.5",
"expo-av": "~13.10.5", "expo-av": "~13.10.5",
"expo-brightness": "~11.8.0",
"expo-build-properties": "~0.11.1", "expo-build-properties": "~0.11.1",
"expo-constants": "~15.4.5", "expo-constants": "~15.4.5",
"expo-linking": "~6.2.2", "expo-linking": "~6.2.2",

View File

@@ -1,9 +1,16 @@
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,
Dimensions,
Platform,
StyleSheet,
View,
} from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler"; import { Gesture, GestureDetector } from "react-native-gesture-handler";
import { runOnJS, useSharedValue } from "react-native-reanimated"; import { runOnJS, useSharedValue } from "react-native-reanimated";
import { ResizeMode, Video } from "expo-av"; import { ResizeMode, Video } from "expo-av";
import * as Brightness from "expo-brightness";
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";
import * as StatusBar from "expo-status-bar"; import * as StatusBar from "expo-status-bar";
@@ -40,6 +47,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
const [headerData, setHeaderData] = useState<HeaderData>(); const [headerData, setHeaderData] = useState<HeaderData>();
const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN); const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN);
const [shouldPlay, setShouldPlay] = useState(true); const [shouldPlay, setShouldPlay] = useState(true);
const [currentVolume, setCurrentVolume] = useState(0.5);
const router = useRouter(); const router = useRouter();
const scale = useSharedValue(1); const scale = useSharedValue(1);
const setVideoRef = usePlayerStore((state) => state.setVideoRef); const setVideoRef = usePlayerStore((state) => state.setVideoRef);
@@ -76,7 +84,53 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
runOnJS(togglePlayback)(); runOnJS(togglePlayback)();
}); });
const composedGesture = Gesture.Exclusive(pinchGesture, doubleTapGesture); const brightness = useSharedValue(0.5);
const handleVolumeChange = (newValue: number) => {
setCurrentVolume(newValue);
};
const handleBrightnessChange = async (newValue: number) => {
try {
await Brightness.setBrightnessAsync(newValue);
} catch (error) {
console.error("Failed to set brightness:", error);
}
};
const screenHalfWidth = Dimensions.get("window").width / 2;
const panGesture = Gesture.Pan()
.onStart((event) => {
const isRightHalf = event.x > screenHalfWidth;
if (isRightHalf) {
runOnJS(setCurrentVolume)(0.5);
} else {
brightness.value = 0.5;
}
})
.onUpdate((event) => {
const divisor = 5000;
if (event.x > screenHalfWidth) {
const change = -event.translationY / divisor;
const newVolume = Math.max(0, Math.min(1, currentVolume + change));
runOnJS(handleVolumeChange)(newVolume);
} else {
const change = -event.translationY / divisor;
const newBrightness = Math.max(
0,
Math.min(1, brightness.value + change),
);
brightness.value = newBrightness;
runOnJS(handleBrightnessChange)(newBrightness);
}
});
const composedGesture = Gesture.Exclusive(
panGesture,
pinchGesture,
doubleTapGesture,
);
useEffect(() => { useEffect(() => {
const initializePlayer = async () => { const initializePlayer = async () => {
@@ -90,6 +144,19 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
if (Platform.OS === "android") { if (Platform.OS === "android") {
await NavigationBar.setVisibilityAsync("hidden"); await NavigationBar.setVisibilityAsync("hidden");
} }
const { status } = await Brightness.requestPermissionsAsync();
if (status !== Brightness.PermissionStatus.GRANTED) {
console.warn("Brightness permissions not granted");
}
try {
const currentBrightness = await Brightness.getBrightnessAsync();
brightness.value = currentBrightness;
} catch (error) {
console.error("Failed to get initial brightness:", error);
}
setIsLoading(true); setIsLoading(true);
const { item, stream, media } = data; const { item, stream, media } = data;
@@ -141,7 +208,13 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
void NavigationBar.setVisibilityAsync("visible"); void NavigationBar.setVisibilityAsync("visible");
} }
}; };
}, [data, dismissFullscreenPlayer, presentFullscreenPlayer, router]); }, [
brightness,
data,
dismissFullscreenPlayer,
presentFullscreenPlayer,
router,
]);
const onVideoLoadStart = () => { const onVideoLoadStart = () => {
setIsLoading(true); setIsLoading(true);
@@ -159,6 +232,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({ data }) => {
source={videoSrc} source={videoSrc}
shouldPlay={shouldPlay} shouldPlay={shouldPlay}
resizeMode={resizeMode} resizeMode={resizeMode}
volume={currentVolume}
onLoadStart={onVideoLoadStart} onLoadStart={onVideoLoadStart}
onReadyForDisplay={onReadyForDisplay} onReadyForDisplay={onReadyForDisplay}
onPlaybackStatusUpdate={setStatus} onPlaybackStatusUpdate={setStatus}

11
pnpm-lock.yaml generated
View File

@@ -58,6 +58,9 @@ importers:
expo-av: expo-av:
specifier: ~13.10.5 specifier: ~13.10.5
version: 13.10.5(expo@50.0.5) version: 13.10.5(expo@50.0.5)
expo-brightness:
specifier: ~11.8.0
version: 11.8.0(expo@50.0.5)
expo-build-properties: expo-build-properties:
specifier: ~0.11.1 specifier: ~0.11.1
version: 0.11.1(expo@50.0.5) version: 0.11.1(expo@50.0.5)
@@ -5517,6 +5520,14 @@ packages:
expo: 50.0.5(@babel/core@7.23.9)(@react-native/babel-preset@0.73.20) expo: 50.0.5(@babel/core@7.23.9)(@react-native/babel-preset@0.73.20)
dev: false dev: false
/expo-brightness@11.8.0(expo@50.0.5):
resolution: {integrity: sha512-ipQA7s8PvJVhy+Ls6Dsql0veXXV5CdMcbXNPwQuXTbUofRE+8FHO0vasShMZlKYcD9KNgFygjx0U+THi80dtAw==}
peerDependencies:
expo: '*'
dependencies:
expo: 50.0.5(@babel/core@7.23.9)(@react-native/babel-preset@0.73.20)
dev: false
/expo-build-properties@0.11.1(expo@50.0.5): /expo-build-properties@0.11.1(expo@50.0.5):
resolution: {integrity: sha512-m4j4aEjFaDuBE6KWYMxDhWgLzzSmpE7uHKAwtvXyNmRK+6JKF0gjiXi0sXgI5ngNppDQpsyPFMvqG7uQpRuCuw==} resolution: {integrity: sha512-m4j4aEjFaDuBE6KWYMxDhWgLzzSmpE7uHKAwtvXyNmRK+6JKF0gjiXi0sXgI5ngNppDQpsyPFMvqG7uQpRuCuw==}
peerDependencies: peerDependencies: