diff --git a/app/(auth)/items/[id].tsx b/app/(auth)/items/[id].tsx
index a205d4f9..86b88913 100644
--- a/app/(auth)/items/[id].tsx
+++ b/app/(auth)/items/[id].tsx
@@ -280,12 +280,7 @@ const page: React.FC = () => {
-
+
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 19150605..487f4f39 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -17,6 +17,7 @@ import { useKeepAwake } from "expo-keep-awake";
import { useSettings } from "@/utils/atoms/settings";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
+import { PlaybackProvider } from "@/providers/PlaybackProvider";
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
@@ -82,99 +83,101 @@ function Layout() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/CurrentlyPlayingBar.tsx b/components/CurrentlyPlayingBar.tsx
index 911cb81e..90b81c73 100644
--- a/components/CurrentlyPlayingBar.tsx
+++ b/components/CurrentlyPlayingBar.tsx
@@ -17,7 +17,14 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
import { BlurView } from "expo-blur";
import { useRouter, useSegments } from "expo-router";
import { useAtom } from "jotai";
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import {
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from "react";
import { Alert, Platform, TouchableOpacity, View } from "react-native";
import Animated, {
useAnimatedStyle,
@@ -27,22 +34,24 @@ import Animated, {
import Video, { OnProgressData, VideoRef } from "react-native-video";
import { Text } from "./common/Text";
import { Loader } from "./Loader";
+import { usePlayback } from "@/providers/PlaybackProvider";
export const CurrentlyPlayingBar: React.FC = () => {
const segments = useSegments();
- const queryClient = useQueryClient();
+ const {
+ currentlyPlaying,
+ pauseVideo,
+ playVideo,
+ setCurrentlyPlayingState,
+ stopVideo,
+ setIsPlaying,
+ isPlaying,
+ videoRef,
+ onProgress,
+ } = usePlayback();
const [api] = useAtom(apiAtom);
const [user] = useAtom(userAtom);
- const [playing, setPlaying] = useAtom(playingAtom);
- const [currentlyPlaying, setCurrentlyPlaying] = useAtom(
- currentlyPlayingItemAtom
- );
- const [fullScreen, setFullScreen] = useAtom(fullScreenAtom);
- const [show, setShow] = useAtom(showCurrentlyPlayingBarAtom);
-
- const videoRef = useRef(null);
- const [progress, setProgress] = useState(0);
const aBottom = useSharedValue(0);
const aPadding = useSharedValue(0);
@@ -90,124 +99,28 @@ export const CurrentlyPlayingBar: React.FC = () => {
}
}, [segments]);
- const { data: item } = useQuery({
- queryKey: ["item", currentlyPlaying?.item.Id],
- queryFn: async () =>
- await getUserItemData({
- api,
- userId: user?.Id,
- itemId: currentlyPlaying?.item.Id,
- }),
- enabled: !!currentlyPlaying?.item.Id && !!api,
- staleTime: 60,
- });
-
- const { data: sessionData } = useQuery({
- queryKey: ["sessionData", currentlyPlaying?.item.Id],
- queryFn: async () => {
- if (!currentlyPlaying?.item.Id) return null;
- const playbackData = await getMediaInfoApi(api!).getPlaybackInfo({
- itemId: currentlyPlaying?.item.Id,
- userId: user?.Id,
- });
- return playbackData.data;
- },
- enabled: !!currentlyPlaying?.item.Id && !!api && !!user?.Id,
- staleTime: 0,
- });
-
- const onProgress = useCallback(
- ({ currentTime }: OnProgressData) => {
- if (
- !sessionData?.PlaySessionId ||
- !api ||
- !currentlyPlaying?.item.Id ||
- !user?.Id ||
- !currentTime
- ) {
- return;
- }
- const newProgress = currentTime * 10000000;
- setProgress(newProgress);
-
- reportPlaybackProgress({
- api,
- itemId: currentlyPlaying?.item.Id,
- positionTicks: newProgress,
- sessionId: sessionData.PlaySessionId,
- IsPaused: !playing,
- });
-
- queryClient.invalidateQueries({
- queryKey: ["nextUp", item?.SeriesId],
- refetchType: "all",
- });
- queryClient.invalidateQueries({
- queryKey: ["episodes"],
- refetchType: "all",
- });
- },
- [sessionData?.PlaySessionId, api, playing, currentlyPlaying?.item.Id]
- );
-
- useEffect(() => {
- if (!item || !api) return;
-
- if (playing) {
- videoRef.current?.resume();
- } else {
- videoRef.current?.pause();
-
- queryClient.invalidateQueries({
- queryKey: ["nextUp", item?.SeriesId],
- refetchType: "all",
- });
- queryClient.invalidateQueries({
- queryKey: ["episodes"],
- refetchType: "all",
- });
- }
- }, [playing, progress, item, sessionData]);
-
- useEffect(() => {
- if (fullScreen === true) {
- videoRef.current?.presentFullscreenPlayer();
- } else {
- videoRef.current?.dismissFullscreenPlayer();
- }
- }, [fullScreen]);
-
- useEffect(() => {
- if (!show && currentlyPlaying && item && sessionData && api) {
- reportPlaybackStopped({
- api,
- itemId: item?.Id,
- sessionId: sessionData?.PlaySessionId,
- positionTicks: progress,
- });
- }
- }, [show]);
-
const startPosition = useMemo(
() =>
- item?.UserData?.PlaybackPositionTicks
- ? Math.round(item.UserData.PlaybackPositionTicks / 10000)
+ currentlyPlaying?.item?.UserData?.PlaybackPositionTicks
+ ? Math.round(
+ currentlyPlaying?.item.UserData.PlaybackPositionTicks / 10000
+ )
: 0,
- [item]
+ [currentlyPlaying?.item]
);
const backdropUrl = useMemo(
() =>
getBackdropUrl({
api,
- item,
+ item: currentlyPlaying?.item,
quality: 70,
width: 200,
}),
- [item]
+ [currentlyPlaying?.item, api]
);
- if (show === false || !api) return null;
+ if (!api || !currentlyPlaying) return null;
return (
{
videoRef.current?.presentFullscreenPlayer();
}}
className={`relative h-full bg-neutral-800 rounded-md overflow-hidden
- ${item?.Type === "Audio" ? "aspect-square" : "aspect-video"}
+ ${
+ currentlyPlaying.item?.Type === "Audio"
+ ? "aspect-square"
+ : "aspect-video"
+ }
`}
>
- {currentlyPlaying?.playbackUrl && (
+ {currentlyPlaying?.url && (