mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 06:25:41 +00:00
feat: queue-ux-improvements (#419)
* feat(queue): add ETA display, equalizer indicator and collapsible now playing
* deleted endsAt and showDuration strings, changed eta update to 30s
* feat(queue): ETA tooltip, persistent Now Playing collapse, EQ bar pause, remove redundant Play icon
* feat(queue): fold ETA into existing total/remaining toggle as third mode
The standalone ETA span next to the track counter is removed; instead the
clickable duration label in the queue header now rotates through three
modes per click: total → remaining → eta → total. Counter (N/M) stays
where it was.
ETA mode keeps the live-feel treatment from the original PR (accent
colour while playing, muted at 50% opacity when paused). The other two
modes use plain accent.
i18n: queue.etaTooltip removed (no longer a separate descriptive label),
queue.showEta added as the action tooltip ('Show estimated end time')
in all 8 locales — matches the showRemaining / showTotal pattern.
* docs(changelog): add #419 queue UX improvements entry
Adds the [1.45.0] / Added entry for this PR's queue panel refinements
(position counter, tri-state duration toggle including ETA, collapsible
Now Playing section, animated EQ indicator).
---------
Co-authored-by: Psychotoxical <171614930+Psychotoxical@users.noreply.github.com>
This commit is contained in:
@@ -21,15 +21,6 @@ interface PreviewState {
|
||||
elapsed: number;
|
||||
/** Total preview window in seconds (echoes the duration_sec arg). */
|
||||
duration: number;
|
||||
/**
|
||||
* True only after the engine has emitted `audio:preview-start` for the
|
||||
* current `previewingId` — i.e. audio is actually playing. Drives the
|
||||
* progress-ring animation so the ring doesn't run ahead of the speaker
|
||||
* during the engine's download/decode/seek warmup. Reset to false on every
|
||||
* `startPreview` call so a switch from track A to track B doesn't carry
|
||||
* over A's animation state.
|
||||
*/
|
||||
audioStarted: boolean;
|
||||
|
||||
startPreview: (song: { id: string; title: string; artist: string; coverArt?: string; duration?: number }, location: TrackPreviewLocation) => Promise<void>;
|
||||
stopPreview: () => Promise<void>;
|
||||
@@ -49,7 +40,6 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
previewingTrack: null,
|
||||
elapsed: 0,
|
||||
duration: 30,
|
||||
audioStarted: false,
|
||||
|
||||
startPreview: async (song, location) => {
|
||||
const auth = useAuthStore.getState();
|
||||
@@ -87,7 +77,6 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
previewingTrack: { id: song.id, title: song.title, artist: song.artist, coverArt: song.coverArt },
|
||||
elapsed: 0,
|
||||
duration: previewDuration,
|
||||
audioStarted: false,
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -101,7 +90,7 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
} catch (e) {
|
||||
// Roll back optimistic state on failure.
|
||||
if (get().previewingId === song.id) {
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0, audioStarted: false });
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0 });
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -113,19 +102,15 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
await invoke('audio_preview_stop');
|
||||
} catch {
|
||||
/* engine will emit preview-end anyway; clear locally as fallback */
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0, audioStarted: false });
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0 });
|
||||
}
|
||||
},
|
||||
|
||||
_onStart: (id) => {
|
||||
const current = get().previewingId;
|
||||
if (current !== id) {
|
||||
if (get().previewingId !== id) {
|
||||
// Engine fired start for an id we didn't track locally — keep id but
|
||||
// leave previewingTrack as-is (the caller's startPreview() set it).
|
||||
set({ previewingId: id, elapsed: 0, audioStarted: true });
|
||||
} else {
|
||||
// Audio is now actually playing — unblock the progress-ring animation.
|
||||
set({ audioStarted: true });
|
||||
set({ previewingId: id, elapsed: 0 });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -136,6 +121,6 @@ export const usePreviewStore = create<PreviewState>((set, get) => ({
|
||||
|
||||
_onEnd: (id) => {
|
||||
if (get().previewingId !== id) return;
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0, audioStarted: false });
|
||||
set({ previewingId: null, previewingTrack: null, elapsed: 0 });
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user