Added feature to show audio slider when changing audio through device

This commit is contained in:
Alex Kim
2024-12-10 05:20:49 +11:00
parent b0adad8dc4
commit 5d79ee34cf
3 changed files with 61 additions and 15 deletions

View File

@@ -1,15 +1,21 @@
import React, { useEffect } from "react";
import React, { useEffect, useRef } from "react";
import { View, StyleSheet } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import { Slider } from "react-native-awesome-slider";
import { VolumeManager } from "react-native-volume-manager";
import { Ionicons } from "@expo/vector-icons";
const AudioSlider = () => {
interface AudioSliderProps {
setVisibility: (show: boolean) => void;
}
const AudioSlider: React.FC<AudioSliderProps> = ({ setVisibility }) => {
const volume = useSharedValue<number>(50); // Explicitly type as number
const min = useSharedValue<number>(0); // Explicitly type as number
const max = useSharedValue<number>(100); // Explicitly type as number
const timeoutRef = useRef<NodeJS.Timeout | null>(null); // Use a ref to store the timeout ID
useEffect(() => {
const fetchInitialVolume = async () => {
try {
@@ -33,7 +39,7 @@ const AudioSlider = () => {
const handleValueChange = async (value: number) => {
volume.value = value;
console.log("volume", value);
console.log("volume through slider", value);
await VolumeManager.setVolume(value / 100);
// Re-call showNativeVolumeUI to ensure the setting is applied on iOS
@@ -42,14 +48,28 @@ const AudioSlider = () => {
useEffect(() => {
const volumeListener = VolumeManager.addVolumeListener((result) => {
console.log("Volume changed:", result.volume);
console.log("Volume through device", result.volume);
volume.value = result.volume * 100;
setVisibility(true);
// Clear any existing timeout
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
// Set a new timeout to hide the visibility after 2 seconds
timeoutRef.current = setTimeout(() => {
setVisibility(false);
}, 1000);
});
return () => {
volumeListener.remove();
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
}, [volume]);
return (
<View style={styles.sliderContainer}>

View File

@@ -253,7 +253,14 @@ export const Controls: React.FC<Props> = ({
useEffect(() => {
prefetchAllTrickplayImages();
}, []);
const toggleControls = () => setShowControls(!showControls);
const toggleControls = () => {
if (showControls) {
setShowAudioSlider(false);
setShowControls(false);
} else {
setShowControls(true);
}
};
const handleSliderStart = useCallback(() => {
if (showControls === false) return;
@@ -438,6 +445,9 @@ export const Controls: React.FC<Props> = ({
router.replace(`player/transcoding-player?${queryParams}`);
};
// Used when user changes audio through audio button on device.
const [showAudioSlider, setShowAudioSlider] = useState(false);
return (
<ControlProvider
item={item}
@@ -546,7 +556,6 @@ export const Controls: React.FC<Props> = ({
alignItems: "center",
transform: [{ translateY: -22.5 }], // Adjust for the button's height (half of 45)
paddingHorizontal: "28%", // Add some padding to the left and right
opacity: showControls ? 1 : 0,
}}
pointerEvents={showControls ? "box-none" : "none"}
>
@@ -557,6 +566,7 @@ export const Controls: React.FC<Props> = ({
transform: [{ rotate: "270deg" }], // Rotate the slider to make it vertical
left: 0,
bottom: 30,
opacity: showControls ? 1 : 0,
}}
>
<BrightnessSlider />
@@ -567,6 +577,7 @@ export const Controls: React.FC<Props> = ({
position: "relative",
justifyContent: "center",
alignItems: "center",
opacity: showControls ? 1 : 0,
}}
>
<Ionicons
@@ -601,6 +612,9 @@ export const Controls: React.FC<Props> = ({
name={isPlaying ? "pause" : "play"}
size={50}
color="white"
style={{
opacity: showControls ? 1 : 0,
}}
/>
) : (
<Loader size={"large"} />
@@ -613,6 +627,7 @@ export const Controls: React.FC<Props> = ({
position: "relative",
justifyContent: "center",
alignItems: "center",
opacity: showControls ? 1 : 0,
}}
>
<Ionicons name="refresh-outline" size={50} color="white" />
@@ -637,9 +652,10 @@ export const Controls: React.FC<Props> = ({
transform: [{ rotate: "270deg" }], // Rotate the slider to make it vertical
bottom: 30,
right: 0,
opacity: showAudioSlider || showControls ? 1 : 0,
}}
>
<AudioSlider />
<AudioSlider setVisibility={setShowAudioSlider} />
</View>
</View>

View File

@@ -1,6 +1,9 @@
import { TrackInfo } from '@/modules/vlc-player';
import { BaseItemDto, MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client';
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { TrackInfo } from "@/modules/vlc-player";
import {
BaseItemDto,
MediaSourceInfo,
} from "@jellyfin/sdk/lib/generated-client";
import React, { createContext, useContext, useState, ReactNode } from "react";
interface ControlContextProps {
item: BaseItemDto;
@@ -8,7 +11,9 @@ interface ControlContextProps {
isVideoLoaded: boolean | undefined;
}
const ControlContext = createContext<ControlContextProps | undefined>(undefined);
const ControlContext = createContext<ControlContextProps | undefined>(
undefined
);
interface ControlProviderProps {
children: ReactNode;
@@ -17,7 +22,12 @@ interface ControlProviderProps {
isVideoLoaded: boolean | undefined;
}
export const ControlProvider: React.FC<ControlProviderProps> = ({ children, item, mediaSource, isVideoLoaded }) => {
export const ControlProvider: React.FC<ControlProviderProps> = ({
children,
item,
mediaSource,
isVideoLoaded,
}) => {
return (
<ControlContext.Provider value={{ item, mediaSource, isVideoLoaded }}>
{children}
@@ -28,7 +38,7 @@ export const ControlProvider: React.FC<ControlProviderProps> = ({ children, item
export const useControlContext = () => {
const context = useContext(ControlContext);
if (context === undefined) {
throw new Error('useControlContext must be used within a ControlProvider');
throw new Error("useControlContext must be used within a ControlProvider");
}
return context;
};
};