mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 02:13:33 +00:00
Add files
This commit is contained in:
commit
e87c814068
266 changed files with 63938 additions and 0 deletions
200
src/renderer/store/app.store.ts
Normal file
200
src/renderer/store/app.store.ts
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
import merge from 'lodash/merge';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import create from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import { AlbumListSort, SongListSort, SortOrder } from '/@/renderer/api/types';
|
||||
import { AdvancedFilterGroup, CardDisplayType, Platform, FilterGroupType } from '/@/renderer/types';
|
||||
|
||||
type SidebarProps = {
|
||||
expanded: string[];
|
||||
image: boolean;
|
||||
leftWidth: string;
|
||||
rightExpanded: boolean;
|
||||
rightWidth: string;
|
||||
};
|
||||
|
||||
type LibraryPageProps<TSort> = {
|
||||
list: ListProps<TSort>;
|
||||
};
|
||||
|
||||
type ListFilter<TSort> = {
|
||||
musicFolderId?: string;
|
||||
sortBy: TSort;
|
||||
sortOrder: SortOrder;
|
||||
};
|
||||
|
||||
type ListAdvancedFilter = {
|
||||
enabled: boolean;
|
||||
filter: AdvancedFilterGroup;
|
||||
};
|
||||
|
||||
type ListProps<T> = {
|
||||
advancedFilter: ListAdvancedFilter;
|
||||
display: CardDisplayType;
|
||||
filter: ListFilter<T>;
|
||||
gridScrollOffset: number;
|
||||
listScrollOffset: number;
|
||||
size: number;
|
||||
type: 'list' | 'grid';
|
||||
};
|
||||
|
||||
type TitlebarProps = {
|
||||
backgroundColor: string;
|
||||
outOfView: boolean;
|
||||
};
|
||||
|
||||
export interface AppState {
|
||||
albums: LibraryPageProps<AlbumListSort>;
|
||||
isReorderingQueue: boolean;
|
||||
platform: Platform;
|
||||
sidebar: {
|
||||
expanded: string[];
|
||||
image: boolean;
|
||||
leftWidth: string;
|
||||
rightExpanded: boolean;
|
||||
rightWidth: string;
|
||||
};
|
||||
songs: LibraryPageProps<SongListSort>;
|
||||
titlebar: TitlebarProps;
|
||||
}
|
||||
|
||||
const DEFAULT_ADVANCED_FILTERS = {
|
||||
group: [],
|
||||
rules: [
|
||||
{
|
||||
field: '',
|
||||
operator: '',
|
||||
uniqueId: nanoid(),
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
type: FilterGroupType.AND,
|
||||
uniqueId: nanoid(),
|
||||
};
|
||||
|
||||
export interface AppSlice extends AppState {
|
||||
actions: {
|
||||
resetServerDefaults: () => void;
|
||||
setAppStore: (data: Partial<AppSlice>) => void;
|
||||
setPage: (
|
||||
page: 'albums' | 'songs',
|
||||
options: Partial<LibraryPageProps<AlbumListSort | SongListSort>>,
|
||||
) => void;
|
||||
setSidebar: (options: Partial<SidebarProps>) => void;
|
||||
setTitlebar: (options: Partial<TitlebarProps>) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const useAppStore = create<AppSlice>()(
|
||||
persist(
|
||||
devtools(
|
||||
immer((set, get) => ({
|
||||
actions: {
|
||||
resetServerDefaults: () => {
|
||||
set((state) => {
|
||||
state.albums.list = {
|
||||
...state.albums.list,
|
||||
filter: {
|
||||
...state.albums.list.filter,
|
||||
musicFolderId: undefined,
|
||||
},
|
||||
gridScrollOffset: 0,
|
||||
listScrollOffset: 0,
|
||||
};
|
||||
});
|
||||
},
|
||||
setAppStore: (data) => {
|
||||
set({ ...get(), ...data });
|
||||
},
|
||||
setPage: (page: 'albums' | 'songs', data: any) => {
|
||||
set((state) => {
|
||||
state[page] = { ...state[page], ...data };
|
||||
});
|
||||
},
|
||||
setSidebar: (options) => {
|
||||
set((state) => {
|
||||
state.sidebar = { ...state.sidebar, ...options };
|
||||
});
|
||||
},
|
||||
setTitlebar: (options) => {
|
||||
set((state) => {
|
||||
state.titlebar = { ...state.titlebar, ...options };
|
||||
});
|
||||
},
|
||||
},
|
||||
albums: {
|
||||
list: {
|
||||
advancedFilter: {
|
||||
enabled: false,
|
||||
filter: DEFAULT_ADVANCED_FILTERS,
|
||||
},
|
||||
display: CardDisplayType.CARD,
|
||||
filter: {
|
||||
musicFolderId: undefined,
|
||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
sortOrder: SortOrder.ASC,
|
||||
},
|
||||
gridScrollOffset: 0,
|
||||
listScrollOffset: 0,
|
||||
size: 50,
|
||||
type: 'grid',
|
||||
},
|
||||
},
|
||||
isReorderingQueue: false,
|
||||
platform: Platform.WINDOWS,
|
||||
sidebar: {
|
||||
expanded: [],
|
||||
image: false,
|
||||
leftWidth: '230px',
|
||||
rightExpanded: false,
|
||||
rightWidth: '400px',
|
||||
},
|
||||
songs: {
|
||||
list: {
|
||||
advancedFilter: {
|
||||
enabled: false,
|
||||
filter: DEFAULT_ADVANCED_FILTERS,
|
||||
},
|
||||
display: CardDisplayType.CARD,
|
||||
filter: {
|
||||
musicFolderId: undefined,
|
||||
sortBy: SongListSort.NAME,
|
||||
sortOrder: SortOrder.ASC,
|
||||
},
|
||||
gridScrollOffset: 0,
|
||||
listScrollOffset: 0,
|
||||
size: 50,
|
||||
type: 'grid',
|
||||
},
|
||||
},
|
||||
titlebar: {
|
||||
backgroundColor: '#000000',
|
||||
outOfView: false,
|
||||
},
|
||||
})),
|
||||
{ name: 'store_app' },
|
||||
),
|
||||
{
|
||||
merge: (persistedState, currentState) => {
|
||||
return merge(currentState, persistedState);
|
||||
},
|
||||
name: 'store_app',
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export const useAppStoreActions = () => useAppStore((state) => state.actions);
|
||||
|
||||
export const useAlbumRouteStore = () => useAppStore((state) => state.albums);
|
||||
|
||||
export const useSongRouteStore = () => useAppStore((state) => state.songs);
|
||||
|
||||
export const useSidebarStore = () => useAppStore((state) => state.sidebar);
|
||||
|
||||
export const useSidebarRightExpanded = () => useAppStore((state) => state.sidebar.rightExpanded);
|
||||
|
||||
export const useSetTitlebar = () => useAppStore((state) => state.actions.setTitlebar);
|
||||
|
||||
export const useTitlebarStore = () => useAppStore((state) => state.titlebar);
|
||||
90
src/renderer/store/auth.store.ts
Normal file
90
src/renderer/store/auth.store.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import merge from 'lodash/merge';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import create from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import { AlbumListSort, SortOrder } from '/@/renderer/api/types';
|
||||
import { useAppStore } from '/@/renderer/store/app.store';
|
||||
import { ServerListItem } from '/@/renderer/types';
|
||||
|
||||
export interface AuthState {
|
||||
currentServer: ServerListItem | null;
|
||||
deviceId: string;
|
||||
serverList: ServerListItem[];
|
||||
}
|
||||
|
||||
export interface AuthSlice extends AuthState {
|
||||
actions: {
|
||||
addServer: (args: ServerListItem) => void;
|
||||
deleteServer: (id: string) => void;
|
||||
setCurrentServer: (server: ServerListItem | null) => void;
|
||||
updateServer: (id: string, args: Partial<ServerListItem>) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthSlice>()(
|
||||
persist(
|
||||
devtools(
|
||||
immer((set) => ({
|
||||
actions: {
|
||||
addServer: (args) => {
|
||||
set((state) => {
|
||||
state.serverList.push(args);
|
||||
});
|
||||
},
|
||||
deleteServer: (id) => {
|
||||
set((state) => {
|
||||
state.serverList = state.serverList.filter((credential) => credential.id !== id);
|
||||
if (state.currentServer?.id === id) {
|
||||
state.currentServer = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
setCurrentServer: (server) => {
|
||||
set((state) => {
|
||||
state.currentServer = server;
|
||||
|
||||
if (server) {
|
||||
useAppStore.getState().actions.setPage('albums', {
|
||||
list: {
|
||||
...useAppStore.getState().albums.list,
|
||||
filter: {
|
||||
...useAppStore.getState().albums.list.filter,
|
||||
sortBy: AlbumListSort.RECENTLY_ADDED,
|
||||
sortOrder: SortOrder.ASC,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
updateServer: (id: string, args: Partial<ServerListItem>) => {
|
||||
set((state) => {
|
||||
const server = state.serverList.find((server) => server.id === id);
|
||||
if (server) {
|
||||
Object.assign(server, { ...server, ...args });
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
currentServer: null,
|
||||
deviceId: nanoid(),
|
||||
serverList: [],
|
||||
})),
|
||||
{ name: 'store_authentication' },
|
||||
),
|
||||
{
|
||||
merge: (persistedState, currentState) => merge(currentState, persistedState),
|
||||
name: 'store_authentication',
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export const useCurrentServerId = () => useAuthStore((state) => state.currentServer)?.id || '';
|
||||
|
||||
export const useCurrentServer = () => useAuthStore((state) => state.currentServer);
|
||||
|
||||
export const useServerList = () => useAuthStore((state) => state.serverList);
|
||||
|
||||
export const useAuthStoreActions = () => useAuthStore((state) => state.actions);
|
||||
3
src/renderer/store/index.ts
Normal file
3
src/renderer/store/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export * from './auth.store';
|
||||
export * from './player.store';
|
||||
export * from './app.store';
|
||||
821
src/renderer/store/player.store.ts
Normal file
821
src/renderer/store/player.store.ts
Normal file
|
|
@ -0,0 +1,821 @@
|
|||
import map from 'lodash/map';
|
||||
import merge from 'lodash/merge';
|
||||
import shuffle from 'lodash/shuffle';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import create from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import shallow from 'zustand/shallow';
|
||||
import { Song } from '/@/renderer/api/types';
|
||||
import { QueueSong, PlayerStatus, PlayerRepeat, PlayerShuffle, Play } from '/@/renderer/types';
|
||||
|
||||
export interface PlayerState {
|
||||
current: {
|
||||
index: number;
|
||||
nextIndex: number;
|
||||
player: 1 | 2;
|
||||
previousIndex: number;
|
||||
shuffledIndex: number;
|
||||
song?: QueueSong;
|
||||
status: PlayerStatus;
|
||||
time: number;
|
||||
};
|
||||
muted: boolean;
|
||||
queue: {
|
||||
default: QueueSong[];
|
||||
previousNode?: QueueSong;
|
||||
shuffled: string[];
|
||||
sorted: QueueSong[];
|
||||
};
|
||||
repeat: PlayerRepeat;
|
||||
shuffle: PlayerShuffle;
|
||||
volume: number;
|
||||
}
|
||||
|
||||
export interface PlayerData {
|
||||
current: {
|
||||
index: number;
|
||||
nextIndex?: number;
|
||||
player: 1 | 2;
|
||||
previousIndex?: number;
|
||||
shuffledIndex: number;
|
||||
song?: QueueSong;
|
||||
status: PlayerStatus;
|
||||
};
|
||||
player1?: QueueSong;
|
||||
player2?: QueueSong;
|
||||
queue: QueueData;
|
||||
}
|
||||
|
||||
export interface QueueData {
|
||||
current?: QueueSong;
|
||||
next?: QueueSong;
|
||||
previous?: QueueSong;
|
||||
}
|
||||
|
||||
export interface PlayerSlice extends PlayerState {
|
||||
actions: {
|
||||
addToQueue: (songs: Song[], type: Play) => PlayerData;
|
||||
autoNext: () => PlayerData;
|
||||
checkIsFirstTrack: () => boolean;
|
||||
checkIsLastTrack: () => boolean;
|
||||
clearQueue: () => PlayerData;
|
||||
getPlayerData: () => PlayerData;
|
||||
getQueueData: () => QueueData;
|
||||
moveToBottomOfQueue: (uniqueIds: string[]) => PlayerData;
|
||||
moveToTopOfQueue: (uniqueIds: string[]) => PlayerData;
|
||||
next: () => PlayerData;
|
||||
pause: () => void;
|
||||
play: () => void;
|
||||
player1: () => QueueSong | undefined;
|
||||
player2: () => QueueSong | undefined;
|
||||
previous: () => PlayerData;
|
||||
removeFromQueue: (uniqueIds: string[]) => PlayerData;
|
||||
reorderQueue: (rowUniqueIds: string[], afterUniqueId?: string) => PlayerData;
|
||||
setCurrentIndex: (index: number) => PlayerData;
|
||||
setCurrentTime: (time: number) => void;
|
||||
setCurrentTrack: (uniqueId: string) => PlayerData;
|
||||
setMuted: (muted: boolean) => void;
|
||||
setRepeat: (type: PlayerRepeat) => PlayerData;
|
||||
setShuffle: (type: PlayerShuffle) => PlayerData;
|
||||
setShuffledIndex: (index: number) => PlayerData;
|
||||
setStore: (data: Partial<PlayerState>) => void;
|
||||
setVolume: (volume: number) => void;
|
||||
shuffleQueue: () => PlayerData;
|
||||
};
|
||||
}
|
||||
|
||||
export const usePlayerStore = create<PlayerSlice>()(
|
||||
persist(
|
||||
devtools(
|
||||
immer((set, get) => ({
|
||||
actions: {
|
||||
addToQueue: (songs, type) => {
|
||||
const { shuffledIndex } = get().current;
|
||||
const shuffledQueue = get().queue.shuffled;
|
||||
const queueSongs = map(songs, (song) => ({
|
||||
...song,
|
||||
uniqueId: nanoid(),
|
||||
}));
|
||||
|
||||
if (type === Play.NOW) {
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const shuffledSongs = shuffle(queueSongs);
|
||||
const foundIndex = queueSongs.findIndex(
|
||||
(song) => song.uniqueId === shuffledSongs[0].uniqueId,
|
||||
);
|
||||
set((state) => {
|
||||
state.queue.shuffled = shuffledSongs.map((song) => song.uniqueId);
|
||||
});
|
||||
|
||||
set((state) => {
|
||||
state.queue.default = queueSongs;
|
||||
state.current.time = 0;
|
||||
state.current.player = 1;
|
||||
state.current.index = foundIndex;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.current.song = shuffledSongs[0];
|
||||
});
|
||||
} else {
|
||||
set((state) => {
|
||||
state.queue.default = queueSongs;
|
||||
state.current.time = 0;
|
||||
state.current.player = 1;
|
||||
state.current.index = 0;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.current.song = queueSongs[0];
|
||||
});
|
||||
}
|
||||
} else if (type === Play.LAST) {
|
||||
// Shuffle the queue after the current track
|
||||
const shuffledQueueWithNewSongs =
|
||||
get().shuffle === PlayerShuffle.TRACK
|
||||
? [
|
||||
...shuffledQueue.slice(0, shuffledIndex + 1),
|
||||
...shuffle([
|
||||
...queueSongs.map((song) => song.uniqueId),
|
||||
...shuffledQueue.slice(shuffledIndex + 1),
|
||||
]),
|
||||
]
|
||||
: [];
|
||||
|
||||
set((state) => {
|
||||
state.queue.default = [...get().queue.default, ...queueSongs];
|
||||
state.queue.shuffled = shuffledQueueWithNewSongs;
|
||||
});
|
||||
} else if (type === Play.NEXT) {
|
||||
const queue = get().queue.default;
|
||||
const currentIndex = get().current.index;
|
||||
|
||||
// Shuffle the queue after the current track
|
||||
const shuffledQueueWithNewSongs =
|
||||
get().shuffle === PlayerShuffle.TRACK
|
||||
? [
|
||||
...shuffledQueue.slice(0, shuffledIndex + 1),
|
||||
...shuffle([
|
||||
...queueSongs.map((song) => song.uniqueId),
|
||||
...shuffledQueue.slice(shuffledIndex + 1),
|
||||
]),
|
||||
]
|
||||
: [];
|
||||
|
||||
set((state) => {
|
||||
state.queue.default = [
|
||||
...queue.slice(0, currentIndex + 1),
|
||||
...queueSongs,
|
||||
...queue.slice(currentIndex + 1),
|
||||
];
|
||||
state.queue.shuffled = shuffledQueueWithNewSongs;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
autoNext: () => {
|
||||
const isLastTrack = get().actions.checkIsLastTrack();
|
||||
const { repeat } = get();
|
||||
|
||||
if (repeat === PlayerRepeat.ONE) {
|
||||
const nextIndex = get().current.index;
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = nextIndex;
|
||||
state.current.shuffledIndex = get().current.shuffledIndex;
|
||||
state.current.player = state.current.player === 1 ? 2 : 1;
|
||||
state.current.song = get().queue.default[nextIndex];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const nextShuffleIndex = isLastTrack ? 0 : get().current.shuffledIndex + 1;
|
||||
|
||||
const nextSong = get().queue.default.find(
|
||||
(song) => song.uniqueId === get().queue.shuffled[nextShuffleIndex],
|
||||
);
|
||||
|
||||
const nextSongIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === nextSong!.uniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = nextSongIndex!;
|
||||
state.current.shuffledIndex = nextShuffleIndex;
|
||||
state.current.player = state.current.player === 1 ? 2 : 1;
|
||||
state.current.song = nextSong!;
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else {
|
||||
const nextIndex = isLastTrack ? 0 : get().current.index + 1;
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = nextIndex;
|
||||
state.current.player = state.current.player === 1 ? 2 : 1;
|
||||
state.current.song = get().queue.default[nextIndex];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
checkIsFirstTrack: () => {
|
||||
const currentIndex =
|
||||
get().shuffle === PlayerShuffle.TRACK
|
||||
? get().current.shuffledIndex
|
||||
: get().current.index;
|
||||
|
||||
return currentIndex === 0;
|
||||
},
|
||||
checkIsLastTrack: () => {
|
||||
const currentIndex =
|
||||
get().shuffle === PlayerShuffle.TRACK
|
||||
? get().current.shuffledIndex
|
||||
: get().current.index;
|
||||
|
||||
return currentIndex === get().queue.default.length - 1;
|
||||
},
|
||||
clearQueue: () => {
|
||||
set((state) => {
|
||||
state.queue.default = [];
|
||||
state.queue.shuffled = [];
|
||||
state.queue.sorted = [];
|
||||
state.current.index = 0;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.current.player = 1;
|
||||
state.current.song = undefined;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
getPlayerData: () => {
|
||||
const queue = get().queue.default;
|
||||
const currentPlayer = get().current.player;
|
||||
const { repeat } = get();
|
||||
const isLastTrack = get().actions.checkIsLastTrack();
|
||||
const isFirstTrack = get().actions.checkIsFirstTrack();
|
||||
|
||||
let player1;
|
||||
let player2;
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const shuffledQueue = get().queue.shuffled;
|
||||
const { shuffledIndex } = get().current;
|
||||
const current = queue.find(
|
||||
(song) => song.uniqueId === shuffledQueue[shuffledIndex],
|
||||
) as QueueSong;
|
||||
|
||||
let nextSongIndex: number | undefined;
|
||||
let previousSongIndex: number | undefined;
|
||||
if (repeat === PlayerRepeat.ALL) {
|
||||
if (isLastTrack) nextSongIndex = 0;
|
||||
else nextSongIndex = shuffledIndex + 1;
|
||||
|
||||
if (isFirstTrack) previousSongIndex = queue.length - 1;
|
||||
else previousSongIndex = shuffledIndex - 1;
|
||||
}
|
||||
|
||||
if (repeat === PlayerRepeat.ONE) {
|
||||
nextSongIndex = shuffledIndex;
|
||||
previousSongIndex = shuffledIndex;
|
||||
}
|
||||
|
||||
if (repeat === PlayerRepeat.NONE) {
|
||||
if (isLastTrack) nextSongIndex = undefined;
|
||||
else nextSongIndex = shuffledIndex + 1;
|
||||
|
||||
if (isFirstTrack) previousSongIndex = undefined;
|
||||
else previousSongIndex = shuffledIndex - 1;
|
||||
}
|
||||
|
||||
const next = nextSongIndex
|
||||
? (queue.find(
|
||||
(song) => song.uniqueId === shuffledQueue[nextSongIndex as number],
|
||||
) as QueueSong)
|
||||
: undefined;
|
||||
|
||||
const previous = queue.find(
|
||||
(song) => song.uniqueId === shuffledQueue[shuffledIndex - 1],
|
||||
) as QueueSong;
|
||||
|
||||
player1 = currentPlayer === 1 ? current : next;
|
||||
player2 = currentPlayer === 1 ? next : current;
|
||||
|
||||
return {
|
||||
current: {
|
||||
index: get().current.index,
|
||||
nextIndex: nextSongIndex,
|
||||
player: get().current.player,
|
||||
previousIndex: previousSongIndex,
|
||||
shuffledIndex: get().current.shuffledIndex,
|
||||
song: get().current.song,
|
||||
status: get().current.status,
|
||||
},
|
||||
player1,
|
||||
player2,
|
||||
queue: {
|
||||
current,
|
||||
next,
|
||||
previous,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const currentIndex = get().current.index;
|
||||
|
||||
let nextSongIndex;
|
||||
let previousSongIndex;
|
||||
if (repeat === PlayerRepeat.ALL) {
|
||||
if (isLastTrack) nextSongIndex = 0;
|
||||
else nextSongIndex = currentIndex + 1;
|
||||
|
||||
if (isFirstTrack) previousSongIndex = queue.length - 1;
|
||||
else previousSongIndex = currentIndex - 1;
|
||||
}
|
||||
|
||||
if (repeat === PlayerRepeat.ONE) {
|
||||
nextSongIndex = currentIndex;
|
||||
previousSongIndex = currentIndex;
|
||||
}
|
||||
|
||||
if (repeat === PlayerRepeat.NONE) {
|
||||
if (isLastTrack) nextSongIndex = undefined;
|
||||
else nextSongIndex = currentIndex + 1;
|
||||
|
||||
if (isFirstTrack) previousSongIndex = undefined;
|
||||
else previousSongIndex = currentIndex - 1;
|
||||
}
|
||||
|
||||
player1 =
|
||||
currentPlayer === 1
|
||||
? queue[currentIndex]
|
||||
: nextSongIndex !== undefined
|
||||
? queue[nextSongIndex]
|
||||
: undefined;
|
||||
|
||||
player2 =
|
||||
currentPlayer === 1
|
||||
? nextSongIndex !== undefined
|
||||
? queue[nextSongIndex]
|
||||
: undefined
|
||||
: queue[currentIndex];
|
||||
|
||||
return {
|
||||
current: {
|
||||
index: currentIndex,
|
||||
nextIndex: nextSongIndex,
|
||||
player: get().current.player,
|
||||
previousIndex: previousSongIndex,
|
||||
shuffledIndex: get().current.shuffledIndex,
|
||||
song: get().current.song,
|
||||
status: get().current.status,
|
||||
},
|
||||
player1,
|
||||
player2,
|
||||
queue: {
|
||||
current: queue[currentIndex],
|
||||
next: nextSongIndex !== undefined ? queue[nextSongIndex] : undefined,
|
||||
previous: queue[currentIndex - 1],
|
||||
},
|
||||
};
|
||||
},
|
||||
getQueueData: () => {
|
||||
const queue = get().queue.default;
|
||||
return {
|
||||
current: queue[get().current.index],
|
||||
next: queue[get().current.index + 1],
|
||||
previous: queue[get().current.index - 1],
|
||||
};
|
||||
},
|
||||
moveToBottomOfQueue: (uniqueIds) => {
|
||||
const queue = get().queue.default;
|
||||
|
||||
const songsToMove = queue.filter((song) => uniqueIds.includes(song.uniqueId));
|
||||
const songsToStay = queue.filter((song) => !uniqueIds.includes(song.uniqueId));
|
||||
|
||||
const reorderedQueue = [...songsToStay, ...songsToMove];
|
||||
|
||||
const currentSongUniqueId = get().current.song?.uniqueId;
|
||||
const newCurrentSongIndex = reorderedQueue.findIndex(
|
||||
(song) => song.uniqueId === currentSongUniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.index = newCurrentSongIndex;
|
||||
state.queue.default = reorderedQueue;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
moveToTopOfQueue: (uniqueIds) => {
|
||||
const queue = get().queue.default;
|
||||
|
||||
const songsToMove = queue.filter((song) => uniqueIds.includes(song.uniqueId));
|
||||
const songsToStay = queue.filter((song) => !uniqueIds.includes(song.uniqueId));
|
||||
|
||||
const reorderedQueue = [...songsToMove, ...songsToStay];
|
||||
|
||||
const currentSongUniqueId = get().current.song?.uniqueId;
|
||||
const newCurrentSongIndex = reorderedQueue.findIndex(
|
||||
(song) => song.uniqueId === currentSongUniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.index = newCurrentSongIndex;
|
||||
state.queue.default = reorderedQueue;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
next: () => {
|
||||
const isLastTrack = get().actions.checkIsLastTrack();
|
||||
const { repeat } = get();
|
||||
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const nextShuffleIndex = isLastTrack ? 0 : get().current.shuffledIndex + 1;
|
||||
|
||||
const nextSong = get().queue.default.find(
|
||||
(song) => song.uniqueId === get().queue.shuffled[nextShuffleIndex],
|
||||
);
|
||||
|
||||
const nextSongIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === nextSong?.uniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = nextSongIndex!;
|
||||
state.current.shuffledIndex = nextShuffleIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = nextSong!;
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else {
|
||||
const nextIndex =
|
||||
repeat === PlayerRepeat.ALL
|
||||
? isLastTrack
|
||||
? 0
|
||||
: get().current.index + 1
|
||||
: isLastTrack
|
||||
? get().current.index
|
||||
: get().current.index + 1;
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = nextIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = get().queue.default[nextIndex];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
pause: () => {
|
||||
set((state) => {
|
||||
state.current.status = PlayerStatus.PAUSED;
|
||||
});
|
||||
},
|
||||
play: () => {
|
||||
set((state) => {
|
||||
state.current.status = PlayerStatus.PLAYING;
|
||||
});
|
||||
},
|
||||
player1: () => {
|
||||
return get().actions.getPlayerData().player1;
|
||||
},
|
||||
player2: () => {
|
||||
return get().actions.getPlayerData().player2;
|
||||
},
|
||||
previous: () => {
|
||||
const isFirstTrack = get().actions.checkIsFirstTrack();
|
||||
const { repeat } = get();
|
||||
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const prevShuffleIndex = isFirstTrack ? 0 : get().current.shuffledIndex - 1;
|
||||
|
||||
const prevSong = get().queue.default.find(
|
||||
(song) => song.uniqueId === get().queue.shuffled[prevShuffleIndex],
|
||||
);
|
||||
|
||||
const prevIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === prevSong?.uniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = prevIndex!;
|
||||
state.current.shuffledIndex = prevShuffleIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = prevSong!;
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else {
|
||||
let prevIndex: number;
|
||||
if (repeat === PlayerRepeat.ALL) {
|
||||
prevIndex = isFirstTrack ? get().queue.default.length - 1 : get().current.index - 1;
|
||||
} else {
|
||||
prevIndex = isFirstTrack ? 0 : get().current.index - 1;
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = prevIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = state.queue.default[state.current.index];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
removeFromQueue: (uniqueIds) => {
|
||||
const queue = get().queue.default;
|
||||
|
||||
const newQueue = queue.filter((song) => !uniqueIds.includes(song.uniqueId));
|
||||
|
||||
set((state) => {
|
||||
state.queue.default = newQueue;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
reorderQueue: (rowUniqueIds: string[], afterUniqueId?: string) => {
|
||||
// Don't move if dropping on top of a selected row
|
||||
if (afterUniqueId && rowUniqueIds.includes(afterUniqueId)) {
|
||||
return get().actions.getPlayerData();
|
||||
}
|
||||
|
||||
const queue = get().queue.default;
|
||||
const currentSongUniqueId = get().current.song?.uniqueId;
|
||||
const queueWithoutSelectedRows = queue.filter(
|
||||
(song) => !rowUniqueIds.includes(song.uniqueId),
|
||||
);
|
||||
|
||||
const moveBeforeIndex = queueWithoutSelectedRows.findIndex(
|
||||
(song) => song.uniqueId === afterUniqueId,
|
||||
);
|
||||
|
||||
// AG-Grid does not provide node data when a row is moved to the bottom of the list
|
||||
const reorderedQueue = afterUniqueId
|
||||
? [
|
||||
...queueWithoutSelectedRows.slice(0, moveBeforeIndex),
|
||||
...queue.filter((song) => rowUniqueIds.includes(song.uniqueId)),
|
||||
...queueWithoutSelectedRows.slice(moveBeforeIndex),
|
||||
]
|
||||
: [
|
||||
...queueWithoutSelectedRows,
|
||||
...queue.filter((song) => rowUniqueIds.includes(song.uniqueId)),
|
||||
];
|
||||
|
||||
const currentSongIndex = reorderedQueue.findIndex(
|
||||
(song) => song.uniqueId === currentSongUniqueId,
|
||||
);
|
||||
|
||||
set({
|
||||
current: { ...get().current, index: currentSongIndex },
|
||||
queue: { ...get().queue, default: reorderedQueue },
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setCurrentIndex: (index) => {
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const foundSong = get().queue.default.find(
|
||||
(song) => song.uniqueId === get().queue.shuffled[index],
|
||||
);
|
||||
const foundIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === foundSong?.uniqueId,
|
||||
);
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = foundIndex!;
|
||||
state.current.shuffledIndex = index;
|
||||
state.current.player = 1;
|
||||
state.current.song = foundSong!;
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else {
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = index;
|
||||
state.current.player = 1;
|
||||
state.current.song = state.queue.default[index];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setCurrentTime: (time) => {
|
||||
set((state) => {
|
||||
state.current.time = time;
|
||||
});
|
||||
},
|
||||
setCurrentTrack: (uniqueId) => {
|
||||
if (get().shuffle === PlayerShuffle.TRACK) {
|
||||
const defaultIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === uniqueId,
|
||||
);
|
||||
|
||||
const shuffledIndex = get().queue.shuffled.findIndex((id) => id === uniqueId);
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = defaultIndex;
|
||||
state.current.shuffledIndex = shuffledIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = state.queue.default[defaultIndex];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
} else {
|
||||
const defaultIndex = get().queue.default.findIndex(
|
||||
(song) => song.uniqueId === uniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.index = defaultIndex;
|
||||
state.current.player = 1;
|
||||
state.current.song = state.queue.default[defaultIndex];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
}
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setMuted: (muted: boolean) => {
|
||||
set((state) => {
|
||||
state.muted = muted;
|
||||
});
|
||||
},
|
||||
setRepeat: (type: PlayerRepeat) => {
|
||||
set((state) => {
|
||||
state.repeat = type;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setShuffle: (type: PlayerShuffle) => {
|
||||
if (type === PlayerShuffle.NONE) {
|
||||
set((state) => {
|
||||
state.shuffle = type;
|
||||
state.queue.shuffled = [];
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
}
|
||||
|
||||
const currentSongId = get().current.song?.uniqueId;
|
||||
|
||||
const queueWithoutCurrentSong = get().queue.default.filter(
|
||||
(song) => song.uniqueId !== currentSongId,
|
||||
);
|
||||
|
||||
const shuffledSongIds = shuffle(queueWithoutCurrentSong).map((song) => song.uniqueId);
|
||||
|
||||
set((state) => {
|
||||
state.shuffle = type;
|
||||
state.current.shuffledIndex = 0;
|
||||
state.queue.shuffled = [currentSongId!, ...shuffledSongIds];
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setShuffledIndex: (index) => {
|
||||
set((state) => {
|
||||
state.current.time = 0;
|
||||
state.current.shuffledIndex = index;
|
||||
state.current.player = 1;
|
||||
state.current.song = state.queue.default[index];
|
||||
state.queue.previousNode = get().current.song;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
setStore: (data) => {
|
||||
set({ ...get(), ...data });
|
||||
},
|
||||
setVolume: (volume: number) => {
|
||||
set((state) => {
|
||||
state.volume = volume;
|
||||
});
|
||||
},
|
||||
shuffleQueue: () => {
|
||||
const queue = get().queue.default;
|
||||
const shuffledQueue = shuffle(queue);
|
||||
|
||||
const currentSongUniqueId = get().current.song?.uniqueId;
|
||||
const newCurrentSongIndex = shuffledQueue.findIndex(
|
||||
(song) => song.uniqueId === currentSongUniqueId,
|
||||
);
|
||||
|
||||
set((state) => {
|
||||
state.current.index = newCurrentSongIndex;
|
||||
state.queue.default = shuffledQueue;
|
||||
});
|
||||
|
||||
return get().actions.getPlayerData();
|
||||
},
|
||||
},
|
||||
current: {
|
||||
index: 0,
|
||||
nextIndex: 0,
|
||||
player: 1,
|
||||
previousIndex: 0,
|
||||
shuffledIndex: 0,
|
||||
song: {} as QueueSong,
|
||||
status: PlayerStatus.PAUSED,
|
||||
time: 0,
|
||||
},
|
||||
muted: false,
|
||||
queue: {
|
||||
default: [],
|
||||
played: [],
|
||||
previousNode: {} as QueueSong,
|
||||
shuffled: [],
|
||||
sorted: [],
|
||||
},
|
||||
repeat: PlayerRepeat.NONE,
|
||||
shuffle: PlayerShuffle.NONE,
|
||||
volume: 50,
|
||||
})),
|
||||
{ name: 'store_player' },
|
||||
),
|
||||
{
|
||||
merge: (persistedState, currentState) => {
|
||||
return merge(currentState, persistedState);
|
||||
},
|
||||
name: 'store_player',
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export const usePlayerStoreActions = () => usePlayerStore((state) => state.actions);
|
||||
|
||||
export const usePlayerControls = () =>
|
||||
usePlayerStore(
|
||||
(state) => ({
|
||||
autoNext: state.actions.autoNext,
|
||||
next: state.actions.next,
|
||||
pause: state.actions.pause,
|
||||
play: state.actions.play,
|
||||
previous: state.actions.previous,
|
||||
setCurrentIndex: state.actions.setCurrentIndex,
|
||||
setMuted: state.actions.setMuted,
|
||||
setRepeat: state.actions.setRepeat,
|
||||
setShuffle: state.actions.setShuffle,
|
||||
setShuffledIndex: state.actions.setShuffledIndex,
|
||||
setVolume: state.actions.setVolume,
|
||||
}),
|
||||
shallow,
|
||||
);
|
||||
|
||||
export const useQueueControls = () =>
|
||||
usePlayerStore(
|
||||
(state) => ({
|
||||
addToQueue: state.actions.addToQueue,
|
||||
clearQueue: state.actions.clearQueue,
|
||||
moveToBottomOfQueue: state.actions.moveToBottomOfQueue,
|
||||
moveToTopOfQueue: state.actions.moveToTopOfQueue,
|
||||
removeFromQueue: state.actions.removeFromQueue,
|
||||
reorderQueue: state.actions.reorderQueue,
|
||||
setCurrentIndex: state.actions.setCurrentIndex,
|
||||
setCurrentTrack: state.actions.setCurrentTrack,
|
||||
setShuffledIndex: state.actions.setShuffledIndex,
|
||||
shuffleQueue: state.actions.shuffleQueue,
|
||||
}),
|
||||
shallow,
|
||||
);
|
||||
|
||||
export const useQueueData = () => usePlayerStore((state) => state.actions.getQueueData);
|
||||
|
||||
export const usePlayer1Data = () => usePlayerStore((state) => state.actions.player1);
|
||||
|
||||
export const usePlayer2Data = () => usePlayerStore((state) => state.actions.player2);
|
||||
|
||||
export const useSetCurrentTime = () => usePlayerStore((state) => state.actions.setCurrentTime);
|
||||
|
||||
export const useIsFirstTrack = () => usePlayerStore((state) => state.actions.checkIsFirstTrack);
|
||||
|
||||
export const useIsLastTrack = () => usePlayerStore((state) => state.actions.checkIsLastTrack);
|
||||
|
||||
export const useDefaultQueue = () => usePlayerStore((state) => state.queue.default);
|
||||
|
||||
export const useCurrentSong = () => usePlayerStore((state) => state.current.song);
|
||||
|
||||
export const useCurrentPlayer = () => usePlayerStore((state) => state.current.player);
|
||||
|
||||
export const useCurrentStatus = () => usePlayerStore((state) => state.current.status);
|
||||
|
||||
export const usePreviousSong = () => usePlayerStore((state) => state.queue.previousNode);
|
||||
|
||||
export const useRepeatStatus = () => usePlayerStore((state) => state.repeat);
|
||||
|
||||
export const useShuffleStatus = () => usePlayerStore((state) => state.shuffle);
|
||||
|
||||
export const useCurrentTime = () => usePlayerStore((state) => state.current.time);
|
||||
|
||||
export const useVolume = () => usePlayerStore((state) => state.volume);
|
||||
|
||||
export const useMuted = () => usePlayerStore((state) => state.muted);
|
||||
237
src/renderer/store/settings.store.ts
Normal file
237
src/renderer/store/settings.store.ts
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/* eslint-disable prefer-destructuring */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import merge from 'lodash/merge';
|
||||
import create from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import { AppTheme } from '/@/renderer/themes/types';
|
||||
import {
|
||||
TableColumn,
|
||||
CrossfadeStyle,
|
||||
Play,
|
||||
PlaybackStyle,
|
||||
PlaybackType,
|
||||
TableType,
|
||||
} from '/@/renderer/types';
|
||||
|
||||
export type PersistedTableColumn = {
|
||||
column: TableColumn;
|
||||
width: number;
|
||||
};
|
||||
|
||||
export type DataTableProps = {
|
||||
autoFit: boolean;
|
||||
columns: PersistedTableColumn[];
|
||||
followCurrentSong?: boolean;
|
||||
rowHeight: number;
|
||||
};
|
||||
|
||||
export type SideQueueType = 'sideQueue' | 'sideDrawerQueue';
|
||||
|
||||
export interface SettingsState {
|
||||
general: {
|
||||
followSystemTheme: boolean;
|
||||
fontContent: string;
|
||||
fontHeader: string;
|
||||
showQueueDrawerButton: boolean;
|
||||
sideQueueType: SideQueueType;
|
||||
theme: AppTheme;
|
||||
themeDark: AppTheme;
|
||||
themeLight: AppTheme;
|
||||
};
|
||||
player: {
|
||||
audioDeviceId?: string | null;
|
||||
crossfadeDuration: number;
|
||||
crossfadeStyle: CrossfadeStyle;
|
||||
globalMediaHotkeys: boolean;
|
||||
muted: boolean;
|
||||
playButtonBehavior: Play;
|
||||
scrobble: {
|
||||
enabled: boolean;
|
||||
scrobbleAtPercentage: number;
|
||||
};
|
||||
skipButtons: {
|
||||
enabled: boolean;
|
||||
skipBackwardSeconds: number;
|
||||
skipForwardSeconds: number;
|
||||
};
|
||||
style: PlaybackStyle;
|
||||
type: PlaybackType;
|
||||
};
|
||||
tab: 'general' | 'playback' | 'view' | string;
|
||||
tables: {
|
||||
nowPlaying: DataTableProps;
|
||||
sideDrawerQueue: DataTableProps;
|
||||
sideQueue: DataTableProps;
|
||||
songs: DataTableProps;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SettingsSlice extends SettingsState {
|
||||
actions: {
|
||||
setSettings: (data: Partial<SettingsState>) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const useSettingsStore = create<SettingsSlice>()(
|
||||
persist(
|
||||
devtools(
|
||||
immer((set, get) => ({
|
||||
actions: {
|
||||
setSettings: (data) => {
|
||||
set({ ...get(), ...data });
|
||||
},
|
||||
},
|
||||
general: {
|
||||
followSystemTheme: false,
|
||||
fontContent: 'Circular STD',
|
||||
fontHeader: 'Gotham',
|
||||
showQueueDrawerButton: true,
|
||||
sideQueueType: 'sideQueue',
|
||||
theme: AppTheme.DEFAULT_DARK,
|
||||
themeDark: AppTheme.DEFAULT_DARK,
|
||||
themeLight: AppTheme.DEFAULT_LIGHT,
|
||||
},
|
||||
player: {
|
||||
audioDeviceId: undefined,
|
||||
crossfadeDuration: 5,
|
||||
crossfadeStyle: CrossfadeStyle.EQUALPOWER,
|
||||
globalMediaHotkeys: true,
|
||||
muted: false,
|
||||
playButtonBehavior: Play.NOW,
|
||||
scrobble: {
|
||||
enabled: false,
|
||||
scrobbleAtPercentage: 75,
|
||||
},
|
||||
skipButtons: {
|
||||
enabled: true,
|
||||
skipBackwardSeconds: 10,
|
||||
skipForwardSeconds: 30,
|
||||
},
|
||||
style: PlaybackStyle.GAPLESS,
|
||||
type: PlaybackType.LOCAL,
|
||||
},
|
||||
|
||||
tab: 'general',
|
||||
tables: {
|
||||
nowPlaying: {
|
||||
autoFit: true,
|
||||
columns: [
|
||||
{
|
||||
column: TableColumn.ROW_INDEX,
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
column: TableColumn.TITLE,
|
||||
width: 500,
|
||||
},
|
||||
{
|
||||
column: TableColumn.DURATION,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.ALBUM,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.ALBUM_ARTIST,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.GENRE,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.YEAR,
|
||||
width: 100,
|
||||
},
|
||||
],
|
||||
followCurrentSong: true,
|
||||
rowHeight: 30,
|
||||
},
|
||||
sideDrawerQueue: {
|
||||
autoFit: true,
|
||||
columns: [
|
||||
{
|
||||
column: TableColumn.TITLE_COMBINED,
|
||||
width: 500,
|
||||
},
|
||||
{
|
||||
column: TableColumn.DURATION,
|
||||
width: 100,
|
||||
},
|
||||
],
|
||||
followCurrentSong: true,
|
||||
rowHeight: 60,
|
||||
},
|
||||
sideQueue: {
|
||||
autoFit: true,
|
||||
columns: [
|
||||
{
|
||||
column: TableColumn.ROW_INDEX,
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
column: TableColumn.TITLE_COMBINED,
|
||||
width: 500,
|
||||
},
|
||||
{
|
||||
column: TableColumn.DURATION,
|
||||
width: 100,
|
||||
},
|
||||
],
|
||||
followCurrentSong: true,
|
||||
rowHeight: 60,
|
||||
},
|
||||
songs: {
|
||||
autoFit: true,
|
||||
columns: [
|
||||
{
|
||||
column: TableColumn.ROW_INDEX,
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
column: TableColumn.TITLE_COMBINED,
|
||||
width: 500,
|
||||
},
|
||||
{
|
||||
column: TableColumn.DURATION,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.ALBUM,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
column: TableColumn.ARTIST,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
column: TableColumn.YEAR,
|
||||
width: 100,
|
||||
},
|
||||
],
|
||||
rowHeight: 60,
|
||||
},
|
||||
},
|
||||
})),
|
||||
{ name: 'store_settings' },
|
||||
),
|
||||
{
|
||||
merge: (persistedState, currentState) => {
|
||||
return merge(currentState, persistedState);
|
||||
},
|
||||
name: 'store_settings',
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
export const useSettingsStoreActions = () => useSettingsStore((state) => state.actions);
|
||||
|
||||
export const usePlayerSettings = () => useSettingsStore((state) => state.player);
|
||||
|
||||
export const useTableSettings = (type: TableType) =>
|
||||
useSettingsStore((state) => state.tables[type]);
|
||||
|
||||
export const useGeneralSettings = () => useSettingsStore((state) => state.general);
|
||||
Loading…
Add table
Add a link
Reference in a new issue