diff --git a/components/Player/component.tsx b/components/Player/component.tsx index 422cdba5..a92a1b20 100644 --- a/components/Player/component.tsx +++ b/components/Player/component.tsx @@ -9,20 +9,20 @@ import { ImageType } from "@jellyfin/sdk/lib/generated-client/models"; import { queryConfig } from "../../api/queries/query.config"; import { Text } from "../Global/helpers/text"; 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/helpers/slider"; +import PlayPauseButton from "./helpers/buttons"; export default function Player({ navigation }: { navigation : NavigationHelpers }): React.JSX.Element { const { apiClient } = useApiClientContext(); - const { queue, playbackState, nowPlaying, play, pause, progress } = usePlayerContext(); + const { queue, playbackState, nowPlaying, useTogglePlayback, progress } = usePlayerContext(); return ( { nowPlaying && ( - + @@ -45,7 +45,6 @@ export default function Player({ navigation }: { navigation : NavigationHelpers< @@ -63,14 +62,14 @@ export default function Player({ navigation }: { navigation : NavigationHelpers< {nowPlaying.artist ?? "Unknown Artist"} - + {/* Buttons for favorites, song menu go here */} - + {/* playback progress goes here */} - - {playPauseButton(playbackState, play, pause)} + + - + )} ); diff --git a/components/Player/helpers/buttons.tsx b/components/Player/helpers/buttons.tsx index df516ce7..2e3d8f0f 100644 --- a/components/Player/helpers/buttons.tsx +++ b/components/Player/helpers/buttons.tsx @@ -2,14 +2,17 @@ import { State } from "react-native-track-player"; import { Colors } from "react-native/Libraries/NewAppScreen"; import { Spinner } from "tamagui"; import Icon from "../../Global/helpers/icon"; +import { usePlayerContext } from "@/player/provider"; -export function playPauseButton(playbackState: State | undefined, play: Function, pause: Function) { +export default function PlayPauseButton() : React.JSX.Element { + + const { playbackState, useTogglePlayback } = usePlayerContext(); let button : React.JSX.Element; switch (playbackState) { case (State.Playing) : { - button = pause()} />; + button = useTogglePlayback.mutate(undefined)} />; break; } @@ -20,7 +23,7 @@ export function playPauseButton(playbackState: State | undefined, play: Function } default : { - button = play()} /> + button = useTogglePlayback.mutate(undefined)} /> break; } } diff --git a/components/Player/mini-player.tsx b/components/Player/mini-player.tsx index 2e098471..52cd794c 100644 --- a/components/Player/mini-player.tsx +++ b/components/Player/mini-player.tsx @@ -14,12 +14,12 @@ import { getImageApi } from "@jellyfin/sdk/lib/utils/api"; import { queryConfig } from "../../api/queries/query.config"; import { useApiClientContext } from "../jellyfin-api-provider"; import TextTicker from 'react-native-text-ticker'; -import { playPauseButton } from "./helpers/buttons"; +import PlayPauseButton from "./helpers/buttons"; import { skipToNext } from "react-native-track-player/lib/src/trackPlayer"; export function Miniplayer({ navigation }: { navigation : NavigationHelpers }) : React.JSX.Element { - const { nowPlaying, playbackState, play, pause } = usePlayerContext(); + const { nowPlaying } = usePlayerContext(); const { apiClient } = useApiClientContext(); @@ -77,7 +77,7 @@ export function Miniplayer({ navigation }: { navigation : NavigationHelpers - { playPauseButton(playbackState, play, pause) } + =0.60.0" + } + }, "node_modules/react-native-mmkv": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-2.12.2.tgz", diff --git a/package.json b/package.json index 5f12555c..3731096e 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react-native-device-info": "^11.1.0", "react-native-file-access": "^3.1.1", "react-native-gesture-handler": "^2.20.0", + "react-native-haptic-feedback": "^2.3.3", "react-native-mmkv": "2.12.2", "react-native-reanimated": "^3.16.3", "react-native-safe-area-context": "^4.11.1", diff --git a/player/provider.tsx b/player/provider.tsx index e7cc3674..579f85bd 100644 --- a/player/provider.tsx +++ b/player/provider.tsx @@ -16,6 +16,8 @@ import { useMutation, UseMutationResult } from "@tanstack/react-query"; import { QueueMutation } from "./interfaces"; import { mapDtoToTrack } from "@/helpers/mappings"; import { QueuingType } from "@/enums/queuing-type"; +import { trigger } from "react-native-haptic-feedback"; +import { pause } from "react-native-track-player/lib/src/trackPlayer"; interface PlayerContext { showPlayer: boolean; @@ -24,10 +26,7 @@ interface PlayerContext { setShowMiniplayer: React.Dispatch>; nowPlaying: JellifyTrack | undefined; queue: JellifyTrack[]; - play: (index?: number | undefined) => Promise, - pause: () => Promise, - resetQueue: (hideMiniplayer : boolean | undefined) => Promise; - addToQueue: (tracks: JellifyTrack[]) => Promise; + useTogglePlayback: UseMutationResult; playNewQueue: UseMutationResult; playbackState: State | undefined; progress: Progress | undefined; @@ -56,13 +55,6 @@ const PlayerContextInitializer = () => { TrackPlayer.skip(index) TrackPlayer.play(); - - handlePlaybackStarted(sessionId, playStateApi, nowPlaying!) - } - - const pause = async () => { - TrackPlayer.pause(); - handlePlaybackStopped(sessionId, playStateApi, nowPlaying!); } const resetQueue = async (hideMiniplayer?: boolean | undefined) => { @@ -86,8 +78,19 @@ const PlayerContextInitializer = () => { //#endregion Functions //#region Hooks + const useTogglePlayback = useMutation({ + mutationFn: async (index?: number | undefined) => { + trigger("impactLight"); + if (playbackState === State.Playing) + await pause(); + else + await play(index); + } + }) + const playNewQueue = useMutation({ mutationFn: async (mutation: QueueMutation) => { + trigger("impactLight"); await resetQueue(false) await addToQueue(mutation.tracklist.map((track) => { return mapDtoToTrack(apiClient!, sessionId, track, QueuingType.FromSelection) @@ -160,10 +163,7 @@ const PlayerContextInitializer = () => { setShowMiniplayer, nowPlaying, queue, - play, - pause, - addToQueue, - resetQueue, + useTogglePlayback, playNewQueue, playbackState, progress, @@ -171,6 +171,7 @@ const PlayerContextInitializer = () => { //#endregion return } +//#region Create PlayerContext export const PlayerContext = createContext({ showPlayer: false, setShowPlayer: () => {}, @@ -178,10 +179,24 @@ export const PlayerContext = createContext({ setShowMiniplayer: () => {}, nowPlaying: undefined, queue: [], - play: async (index?: number | undefined) => {}, - pause: async () => {}, - resetQueue: async () => {}, - addToQueue: async ([]) => {}, + useTogglePlayback: { + mutate: () => {}, + mutateAsync: async () => {}, + data: undefined, + error: null, + variables: undefined, + isError: false, + isIdle: true, + isPaused: false, + isPending: false, + isSuccess: false, + status: "idle", + reset: () => {}, + context: {}, + failureCount: 0, + failureReason: null, + submittedAt: 0 + }, playNewQueue: { mutate: () => {}, mutateAsync: async () => {}, @@ -203,6 +218,7 @@ export const PlayerContext = createContext({ playbackState: undefined, progress: undefined, }); +//#endregion Create PlayerContext export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JSX.Element = ({ children }: { children: ReactNode }) => { const { @@ -212,10 +228,7 @@ export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JS setShowMiniplayer, nowPlaying, queue, - play, - pause, - resetQueue, - addToQueue, + useTogglePlayback, playNewQueue, playbackState, progress @@ -228,10 +241,7 @@ export const PlayerProvider: ({ children }: { children: ReactNode }) => React.JS setShowMiniplayer, nowPlaying, queue, - play, - pause, - resetQueue, - addToQueue, + useTogglePlayback, playNewQueue, playbackState, progress