diff --git a/app.json b/app.json index 2dfe334a..0f1c9ac2 100644 --- a/app.json +++ b/app.json @@ -41,7 +41,8 @@ "package": "com.fredrikburmester.streamyfin", "permissions": [ "android.permission.FOREGROUND_SERVICE", - "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" + "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK", + "android.permission.WRITE_SETTINGS" ] }, "plugins": [ diff --git a/app/(auth)/player/direct-player.tsx b/app/(auth)/player/direct-player.tsx index 0ab6343e..030fa67c 100644 --- a/app/(auth)/player/direct-player.tsx +++ b/app/(auth)/player/direct-player.tsx @@ -455,21 +455,6 @@ export default function page() { writeToLog("ERROR", "Video Error", e.nativeEvent); }} /> - - - - {videoRef.current && ( { selectedTextTrack={selectedTextTrack} selectedAudioTrack={selectedAudioTrack} /> - - - ) : ( No video source... diff --git a/bun.lockb b/bun.lockb index 3a854c55..971e5d45 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/video-player/controls/BrightnessSlider.tsx b/components/video-player/controls/BrightnessSlider.tsx new file mode 100644 index 00000000..33fe0e0f --- /dev/null +++ b/components/video-player/controls/BrightnessSlider.tsx @@ -0,0 +1,67 @@ +import React, { useEffect } from "react"; +import { View, StyleSheet } from "react-native"; +import { useSharedValue } from "react-native-reanimated"; +import { Slider } from "react-native-awesome-slider"; +import * as Brightness from "expo-brightness"; +import { Ionicons } from "@expo/vector-icons"; +import MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons"; + +const BrightnessSlider = () => { + const brightness = useSharedValue(50); + const min = useSharedValue(0); + const max = useSharedValue(100); + + useEffect(() => { + const fetchInitialBrightness = async () => { + const initialBrightness = await Brightness.getBrightnessAsync(); + brightness.value = initialBrightness * 100; + }; + fetchInitialBrightness(); + }, [brightness]); + + const handleValueChange = async (value: number) => { + brightness.value = value; + await Brightness.setBrightnessAsync(value / 100); + }; + + return ( + + + + + ); +}; + +const styles = StyleSheet.create({ + sliderContainer: { + width: 150, + display: "flex", + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + }, +}); + +export default BrightnessSlider; diff --git a/components/video-player/controls/Controls.tsx b/components/video-player/controls/Controls.tsx index e61579de..a143fa0f 100644 --- a/components/video-player/controls/Controls.tsx +++ b/components/video-player/controls/Controls.tsx @@ -50,6 +50,7 @@ import { VideoProvider } from "./contexts/VideoContext"; import * as Haptics from "expo-haptics"; import DropdownViewDirect from "./dropdown/DropdownViewDirect"; import DropdownViewTranscoding from "./dropdown/DropdownViewTranscoding"; +import BrightnessSlider from "./BrightnessSlider"; interface Props { item: BaseItemDto; @@ -324,220 +325,303 @@ export const Controls: React.FC = ({ mediaSource={mediaSource} isVideoLoaded={isVideoLoaded} > - - - {!mediaSource?.TranscodingUrl ? ( - - ) : ( - - )} - + {!mediaSource?.TranscodingUrl ? ( + + ) : ( + + )} + - + - - Skip Intro - - + Skip Intro + + - + + Skip Credits + + + + { + toggleControls(); + }} + style={{ + position: "absolute", + width: Dimensions.get("window").width, + height: Dimensions.get("window").height, + }} + > + + + top: 0, + right: 0, + opacity: showControls ? 1 : 0, + }, + ]} + pointerEvents={showControls ? "auto" : "none"} + className={`flex flex-row items-center space-x-2 z-10 p-4 `} + > + {previousItem && ( - Skip Credits - - - - { - toggleControls(); - }} - style={{ - position: "absolute", - width: Dimensions.get("window").width, - height: Dimensions.get("window").height, - }} - > - - - {Platform.OS !== "ios" && ( - - - - )} - { - if (stop) await stop(); - router.back(); - }} + onPress={goToPreviousItem} className="aspect-square flex flex-col bg-neutral-800/90 rounded-xl items-center justify-center p-2" > - + - + )} - - - {item?.Name} - {item?.Type === "Episode" && ( - {item.SeriesName} - )} - {item?.Type === "Movie" && ( - {item?.ProductionYear} - )} - {item?.Type === "Audio" && ( - {item?.Album} - )} - - - - - - - - + + )} + + {mediaSource?.TranscodingUrl && ( + + + + )} + { + if (stop) await stop(); + router.back(); + }} + className="aspect-square flex flex-col bg-neutral-800/90 rounded-xl items-center justify-center p-2" + > + + + + + + + + + + + + + {settings?.rewindSkipTime} + + + + + { + togglePlay(progress.value); + }} + > + {!isBuffering ? ( + + ) : ( + + )} + + + + + + + {settings?.forwardSkipTime} + + + + + + + + {item?.Name} + {item?.Type === "Episode" && ( + {item.SeriesName} + )} + {item?.Type === "Movie" && ( + {item?.ProductionYear} + )} + {item?.Type === "Audio" && ( + {item?.Album} + )} + + + + ( + - - { - togglePlay(progress.value); - }} - > - - - - - - - - - - - { - if (!trickPlayUrl || !trickplayInfo) { - return null; - } - const { x, y, url } = trickPlayUrl; - - const tileWidth = 150; - const tileHeight = 150 / trickplayInfo.aspectRatio!; - return ( + )} + cache={cacheProgress} + onSlidingStart={handleSliderStart} + onSlidingComplete={handleSliderComplete} + onValueChange={handleSliderChange} + containerStyle={{ + borderRadius: 100, + }} + renderBubble={() => { + if (!trickPlayUrl || !trickplayInfo) { + return null; + } + const { x, y, url } = trickPlayUrl; + const tileWidth = 150; + const tileHeight = 150 / trickplayInfo.aspectRatio!; + return ( + @@ -552,48 +636,44 @@ export const Controls: React.FC = ({ { translateX: -x * tileWidth }, { translateY: -y * tileHeight }, ], + resizeMode: "cover", }} source={{ uri: url }} contentFit="cover" /> - - {`${time.hours > 0 ? `${time.hours}:` : ""}${ - time.minutes < 10 ? `0${time.minutes}` : time.minutes - }:${ - time.seconds < 10 ? `0${time.seconds}` : time.seconds - }`} - - ); - }} - sliderHeight={10} - thumbWidth={0} - progress={progress} - minimumValue={min} - maximumValue={max} - /> - - - {formatTimeString(currentTime, isVlc ? "ms" : "s")} - - - -{formatTimeString(remainingTime, isVlc ? "ms" : "s")} - - + + {`${time.hours > 0 ? `${time.hours}:` : ""}${ + time.minutes < 10 ? `0${time.minutes}` : time.minutes + }:${ + time.seconds < 10 ? `0${time.seconds}` : time.seconds + }`} + + + ); + }} + sliderHeight={10} + thumbWidth={0} + progress={progress} + minimumValue={min} + maximumValue={max} + /> + + + {formatTimeString(currentTime, isVlc ? "ms" : "s")} + + + -{formatTimeString(remainingTime, isVlc ? "ms" : "s")} + - + ); }; diff --git a/package.json b/package.json index b71b26ff..cf2b2402 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "expo-asset": "~10.0.10", "expo-background-fetch": "~12.0.1", "expo-blur": "~13.0.2", + "expo-brightness": "~12.0.1", "expo-build-properties": "~0.12.5", "expo-constants": "~16.0.2", "expo-dev-client": "~4.0.29",