Adding scaffold for discover

adding slider

player component styling

wiring progess into player provider
This commit is contained in:
Violet Caulfield
2025-01-06 15:43:20 -06:00
parent a274b2082f
commit 36e4ec84f0
7 changed files with 97 additions and 21 deletions
+47 -4
View File
@@ -1,10 +1,35 @@
import React from "react";
import { Slider as TamaguiSlider } from "tamagui";
import { SliderProps as TamaguiSliderProps, SliderVerticalProps, Slider as TamaguiSlider } from "tamagui";
export default function Slider() : React.JSX.Element {
interface SliderProps {
value?: number | undefined;
max: number;
width?: number | undefined
props: TamaguiSliderProps
}
export function HorizontalSlider({
value,
max,
width,
props
}: {
value?: number | undefined,
max: number;
width?: number | undefined,
props?: TamaguiSliderProps | undefined
}) : React.JSX.Element {
return (
<TamaguiSlider size="$4" width={200} defaultValue={[50]} max={100} step={1}>
<TamaguiSlider
size="$4"
width={width}
value={value ? [value] : []}
max={max}
step={1}
orientation="horizontal"
{ ...props }
>
<TamaguiSlider.Track>
<TamaguiSlider.TrackActive />
</TamaguiSlider.Track>
@@ -12,4 +37,22 @@ export default function Slider() : React.JSX.Element {
</TamaguiSlider>
)
}
export function VerticalSlider(props: SliderVerticalProps) : React.JSX.Element {
return (
<TamaguiSlider
size="$4"
width={200}
defaultValue={[0]}
max={100}
step={1}
orientation="vertical"
>
<TamaguiSlider.Track>
<TamaguiSlider.TrackActive />
</TamaguiSlider.Track>
<TamaguiSlider.Thumb circular index={0} />
</TamaguiSlider>
)
}
+15 -6
View File
@@ -12,11 +12,12 @@ import { SafeAreaView } from "react-native-safe-area-context";
import { playPauseButton } from "./helpers/buttons";
import { BottomTabNavigationEventMap } from "@react-navigation/bottom-tabs";
import { NavigationHelpers, ParamListBase } from "@react-navigation/native";
import { HorizontalSlider } from "../Global/slider";
export default function Player({ navigation }: { navigation : NavigationHelpers<ParamListBase, BottomTabNavigationEventMap> }): React.JSX.Element {
const { apiClient } = useApiClientContext();
const { queue, playbackState, nowPlaying, play, pause } = usePlayerContext();
const { queue, playbackState, nowPlaying, play, pause, progress } = usePlayerContext();
return (
<SafeAreaView>
@@ -42,21 +43,23 @@ export default function Player({ navigation }: { navigation : NavigationHelpers<
/>
</XStack>
<XStack>
<XStack
alignContent="flex-start"
marginHorizontal={10}
>
<YStack alignContent="flex-start">
<Text>{nowPlaying?.title ?? "Untitled Track"}</Text>
<Text
bold
onPress={() => {
navigation.goBack();
navigation.navigate("Artist", {
artistName: nowPlaying?.artist,
artistId: nowPlaying?.ArtistId
artistName: nowPlaying.artist,
artistId: nowPlaying.ArtistId
})
}}
>
{nowPlaying?.artist ?? "Unknown Artist"}</Text>
{nowPlaying.artist ?? "Unknown Artist"}</Text>
</YStack>
<XStack>
@@ -68,6 +71,12 @@ export default function Player({ navigation }: { navigation : NavigationHelpers<
<XStack>
{/* playback progress goes here */}
<HorizontalSlider
value={progress!.position}
max={progress!.duration}
width={400}
/>
</XStack>
<XStack>
+1
View File
@@ -0,0 +1 @@
export const UPDATE_INTERVAL: number = 500
+16
View File
@@ -4,6 +4,22 @@ import { useQuery } from "@tanstack/react-query";
import { QueryKeys } from "../enums/query-keys";
import { PlaystateApi } from "@jellyfin/sdk/lib/generated-client/api/playstate-api";
export const usePlaybackStopped = (sessionId: string, playStateApi: PlaystateApi, activeTrack: JellifyTrack) => useQuery({
queryKey: [QueryKeys.ReportPlaybackStopped, sessionId, activeTrack, playStateApi],
queryFn: async ({ queryKey }) => {
const sessionId: string = queryKey[1] as string;
const activeTrack : JellifyTrack = queryKey[2] as JellifyTrack;
const playStateApi : PlaystateApi = queryKey[3] as PlaystateApi;
return await playStateApi.reportPlaybackStopped({
playbackStopInfo: {
SessionId: sessionId,
ItemId: activeTrack.ItemId
}
})
}
})
export const handlePlaybackStateChange = (state: State, sessionId: string, playStateApi: PlaystateApi, activeTrack: JellifyTrack) => useQuery({
queryKey: [QueryKeys.PlaybackStateChange, state, sessionId, activeTrack, playStateApi],
queryFn: async ({ queryKey }) => {
+18 -11
View File
@@ -3,14 +3,15 @@ import { JellifyTrack } from "../types/JellifyTrack";
import { storage } from "../constants/storage";
import { MMKVStorageKeys } from "../enums/mmkv-storage-keys";
import { findPlayQueueIndexStart } from "./helpers/index";
import TrackPlayer, { Event, State, usePlaybackState, useTrackPlayerEvents } from "react-native-track-player";
import TrackPlayer, { Event, Progress, State, useActiveTrack, usePlaybackState, useProgress, useTrackPlayerEvents } from "react-native-track-player";
import _ from "lodash";
import { buildNewQueue } from "./helpers/queue";
import { useApiClientContext } from "../components/jellyfin-api-provider";
import { getPlaystateApi } from "@jellyfin/sdk/lib/utils/api";
import { handlePlaybackStateChange } from "./handlers";
import { handlePlaybackStateChange, usePlaybackStopped } from "./handlers";
import { sleep } from "@/helpers/sleep";
import { useSetupPlayer } from "@/components/Player/hooks";
import { UPDATE_INTERVAL } from "./config";
interface PlayerContext {
showPlayer: boolean;
@@ -24,6 +25,7 @@ interface PlayerContext {
resetQueue: (hideMiniplayer : boolean | undefined) => Promise<void>;
addToQueue: (tracks: JellifyTrack[]) => Promise<void>;
playbackState: State | undefined;
progress: Progress | undefined;
}
const PlayerContextInitializer = () => {
@@ -97,6 +99,7 @@ const PlayerContextInitializer = () => {
useTrackPlayerEvents([
Event.PlaybackState,
Event.PlaybackProgressUpdated,
Event.PlaybackActiveTrackChanged,
], async (event) => {
@@ -111,17 +114,16 @@ const PlayerContextInitializer = () => {
case (Event.PlaybackActiveTrackChanged) : {
// Scrobble previously played track
if (nowPlaying) {
playStateApi.reportPlaybackStopped({
playbackStopInfo: {
SessionId: sessionId,
ItemId: nowPlaying.ItemId
}
})
usePlaybackStopped(sessionId, playStateApi, nowPlaying)
}
console.debug("Active track changed")
const activeTrack = await sleep(500).then(async () => {
console.debug("Active track changed");
// Sleep before capturing the active track in case we are
// skipping to an initial queue index
const activeTrack = await sleep(250).then(async () => {
return await TrackPlayer.getActiveTrack()
}) as JellifyTrack;
@@ -131,7 +133,8 @@ const PlayerContextInitializer = () => {
}
})
const { state: playbackState } = usePlaybackState()
const { state: playbackState } = usePlaybackState();
const progress = useProgress(UPDATE_INTERVAL);
useEffect(() => {
if (!showMiniplayer)
@@ -163,6 +166,7 @@ const PlayerContextInitializer = () => {
addToQueue,
resetQueue,
playbackState,
progress,
}
//#endregion return
}
@@ -179,6 +183,7 @@ export const PlayerContext = createContext<PlayerContext>({
resetQueue: async () => {},
addToQueue: async ([]) => {},
playbackState: undefined,
progress: undefined,
});
export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JSX.Element = ({ children }: { children: ReactNode }) => {
@@ -194,6 +199,7 @@ export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JS
resetQueue,
addToQueue,
playbackState,
progress
} = PlayerContextInitializer();
return <PlayerContext.Provider value={{
@@ -208,6 +214,7 @@ export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JS
resetQueue,
addToQueue,
playbackState,
progress
}}>
{ children }
</PlayerContext.Provider>