mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
7e9cb60763
Move the Subsonic + Navidrome protocol clients and the library IPC facade (subsonic*, navidrome*, library.ts + tests) from src/api/ into src/lib/api/, the feature-free infra layer (plan M4, decision §10.3: shared client core → lib/). Pure move: deep-path import specifiers @/api/* -> @/lib/api/* across ~150 consumers; no behaviour change. Domain REST (lyrics/events) and cover/analysis infra stay in src/api/ pending their own M4 placement. tsc 0, lint 0/0, full suite 319 files / 2353 tests green.
48 lines
1.9 KiB
TypeScript
48 lines
1.9 KiB
TypeScript
import type React from 'react';
|
|
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
|
|
import { songToTrack } from '@/utils/playback/songToTrack';
|
|
|
|
export interface StartPlaylistRowDragDeps {
|
|
e: React.MouseEvent;
|
|
idx: number;
|
|
songs: SubsonicSong[];
|
|
selectedIds: Set<string>;
|
|
isFiltered: boolean;
|
|
startDrag: (payload: { data: string; label: string }, x: number, y: number) => void;
|
|
}
|
|
|
|
export function startPlaylistRowDrag(deps: StartPlaylistRowDragDeps): void {
|
|
const { e, idx, songs, selectedIds, isFiltered, startDrag } = deps;
|
|
if (e.button !== 0) return;
|
|
if ((e.target as HTMLElement).closest('button, input')) return;
|
|
e.preventDefault();
|
|
const sx = e.clientX, sy = e.clientY;
|
|
const onMove = (me: MouseEvent) => {
|
|
if (Math.abs(me.clientX - sx) > 5 || Math.abs(me.clientY - sy) > 5) {
|
|
document.removeEventListener('mousemove', onMove);
|
|
document.removeEventListener('mouseup', onUp);
|
|
if (!isFiltered && selectedIds.has(songs[idx]?.id) && selectedIds.size > 1) {
|
|
const bulkTracks = songs.filter(s => selectedIds.has(s.id)).map(songToTrack);
|
|
startDrag({ data: JSON.stringify({ type: 'songs', tracks: bulkTracks }), label: `${bulkTracks.length} Songs` }, me.clientX, me.clientY);
|
|
} else if (!isFiltered) {
|
|
startDrag(
|
|
{ data: JSON.stringify({ type: 'playlist_reorder', index: idx }), label: songs[idx]?.title ?? '' },
|
|
me.clientX, me.clientY
|
|
);
|
|
} else {
|
|
// filtered view: single-song drag to queue
|
|
startDrag(
|
|
{ data: JSON.stringify({ type: 'song', track: songToTrack(songs[idx]) }), label: songs[idx]?.title ?? '' },
|
|
me.clientX, me.clientY
|
|
);
|
|
}
|
|
}
|
|
};
|
|
const onUp = () => {
|
|
document.removeEventListener('mousemove', onMove);
|
|
document.removeEventListener('mouseup', onUp);
|
|
};
|
|
document.addEventListener('mousemove', onMove);
|
|
document.addEventListener('mouseup', onUp);
|
|
}
|