feat(queue-store): add stop-after store and remove-after action
Derived store stopAfterTrackId reads from queueState (single source of truth). Actions: setStopAfter / clearStopAfter / toggleStopAfter mutate via v2_queue_* commands. consumeStopAfterIf is for the natural-end handler. removeAfter wraps v2_queue_remove_after and returns count for toast display. Refs #356. cc
This commit is contained in:
1 file changed
+58
@@ -6,6 +6,7 @@
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
||||
import { writable, get } from 'svelte/store';
|
||||
import { cmdToggleShuffle, cmdSetRepeatMode, cmdAddToQueue, cmdAddToQueueNext, cmdAddTracksToQueue, cmdAddTracksToQueueNext, cmdSetQueue, cmdClearQueue } from '$lib/services/commandRouter';
|
||||
|
||||
// ============ Types ============
|
||||
@@ -59,10 +60,16 @@ interface BackendQueueState {
|
||||
shuffle: boolean;
|
||||
repeat: 'Off' | 'All' | 'One';
|
||||
total_tracks: number;
|
||||
stop_after_track_id: number | null;
|
||||
}
|
||||
|
||||
export type RepeatMode = 'off' | 'all' | 'one';
|
||||
|
||||
// ============ Stores ============
|
||||
|
||||
/** Currently-marked "stop after" track ID. null = no marker. */
|
||||
export const stopAfterTrackId = writable<number | null>(null);
|
||||
|
||||
// ============ State ============
|
||||
|
||||
let queue: QueueTrack[] = [];
|
||||
@@ -218,6 +225,7 @@ async function applyBackendQueueState(queueState: BackendQueueState): Promise<vo
|
||||
if (pendingRepeatMode === repeatMode) {
|
||||
pendingRepeatMode = null;
|
||||
}
|
||||
stopAfterTrackId.set(queueState.stop_after_track_id);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -505,6 +513,56 @@ export async function moveQueueTrack(fromIndex: number, toIndex: number): Promis
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stop-after marker on a track ID. Replaces any previous marker.
|
||||
*/
|
||||
export async function setStopAfter(trackId: number): Promise<void> {
|
||||
await invoke('v2_queue_set_stop_after', { trackId });
|
||||
await syncQueueState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stop-after marker (user cancellation).
|
||||
*/
|
||||
export async function clearStopAfter(): Promise<void> {
|
||||
await invoke('v2_queue_clear_stop_after');
|
||||
await syncQueueState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the marker on a track: clears if currently set on that track, otherwise sets.
|
||||
*/
|
||||
export async function toggleStopAfter(trackId: number): Promise<void> {
|
||||
const current = get(stopAfterTrackId);
|
||||
if (current === trackId) {
|
||||
await clearStopAfter();
|
||||
} else {
|
||||
await setStopAfter(trackId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* One-shot consume: called by natural-end handlers before advancing.
|
||||
* Returns true if the marker fired (caller should pause instead of advance).
|
||||
*/
|
||||
export async function consumeStopAfterIf(finishedTrackId: number): Promise<boolean> {
|
||||
const fired = await invoke<boolean>('v2_queue_consume_stop_after_if', { finishedTrackId });
|
||||
if (fired) {
|
||||
await syncQueueState();
|
||||
}
|
||||
return fired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all queue tracks after the given index. Returns count removed.
|
||||
* Auto-clears marker if it referenced any removed track.
|
||||
*/
|
||||
export async function removeAfter(index: number): Promise<number> {
|
||||
const count = await invoke<number>('v2_queue_remove_after', { index });
|
||||
await syncQueueState();
|
||||
return count;
|
||||
}
|
||||
|
||||
// ============ Local Track Management ============
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user