From 9f0a8f2bae81601e12f1ff8a00c164a5ac9f6dfe Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sun, 2 Nov 2025 19:40:42 -0800 Subject: [PATCH] begin implementing player context --- .../features/player/components/playerbar.tsx | 2 +- .../player/context/player-context.tsx | 177 +++++++++++++----- src/renderer/store/player.store.ts | 31 +-- src/renderer/store/settings.store.ts | 7 - 4 files changed, 148 insertions(+), 69 deletions(-) diff --git a/src/renderer/features/player/components/playerbar.tsx b/src/renderer/features/player/components/playerbar.tsx index baa879c9b..155dc3b51 100644 --- a/src/renderer/features/player/components/playerbar.tsx +++ b/src/renderer/features/player/components/playerbar.tsx @@ -3,7 +3,7 @@ import { MouseEvent } from 'react'; import styles from './playerbar.module.css'; -import { AudioPlayer } from '/@/renderer/components/audio-player'; +import { AudioPlayer } from '/@/renderer/features/player/audio-player'; import { CenterControls } from '/@/renderer/features/player/components/center-controls'; import { LeftControls } from '/@/renderer/features/player/components/left-controls'; import { RightControls } from '/@/renderer/features/player/components/right-controls'; diff --git a/src/renderer/features/player/context/player-context.tsx b/src/renderer/features/player/context/player-context.tsx index 5d7fe1ae0..d65566b48 100644 --- a/src/renderer/features/player/context/player-context.tsx +++ b/src/renderer/features/player/context/player-context.tsx @@ -1,7 +1,8 @@ import { createContext, useCallback, useMemo } from 'react'; -import { AddToQueueType } from '/@/renderer/store'; +import { AddToQueueType, usePlayerActions } from '/@/renderer/store'; import { LibraryItem, QueueSong, Song } from '/@/shared/types/domain-types'; +import { Play } from '/@/shared/types/types'; interface PlayerContext { addToQueueByData: (data: Song[], type: AddToQueueType) => void; @@ -12,11 +13,11 @@ interface PlayerContext { increaseVolume: (amount: number) => void; mediaNext: () => void; mediaPause: () => void; - mediaPlay: (id: string) => void; + mediaPlay: (id?: string) => void; mediaPrevious: () => void; mediaSeekToTimestamp: (timestamp: number) => void; - mediaStepBackward: () => void; - mediaStepForward: () => void; + mediaSkipBackward: () => void; + mediaSkipForward: () => void; mediaToggleMute: () => void; mediaTogglePlayPause: () => void; moveSelectedTo: (items: QueueSong[], edge: 'bottom' | 'top', uniqueId: string) => void; @@ -41,8 +42,8 @@ export const PlayerContext = createContext({ mediaPlay: () => {}, mediaPrevious: () => {}, mediaSeekToTimestamp: () => {}, - mediaStepBackward: () => {}, - mediaStepForward: () => {}, + mediaSkipBackward: () => {}, + mediaSkipForward: () => {}, mediaToggleMute: () => {}, mediaTogglePlayPause: () => {}, moveSelectedTo: () => {}, @@ -56,56 +57,140 @@ export const PlayerContext = createContext({ }); export const PlayerProvider = ({ children }: { children: React.ReactNode }) => { - const addToQueueByData = useCallback((data: Song[], type: AddToQueueType) => {}, []); + const storeActions = usePlayerActions(); + + const addToQueueByData = useCallback( + (data: Song[], type: AddToQueueType) => { + if (typeof type === 'object' && 'edge' in type && type.edge !== null) { + const edge = type.edge === 'top' ? 'top' : 'bottom'; + storeActions.addToQueueByUniqueId(data, type.uniqueId, edge); + } else { + storeActions.addToQueueByType(data, type as Play); + } + }, + [storeActions], + ); const addToQueueByFetch = useCallback( (id: string[], itemType: LibraryItem, type: AddToQueueType) => {}, [], ); - const clearQueue = useCallback(() => {}, []); + const clearQueue = useCallback(() => { + storeActions.clearQueue(); + }, [storeActions]); - const clearSelected = useCallback((items: QueueSong[]) => {}, []); - - const decreaseVolume = useCallback((amount: number) => {}, []); - - const increaseVolume = useCallback((amount: number) => {}, []); - - const mediaNext = useCallback(() => {}, []); - - const mediaPause = useCallback(() => {}, []); - - const mediaPlay = useCallback((id: string) => {}, []); - - const mediaPrevious = useCallback(() => {}, []); - - const mediaSeekToTimestamp = useCallback((timestamp: number) => {}, []); - - const mediaStepBackward = useCallback(() => {}, []); - - const mediaStepForward = useCallback(() => {}, []); - - const mediaToggleMute = useCallback(() => {}, []); - - const mediaTogglePlayPause = useCallback(() => {}, []); - - const moveSelectedTo = useCallback( - (items: QueueSong[], edge: 'bottom' | 'top', uniqueId: string) => {}, - [], + const clearSelected = useCallback( + (items: QueueSong[]) => { + storeActions.clearSelected(items); + }, + [storeActions], ); - const moveSelectedToBottom = useCallback((items: QueueSong[]) => {}, []); + const decreaseVolume = useCallback( + (amount: number) => { + storeActions.decreaseVolume(amount); + }, + [storeActions], + ); - const moveSelectedToNext = useCallback((items: QueueSong[]) => {}, []); + const increaseVolume = useCallback( + (amount: number) => { + storeActions.increaseVolume(amount); + }, + [storeActions], + ); - const moveSelectedToTop = useCallback((items: QueueSong[]) => {}, []); + const mediaNext = useCallback(() => { + storeActions.mediaNext(); + }, [storeActions]); - const setVolume = useCallback((volume: number) => {}, []); + const mediaPause = useCallback(() => { + storeActions.mediaPause(); + }, [storeActions]); - const shuffle = useCallback(() => {}, []); + const mediaPlay = useCallback( + (id?: string) => { + storeActions.mediaPlay(id); + }, + [storeActions], + ); - const shuffleAll = useCallback(() => {}, []); + const mediaPrevious = useCallback(() => { + storeActions.mediaPrevious(); + }, [storeActions]); - const shuffleSelected = useCallback((items: QueueSong[]) => {}, []); + const mediaSeekToTimestamp = useCallback( + (timestamp: number) => { + storeActions.mediaSeekToTimestamp(timestamp); + }, + [storeActions], + ); + + const mediaSkipBackward = useCallback(() => { + storeActions.mediaSkipBackward(); + }, [storeActions]); + + const mediaSkipForward = useCallback(() => { + storeActions.mediaSkipForward(); + }, [storeActions]); + + const mediaToggleMute = useCallback(() => { + storeActions.mediaToggleMute(); + }, [storeActions]); + + const mediaTogglePlayPause = useCallback(() => { + storeActions.mediaTogglePlayPause(); + }, [storeActions]); + + const moveSelectedTo = useCallback( + (items: QueueSong[], edge: 'bottom' | 'top', uniqueId: string) => { + storeActions.moveSelectedTo(items, uniqueId, edge); + }, + [storeActions], + ); + + const moveSelectedToBottom = useCallback( + (items: QueueSong[]) => { + storeActions.moveSelectedToBottom(items); + }, + [storeActions], + ); + + const moveSelectedToNext = useCallback( + (items: QueueSong[]) => { + storeActions.moveSelectedToNext(items); + }, + [storeActions], + ); + + const moveSelectedToTop = useCallback( + (items: QueueSong[]) => { + storeActions.moveSelectedToTop(items); + }, + [storeActions], + ); + + const setVolume = useCallback( + (volume: number) => { + storeActions.setVolume(volume); + }, + [storeActions], + ); + + const shuffle = useCallback(() => { + storeActions.shuffle(); + }, [storeActions]); + + const shuffleAll = useCallback(() => { + storeActions.shuffleAll(); + }, [storeActions]); + + const shuffleSelected = useCallback( + (items: QueueSong[]) => { + storeActions.shuffleSelected(items); + }, + [storeActions], + ); const contextValue: PlayerContext = useMemo( () => ({ @@ -120,8 +205,8 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => { mediaPlay, mediaPrevious, mediaSeekToTimestamp, - mediaStepBackward, - mediaStepForward, + mediaSkipBackward, + mediaSkipForward, mediaToggleMute, mediaTogglePlayPause, moveSelectedTo, @@ -145,8 +230,8 @@ export const PlayerProvider = ({ children }: { children: React.ReactNode }) => { mediaPlay, mediaPrevious, mediaSeekToTimestamp, - mediaStepBackward, - mediaStepForward, + mediaSkipBackward, + mediaSkipForward, mediaToggleMute, mediaTogglePlayPause, moveSelectedTo, diff --git a/src/renderer/store/player.store.ts b/src/renderer/store/player.store.ts index e9d2ac070..d32c55b42 100644 --- a/src/renderer/store/player.store.ts +++ b/src/renderer/store/player.store.ts @@ -8,6 +8,7 @@ import { immer } from 'zustand/middleware/immer'; import { useShallow } from 'zustand/react/shallow'; import { createSelectors } from '/@/renderer/lib/zustand'; +import { useSettingsStore } from '/@/renderer/store/settings.store'; import { shuffleInPlace } from '/@/renderer/utils/shuffle'; import { QueueSong, Song } from '/@/shared/types/domain-types'; import { @@ -67,8 +68,8 @@ interface Actions { mediaPlay: (id?: string) => void; mediaPrevious: () => void; mediaSeekToTimestamp: (timestamp: number) => void; - mediaStepBackward: () => void; - mediaStepForward: () => void; + mediaSkipBackward: () => void; + mediaSkipForward: () => void; mediaToggleMute: () => void; mediaTogglePlayPause: () => void; moveSelectedTo: (items: QueueSong[], uniqueId: string, edge: 'bottom' | 'top') => void; @@ -105,8 +106,6 @@ interface State { shuffle: PlayerShuffle; speed: number; status: PlayerStatus; - stepBackward: number; - stepForward: number; timestamp: number; transitionType: PlayerStyle; volume: number; @@ -570,22 +569,24 @@ export const usePlayerStoreBase = create()( state.player.seekToTimestamp = uniqueSeekToTimestamp(timestamp); }); }, - mediaStepBackward: () => { + mediaSkipBackward: () => { set((state) => { - const newTimestamp = Math.max( - 0, - state.player.timestamp - state.player.stepBackward, - ); + const timeToSkip = + useSettingsStore.getState().general.skipButtons.skipBackwardSeconds || + 5; + const newTimestamp = Math.max(0, state.player.timestamp - timeToSkip); state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp); }); }, - mediaStepForward: () => { + mediaSkipForward: () => { set((state) => { const queue = state.getQueue(); const index = state.player.index; const currentTrack = queue.items[index]; const duration = currentTrack?.duration; + const timeToSkip = + useSettingsStore.getState().general.skipButtons.skipForwardSeconds || 5; if (!duration) { return; @@ -593,7 +594,7 @@ export const usePlayerStoreBase = create()( const newTimestamp = Math.min( duration - 1, - state.player.timestamp + state.player.stepForward, + state.player.timestamp + timeToSkip, ); state.player.seekToTimestamp = uniqueSeekToTimestamp(newTimestamp); @@ -872,12 +873,12 @@ export const usePlayerStoreBase = create()( playerNum: 1, queueType: PlayerQueueType.DEFAULT, repeat: PlayerRepeat.NONE, + seekBackward: 10, + seekForward: 10, seekToTimestamp: uniqueSeekToTimestamp(0), shuffle: PlayerShuffle.NONE, speed: 1, status: PlayerStatus.PAUSED, - stepBackward: 10, - stepForward: 10, timestamp: 0, transitionType: PlayerStyle.GAPLESS, volume: 30, @@ -1005,8 +1006,8 @@ export const usePlayerActions = () => { mediaPlay: state.mediaPlay, mediaPrevious: state.mediaPrevious, mediaSeekToTimestamp: state.mediaSeekToTimestamp, - mediaStepBackward: state.mediaStepBackward, - mediaStepForward: state.mediaStepForward, + mediaSkipBackward: state.mediaSkipBackward, + mediaSkipForward: state.mediaSkipForward, mediaToggleMute: state.mediaToggleMute, mediaTogglePlayPause: state.mediaTogglePlayPause, moveSelectedTo: state.moveSelectedTo, diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts index 676c39573..64e959a18 100644 --- a/src/renderer/store/settings.store.ts +++ b/src/renderer/store/settings.store.ts @@ -9,7 +9,6 @@ import { createWithEqualityFn } from 'zustand/traditional'; import i18n from '/@/i18n/i18n'; import { ContextMenuItemType } from '/@/renderer/features/context-menu/events'; import { AppRoute } from '/@/renderer/router/routes'; -import { usePlayerStore } from '/@/renderer/store/player.store'; import { mergeOverridingColumns } from '/@/renderer/store/utils'; import { FontValueSchema } from '/@/renderer/types/fonts'; import { randomString } from '/@/renderer/utils'; @@ -967,12 +966,6 @@ export const useGeneralSettings = () => useSettingsStore((state) => state.genera export const usePlaybackType = () => useSettingsStore((state) => { - const isFallback = usePlayerStore.getState().fallback; - - if (isFallback) { - return PlayerType.WEB; - } - return state.playback.type; });