3984c7a499
Add a play overlay button shown on cover art hover that inserts the track into the queue right after the current track and jumps to it, so it takes priority over what's already queued. Replaces the double-click-to-play interaction with a new playNow queue action.
110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
|
|
export type QueueSource =
|
|
| 'manual'
|
|
| 'album'
|
|
| 'playlist'
|
|
| 'artist'
|
|
| 'search'
|
|
| 'radio';
|
|
|
|
export interface QueueEntry {
|
|
trackId: string;
|
|
title: string;
|
|
artistName: string;
|
|
albumTitle: string;
|
|
durationMs: number;
|
|
albumArtUrl?: string;
|
|
}
|
|
|
|
export interface QueueState {
|
|
entries: QueueEntry[];
|
|
currentIndex: number;
|
|
source: QueueSource;
|
|
sourceId: string | null;
|
|
sourceName: string | null;
|
|
}
|
|
|
|
export const queueInitialState: QueueState = {
|
|
entries: [],
|
|
currentIndex: -1,
|
|
source: 'manual',
|
|
sourceId: null,
|
|
sourceName: null,
|
|
};
|
|
|
|
export const queueSlice = createSlice({
|
|
name: 'queue',
|
|
initialState: queueInitialState,
|
|
reducers: {
|
|
setQueue(
|
|
state,
|
|
action: PayloadAction<{
|
|
entries: QueueEntry[];
|
|
startIndex?: number;
|
|
source: QueueSource;
|
|
sourceId?: string;
|
|
sourceName?: string;
|
|
}>,
|
|
) {
|
|
state.entries = action.payload.entries;
|
|
state.currentIndex = action.payload.startIndex ?? 0;
|
|
state.source = action.payload.source;
|
|
state.sourceId = action.payload.sourceId ?? null;
|
|
state.sourceName = action.payload.sourceName ?? null;
|
|
},
|
|
addToQueue(state, action: PayloadAction<QueueEntry>) {
|
|
state.entries.push(action.payload);
|
|
},
|
|
addNextInQueue(state, action: PayloadAction<QueueEntry>) {
|
|
state.entries.splice(state.currentIndex + 1, 0, action.payload);
|
|
},
|
|
playNow(state, action: PayloadAction<QueueEntry>) {
|
|
const insertAt = state.currentIndex + 1;
|
|
state.entries.splice(insertAt, 0, action.payload);
|
|
state.currentIndex = insertAt;
|
|
},
|
|
removeFromQueue(state, action: PayloadAction<number>) {
|
|
state.entries.splice(action.payload, 1);
|
|
if (action.payload < state.currentIndex) state.currentIndex--;
|
|
},
|
|
moveInQueue(state, action: PayloadAction<{ from: number; to: number }>) {
|
|
const { from, to } = action.payload;
|
|
const [entry] = state.entries.splice(from, 1);
|
|
state.entries.splice(to, 0, entry);
|
|
if (state.currentIndex === from) state.currentIndex = to;
|
|
else if (from < state.currentIndex && to >= state.currentIndex)
|
|
state.currentIndex--;
|
|
else if (from > state.currentIndex && to <= state.currentIndex)
|
|
state.currentIndex++;
|
|
},
|
|
goToIndex(state, action: PayloadAction<number>) {
|
|
state.currentIndex = action.payload;
|
|
},
|
|
nextTrack(state) {
|
|
if (state.currentIndex < state.entries.length - 1) state.currentIndex++;
|
|
},
|
|
prevTrack(state) {
|
|
if (state.currentIndex > 0) state.currentIndex--;
|
|
},
|
|
clearQueue(state) {
|
|
state.entries = [];
|
|
state.currentIndex = -1;
|
|
},
|
|
},
|
|
});
|
|
|
|
export const {
|
|
setQueue,
|
|
addToQueue,
|
|
addNextInQueue,
|
|
playNow,
|
|
removeFromQueue,
|
|
moveInQueue,
|
|
goToIndex,
|
|
nextTrack,
|
|
prevTrack,
|
|
clearQueue,
|
|
} = queueSlice.actions;
|
|
export default queueSlice.reducer;
|