From bd6c2409c3ecd52c83fcd3ea019cc040d47038e1 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:48:41 +0100 Subject: [PATCH] feat: gesture controls --- apps/expo/app.config.ts | 1 + apps/expo/package.json | 1 + apps/expo/src/app/videoPlayer/index.tsx | 80 ++++++++++++++++++++++++- pnpm-lock.yaml | 11 ++++ 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/apps/expo/app.config.ts b/apps/expo/app.config.ts index d03a74d..dc04199 100644 --- a/apps/expo/app.config.ts +++ b/apps/expo/app.config.ts @@ -27,6 +27,7 @@ const defineConfig = (): ExpoConfig => ({ foregroundImage: "./assets/images/adaptive-icon.png", backgroundColor: "#FFFFFF", }, + permissions: ["WRITE_SETTINGS"], }, web: { favicon: "./assets/images/favicon.png", diff --git a/apps/expo/package.json b/apps/expo/package.json index 9c420ca..02c8999 100644 --- a/apps/expo/package.json +++ b/apps/expo/package.json @@ -27,6 +27,7 @@ "clsx": "^2.1.0", "expo": "~50.0.5", "expo-av": "~13.10.5", + "expo-brightness": "~11.8.0", "expo-build-properties": "~0.11.1", "expo-constants": "~15.4.5", "expo-linking": "~6.2.2", diff --git a/apps/expo/src/app/videoPlayer/index.tsx b/apps/expo/src/app/videoPlayer/index.tsx index 88dccf0..f834c8e 100644 --- a/apps/expo/src/app/videoPlayer/index.tsx +++ b/apps/expo/src/app/videoPlayer/index.tsx @@ -1,9 +1,16 @@ import type { AVPlaybackSource } from "expo-av"; 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 { runOnJS, useSharedValue } from "react-native-reanimated"; import { ResizeMode, Video } from "expo-av"; +import * as Brightness from "expo-brightness"; import * as NavigationBar from "expo-navigation-bar"; import { useLocalSearchParams, useRouter } from "expo-router"; import * as StatusBar from "expo-status-bar"; @@ -40,6 +47,7 @@ const VideoPlayer: React.FC = ({ data }) => { const [headerData, setHeaderData] = useState(); const [resizeMode, setResizeMode] = useState(ResizeMode.CONTAIN); const [shouldPlay, setShouldPlay] = useState(true); + const [currentVolume, setCurrentVolume] = useState(0.5); const router = useRouter(); const scale = useSharedValue(1); const setVideoRef = usePlayerStore((state) => state.setVideoRef); @@ -76,7 +84,53 @@ const VideoPlayer: React.FC = ({ data }) => { 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(() => { const initializePlayer = async () => { @@ -90,6 +144,19 @@ const VideoPlayer: React.FC = ({ data }) => { if (Platform.OS === "android") { 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); const { item, stream, media } = data; @@ -141,7 +208,13 @@ const VideoPlayer: React.FC = ({ data }) => { void NavigationBar.setVisibilityAsync("visible"); } }; - }, [data, dismissFullscreenPlayer, presentFullscreenPlayer, router]); + }, [ + brightness, + data, + dismissFullscreenPlayer, + presentFullscreenPlayer, + router, + ]); const onVideoLoadStart = () => { setIsLoading(true); @@ -159,6 +232,7 @@ const VideoPlayer: React.FC = ({ data }) => { source={videoSrc} shouldPlay={shouldPlay} resizeMode={resizeMode} + volume={currentVolume} onLoadStart={onVideoLoadStart} onReadyForDisplay={onReadyForDisplay} onPlaybackStatusUpdate={setStatus} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1986990..c50e331 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,6 +58,9 @@ importers: expo-av: specifier: ~13.10.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: specifier: ~0.11.1 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) 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): resolution: {integrity: sha512-m4j4aEjFaDuBE6KWYMxDhWgLzzSmpE7uHKAwtvXyNmRK+6JKF0gjiXi0sXgI5ngNppDQpsyPFMvqG7uQpRuCuw==} peerDependencies: