mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
refactor(queue): co-locate QueuePanel UI into features/queue
Extract the queue UI (QueuePanel + queuePanel/* components + useQueue* hooks)
into features/queue/ with a barrel. This is the chosen playback/queue boundary:
queue = the QueuePanel UI that CONSUMES the playback store; queue STATE and the
audio engine stay in store/ (playback-core, moved separately). Verified
one-way: no playback-core file imports the queue UI back (only doc comments
mention it).
Excluded as NOT queue-UI: useIdlePlayQueuePull (AppShell) and
usePlayQueueSyncLedState (ConnectionIndicator) are queue-SYNC orchestration,
not panel UI — left in hooks/ to move with playback.
Pure move. One test fix: QueuePanel.test.tsx reads its subject via a hardcoded
readFileSync('src/components/QueuePanel.tsx') path (architecture-pin grep for
forbidden HTML5 DnD) — repointed to the new location (the move tool can't
rewrite non-import string paths). tsc 0, lint 0/0, suite 319/2353 green.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { useMemo, useSyncExternalStore } from 'react';
|
||||
import { usePlayerStore } from '@/store/playerStore';
|
||||
import type { QueueItemRef, Track } from '@/store/playerStoreTypes';
|
||||
import { resolveQueueTrack } from '@/utils/library/queueTrackView';
|
||||
import {
|
||||
getQueueResolverVersion,
|
||||
subscribeQueueResolver,
|
||||
} from '@/utils/library/queueTrackResolver';
|
||||
|
||||
/**
|
||||
* Stable queue selectors (queue thin-state). The store is refs-canonical now:
|
||||
* full `Track`s come from the resolver cache (placeholder until a fetch lands),
|
||||
* with session star/rating overrides (F4) merged on read via resolveQueueTrack.
|
||||
*/
|
||||
|
||||
/** The track at a queue index, or null. */
|
||||
export function useQueueTrackAt(idx: number): Track | null {
|
||||
const ref = usePlayerStore(s => s.queueItems[idx] ?? null);
|
||||
const starredOverrides = usePlayerStore(s => s.starredOverrides);
|
||||
const userRatingOverrides = usePlayerStore(s => s.userRatingOverrides);
|
||||
const version = useSyncExternalStore(subscribeQueueResolver, getQueueResolverVersion);
|
||||
return useMemo(() => {
|
||||
if (!ref) return null;
|
||||
return resolveQueueTrack(ref);
|
||||
// version drives re-resolution as the cache fills; overrides drive the merge.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [ref, starredOverrides, userRatingOverrides, version]);
|
||||
}
|
||||
|
||||
/** The currently playing track, or null. */
|
||||
export function useCurrentTrack(): Track | null {
|
||||
return usePlayerStore(s => s.currentTrack);
|
||||
}
|
||||
|
||||
/** The whole queue as thin refs (the canonical list). */
|
||||
export function useQueueItems(): QueueItemRef[] {
|
||||
return usePlayerStore(s => s.queueItems);
|
||||
}
|
||||
Reference in New Issue
Block a user