mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-21 23:05:46 +00:00
refactor(mini-player): H6 — split MiniPlayer.tsx 820 → 218 LOC across 11 files (#669)
* refactor(mini-player): H6 — extract helpers + constants
Pure code-move: window-size constants, localStorage keys + read helpers,
toMini track shape, initialSnapshot, and fmt(seconds) → utils/miniPlayerHelpers.ts.
MiniPlayer.tsx: 820 → 745 LOC.
* refactor(mini-player): H6 — extract MiniTitlebar + MiniMeta + MiniControls
Three small visual subcomponents move into components/miniPlayer/.
MiniPlayer drops the now-unused Pin/PinOff/Maximize2/X/Play/Pause/
SkipBack/SkipForward lucide icons and the CachedImage import.
MiniPlayer.tsx: 745 → 665 LOC.
* refactor(mini-player): H6 — extract MiniToolbar + useMiniVolumePopover
The whole toolbar (volume button + portaled popover, shuffle, gapless/
crossfade/infinite, queue toggle) moves into MiniToolbar.tsx. The volume
popover open-state + ref/style positioning + outside-click/Escape close
move into the useMiniVolumePopover hook.
MiniPlayer.tsx: 665 → 492 LOC.
* refactor(mini-player): H6 — extract MiniQueue + useMiniQueueDrag
The OverlayScrollArea + queue.map block moves into MiniQueue.tsx. The
PsyDnD wiring (drop-inside emits mini:reorder, drop-outside emits
mini:remove, reorder math collapsing same-position + adjusting for shift)
moves into the useMiniQueueDrag hook.
MiniPlayer.tsx: 492 → 346 LOC.
* refactor(mini-player): H6 — extract useMiniSync + useMiniWindowSetup + useMiniKeyboardShortcuts
Three more hooks pull the remaining side-effect islands out of MiniPlayer:
- useMiniSync owns mini:ready emit on mount + focus, plus the
mini:sync / audio:progress / audio:ended listeners. The hidden-window
visibility ref that gates progress now lives inside the hook.
- useMiniWindowSetup bundles three small window-bound effects:
Linux WebKitGTK smooth-scroll, the cold-start expanded-size restore
when queueOpen=true, and always-on-top reapply on mount + focus.
- useMiniKeyboardShortcuts moves the keyboard-shortcut bridge wiring.
MiniPlayer.tsx: 346 → 218 LOC.
This commit is contained in:
committed by
GitHub
parent
463d3e0c5b
commit
383bbbd75f
@@ -0,0 +1,82 @@
|
||||
import { usePlayerStore } from '../store/playerStore';
|
||||
import type { MiniSyncPayload, MiniTrackInfo } from './miniPlayerBridge';
|
||||
|
||||
export const COLLAPSED_SIZE = { w: 340, h: 260 };
|
||||
export const EXPANDED_SIZE = { w: 340, h: 500 };
|
||||
// Minimum window dimensions per state. When the queue is open the floor must
|
||||
// keep at least two queue rows visible; a stricter min would let the user
|
||||
// collapse the queue area to nothing while it's still toggled on.
|
||||
export const COLLAPSED_MIN = { w: 320, h: 240 };
|
||||
export const EXPANDED_MIN = { w: 320, h: 340 };
|
||||
|
||||
// Persist the expanded-window height so reopening the queue restores the
|
||||
// user's preferred size instead of snapping back to EXPANDED_SIZE.h.
|
||||
export const EXPANDED_H_KEY = 'psysonic_mini_expanded_h';
|
||||
export function readStoredExpandedHeight(): number {
|
||||
try {
|
||||
const raw = localStorage.getItem(EXPANDED_H_KEY);
|
||||
if (raw) {
|
||||
const n = parseInt(raw, 10);
|
||||
if (Number.isFinite(n) && n >= EXPANDED_MIN.h) return n;
|
||||
}
|
||||
} catch {}
|
||||
return EXPANDED_SIZE.h;
|
||||
}
|
||||
|
||||
// Persist whether the queue panel was open so the next launch restores
|
||||
// the same state. Same scope as the height: localStorage of the mini
|
||||
// webview (shared across mini sessions, separate from the main store).
|
||||
export const QUEUE_OPEN_KEY = 'psysonic_mini_queue_open';
|
||||
export function readQueueOpen(): boolean {
|
||||
try { return localStorage.getItem(QUEUE_OPEN_KEY) === '1'; } catch { return false; }
|
||||
}
|
||||
|
||||
export function toMini(t: any): MiniTrackInfo {
|
||||
return {
|
||||
id: t.id,
|
||||
title: t.title,
|
||||
artist: t.artist,
|
||||
album: t.album,
|
||||
albumId: t.albumId,
|
||||
artistId: t.artistId,
|
||||
coverArt: t.coverArt,
|
||||
duration: t.duration,
|
||||
starred: !!t.starred,
|
||||
year: t.year,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate from the persisted playerStore so initial paint shows real content
|
||||
* instead of "—" while we wait for the mini:sync event from the main window.
|
||||
* The persisted state covers the cold-start window (webview boot + bundle).
|
||||
*/
|
||||
export function initialSnapshot(): MiniSyncPayload {
|
||||
try {
|
||||
const s = usePlayerStore.getState();
|
||||
return {
|
||||
track: s.currentTrack ? toMini(s.currentTrack) : null,
|
||||
queue: (s.queue ?? []).map(toMini),
|
||||
queueIndex: s.queueIndex ?? 0,
|
||||
isPlaying: s.isPlaying,
|
||||
volume: s.volume ?? 1,
|
||||
gaplessEnabled: false,
|
||||
crossfadeEnabled: false,
|
||||
infiniteQueueEnabled: false,
|
||||
isMobile: false,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
track: null, queue: [], queueIndex: 0, isPlaying: false,
|
||||
volume: 1, gaplessEnabled: false, crossfadeEnabled: false,
|
||||
infiniteQueueEnabled: false, isMobile: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function fmt(seconds: number): string {
|
||||
if (!isFinite(seconds) || seconds < 0) seconds = 0;
|
||||
const m = Math.floor(seconds / 60);
|
||||
const s = Math.floor(seconds % 60);
|
||||
return `${m}:${s.toString().padStart(2, '0')}`;
|
||||
}
|
||||
Reference in New Issue
Block a user