mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
b0418bf920
Two small file-private bits move out of playerStore.ts:
- `src/store/queueVisibilityStorage.ts` — `readInitialQueueVisibility`
and `persistQueueVisibility` (the QueuePanel show/hide toggle
survives reloads via a localStorage round-trip; SSR / private-mode
failures swallowed silently).
- `src/store/queueUndoHotkey.ts` — `installQueueUndoHotkey` (Ctrl+Z /
Cmd+Z queue undo, Ctrl+Shift+Z redo, document-capture; skips text
fields so native text undo stays; idempotent via window-scoped
flag; mini-player window skipped). Added a `_resetQueueUndoHotkeyForTest`
that removes the keydown listener too (needed so vitest specs
don't accumulate handlers across tests).
playerStore re-exports `installQueueUndoHotkey` so bootstrap + tests
keep their existing `from './playerStore'` imports. The
queue-visibility helpers were file-private; no re-exports.
Side-cleanup: `getWindowKind` import is gone from playerStore (only
the moved hotkey installer used it).
16 focused tests pin the storage round-trip, the idempotency flag, the
modifier + key matching, the editable-target skip, and the
preventDefault contract.
playerStore 1940 → 1879 LOC.
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import { getWindowKind } from '../app/windowKind';
|
|
import { usePlayerStore } from './playerStore';
|
|
|
|
const QUEUE_UNDO_HOTKEY_FLAG = '__psyQueueUndoListenerInstalled';
|
|
|
|
/** True when the event path includes a real text field — skip queue undo so Ctrl+Z stays native there. */
|
|
function keyboardEventTargetIsEditableField(e: KeyboardEvent): boolean {
|
|
for (const n of e.composedPath()) {
|
|
if (!(n instanceof HTMLElement)) continue;
|
|
const tag = n.tagName;
|
|
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;
|
|
if (n.isContentEditable) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
let installedHandler: ((e: KeyboardEvent) => void) | null = null;
|
|
|
|
/**
|
|
* Ctrl+Z / Cmd+Z undo and Ctrl+Shift+Z / Cmd+Shift+Z redo for the queue —
|
|
* document capture. Call once at startup (e.g. from bootstrap.ts);
|
|
* idempotent via the window-scoped flag. Skips the mini-player window so
|
|
* the host renderer owns queue history.
|
|
*/
|
|
export function installQueueUndoHotkey(): void {
|
|
if (typeof window === 'undefined') return;
|
|
const w = window as unknown as Record<string, unknown>;
|
|
if (w[QUEUE_UNDO_HOTKEY_FLAG]) return;
|
|
if (getWindowKind() === 'mini') return;
|
|
w[QUEUE_UNDO_HOTKEY_FLAG] = true;
|
|
const handler = (e: KeyboardEvent) => {
|
|
if (!(e.ctrlKey || e.metaKey)) return;
|
|
if (e.code !== 'KeyZ' && String(e.key || '').toLowerCase() !== 'z') return;
|
|
if (keyboardEventTargetIsEditableField(e)) return;
|
|
|
|
if (e.shiftKey) {
|
|
if (usePlayerStore.getState().redoLastQueueEdit()) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (usePlayerStore.getState().undoLastQueueEdit()) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
};
|
|
installedHandler = handler;
|
|
document.addEventListener('keydown', handler, true);
|
|
}
|
|
|
|
/** Test-only: remove the installed listener and clear the install flag. */
|
|
export function _resetQueueUndoHotkeyForTest(): void {
|
|
if (typeof window === 'undefined') return;
|
|
if (installedHandler) {
|
|
document.removeEventListener('keydown', installedHandler, true);
|
|
installedHandler = null;
|
|
}
|
|
const w = window as unknown as Record<string, unknown>;
|
|
w[QUEUE_UNDO_HOTKEY_FLAG] = undefined;
|
|
}
|