mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-02-07 21:12:22 +00:00
wip
This commit is contained in:
@@ -20,6 +20,8 @@ import { Text } from "./common/Text";
|
||||
import { Loader } from "./Loader";
|
||||
import { Dimensions } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { Bubble, Slider } from "react-native-awesome-slider";
|
||||
import { runtimeTicksToMinutes } from "@/utils/time";
|
||||
|
||||
export const CurrentlyPlayingBar: React.FC = () => {
|
||||
const segments = useSegments();
|
||||
@@ -66,6 +68,22 @@ export const CurrentlyPlayingBar: React.FC = () => {
|
||||
right: 16,
|
||||
});
|
||||
|
||||
const textValues = useSharedValue({
|
||||
height: 70,
|
||||
bottom: 90,
|
||||
left: 149,
|
||||
width: 140,
|
||||
});
|
||||
|
||||
const animatedTextStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
bottom: withTiming(textValues.value.bottom, { duration: 500 }),
|
||||
left: withTiming(textValues.value.left, { duration: 500 }),
|
||||
height: withTiming(textValues.value.height, { duration: 500 }),
|
||||
width: withTiming(textValues.value.width, { duration: 500 }),
|
||||
};
|
||||
});
|
||||
|
||||
const animatedButtonStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
bottom: withTiming(buttonsValues.value.bottom, { duration: 500 }),
|
||||
@@ -84,6 +102,18 @@ export const CurrentlyPlayingBar: React.FC = () => {
|
||||
};
|
||||
});
|
||||
|
||||
const poster = useMemo(() => {
|
||||
if (currentlyPlaying?.item.Type === "Audio")
|
||||
return `${api?.basePath}/Items/${currentlyPlaying.item.AlbumId}/Images/Primary?tag=${currentlyPlaying.item.AlbumPrimaryImageTag}&quality=90&maxHeight=200&maxWidth=200`;
|
||||
else
|
||||
return getBackdropUrl({
|
||||
api,
|
||||
item: currentlyPlaying?.item,
|
||||
quality: 70,
|
||||
width: 200,
|
||||
});
|
||||
}, [currentlyPlaying?.item.Id, api]);
|
||||
|
||||
const startPosition = useMemo(
|
||||
() =>
|
||||
currentlyPlaying?.item?.UserData?.PlaybackPositionTicks
|
||||
@@ -126,12 +156,6 @@ export const CurrentlyPlayingBar: React.FC = () => {
|
||||
};
|
||||
});
|
||||
|
||||
const animatedValues = useSharedValue({
|
||||
paddingBottom: 0,
|
||||
paddingInner: 0,
|
||||
borderRadiusBottom: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (size === "full") {
|
||||
backgroundValues.value = {
|
||||
@@ -171,18 +195,39 @@ export const CurrentlyPlayingBar: React.FC = () => {
|
||||
width: 113,
|
||||
left: 16,
|
||||
};
|
||||
textValues.value = {
|
||||
bottom: 78,
|
||||
height: 64,
|
||||
left: 141,
|
||||
width: 140,
|
||||
};
|
||||
}
|
||||
}, [size, screenHeight, insets]);
|
||||
|
||||
const progress = useSharedValue(0);
|
||||
const min = useSharedValue(0);
|
||||
const max = useSharedValue(currentlyPlaying?.item.RunTimeTicks || 0);
|
||||
|
||||
useEffect(() => {
|
||||
max.value = currentlyPlaying?.item.RunTimeTicks || 0;
|
||||
}, [currentlyPlaying?.item.RunTimeTicks]);
|
||||
|
||||
if (!api || !currentlyPlaying) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Animated.View
|
||||
className={`bg-black rounded-lg absolute`}
|
||||
className={`bg-neutral-800 rounded-lg absolute`}
|
||||
style={[animatedBackgroundStyle]}
|
||||
></Animated.View>
|
||||
|
||||
<Animated.View
|
||||
className={`border border-red-600 absolute`}
|
||||
style={[animatedTextStyle]}
|
||||
>
|
||||
<Text>{currentlyPlaying.item.Name}</Text>
|
||||
</Animated.View>
|
||||
|
||||
<Animated.View
|
||||
className={`flex flex-row items-center z-10`}
|
||||
style={[
|
||||
@@ -211,68 +256,109 @@ export const CurrentlyPlayingBar: React.FC = () => {
|
||||
|
||||
<Animated.View
|
||||
style={[animatedVideoStyle]}
|
||||
className={` rounded-md absolute overflow-hidden flex flex-col items-center justify-center pointer-events-none z-0`}
|
||||
className={` rounded-md absolute overflow-hidden flex flex-col items-center justify-center pointer-events-none z-0 object-contain`}
|
||||
>
|
||||
<View className="">
|
||||
{videoSource && (
|
||||
<Video
|
||||
ref={videoRef}
|
||||
allowsExternalPlayback
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
playWhenInactive={true}
|
||||
playInBackground={true}
|
||||
showNotificationControls={true}
|
||||
ignoreSilentSwitch="ignore"
|
||||
controls={false}
|
||||
pictureInPicture={true}
|
||||
debug={{
|
||||
enable: true,
|
||||
thread: true,
|
||||
}}
|
||||
onProgress={(e) => onProgress(e)}
|
||||
subtitleStyle={{
|
||||
fontSize: 16,
|
||||
}}
|
||||
source={videoSource}
|
||||
onRestoreUserInterfaceForPictureInPictureStop={() => {
|
||||
setTimeout(() => {
|
||||
presentFullscreenPlayer();
|
||||
}, 300);
|
||||
}}
|
||||
onFullscreenPlayerDidDismiss={() => {}}
|
||||
onFullscreenPlayerDidPresent={() => {}}
|
||||
onPlaybackStateChanged={(e) => {
|
||||
if (e.isPlaying === true) {
|
||||
playVideo(false);
|
||||
} else if (e.isPlaying === false) {
|
||||
pauseVideo(false);
|
||||
}
|
||||
}}
|
||||
onVolumeChange={(e) => {
|
||||
setVolume(e.volume);
|
||||
}}
|
||||
progressUpdateInterval={4000}
|
||||
onError={(e) => {
|
||||
console.log(e);
|
||||
writeToLog(
|
||||
"ERROR",
|
||||
"Video playback error: " + JSON.stringify(e)
|
||||
);
|
||||
Alert.alert("Error", "Cannot play this video file.");
|
||||
setIsPlaying(false);
|
||||
// setCurrentlyPlaying(null);
|
||||
}}
|
||||
renderLoader={
|
||||
currentlyPlaying.item?.Type !== "Audio" && (
|
||||
<View className="flex flex-col items-center justify-center h-full">
|
||||
<Loader />
|
||||
</View>
|
||||
)
|
||||
{videoSource && (
|
||||
<Video
|
||||
ref={videoRef}
|
||||
allowsExternalPlayback
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
resizeMode="contain"
|
||||
playWhenInactive={true}
|
||||
playInBackground={true}
|
||||
showNotificationControls={true}
|
||||
ignoreSilentSwitch="ignore"
|
||||
controls={false}
|
||||
pictureInPicture={true}
|
||||
debug={{
|
||||
enable: true,
|
||||
thread: true,
|
||||
}}
|
||||
onProgress={(e) => {
|
||||
onProgress(e);
|
||||
}}
|
||||
subtitleStyle={{
|
||||
fontSize: 16,
|
||||
}}
|
||||
source={videoSource}
|
||||
onRestoreUserInterfaceForPictureInPictureStop={() => {
|
||||
setTimeout(() => {
|
||||
presentFullscreenPlayer();
|
||||
}, 300);
|
||||
}}
|
||||
onFullscreenPlayerDidDismiss={() => {}}
|
||||
onFullscreenPlayerDidPresent={() => {}}
|
||||
onPlaybackStateChanged={(e) => {
|
||||
if (e.isPlaying === true) {
|
||||
playVideo(false);
|
||||
} else if (e.isPlaying === false) {
|
||||
pauseVideo(false);
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
}}
|
||||
onVolumeChange={(e) => {
|
||||
setVolume(e.volume);
|
||||
}}
|
||||
progressUpdateInterval={4000}
|
||||
onError={(e) => {
|
||||
console.log(e);
|
||||
writeToLog("ERROR", "Video playback error: " + JSON.stringify(e));
|
||||
Alert.alert("Error", "Cannot play this video file.");
|
||||
setIsPlaying(false);
|
||||
// setCurrentlyPlaying(null);
|
||||
}}
|
||||
renderLoader={
|
||||
currentlyPlaying.item?.Type !== "Audio" && (
|
||||
<View className="flex flex-col items-center justify-center h-full">
|
||||
<Loader />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Animated.View>
|
||||
{size === "full" && (
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
position: "absolute",
|
||||
bottom: insets.bottom + 16,
|
||||
left: 16,
|
||||
width: screenWiidth - 32,
|
||||
}}
|
||||
>
|
||||
<Slider
|
||||
theme={{
|
||||
maximumTrackTintColor: "rgba(1,1,1,0.2)",
|
||||
minimumTrackTintColor: "#fff",
|
||||
cacheTrackTintColor: "#333",
|
||||
bubbleBackgroundColor: "#fff",
|
||||
bubbleTextColor: "#000",
|
||||
heartbeatColor: "#999",
|
||||
}}
|
||||
onSlidingComplete={(val) => {
|
||||
const tick = Math.floor(val);
|
||||
console.log(tick);
|
||||
videoRef.current?.seek(tick);
|
||||
progress.value = tick;
|
||||
}}
|
||||
containerStyle={{
|
||||
borderRadius: 100,
|
||||
}}
|
||||
bubble={(s) => runtimeTicksToMinutes(s)}
|
||||
sliderHeight={12}
|
||||
thumbWidth={0}
|
||||
progress={progress}
|
||||
minimumValue={min}
|
||||
maximumValue={max}
|
||||
/>
|
||||
<Text className="mt-2 text-xs text-neutral-500">
|
||||
{runtimeTicksToMinutes(progress.value)}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* <Animated.View
|
||||
style={[
|
||||
|
||||
Reference in New Issue
Block a user