Split stores

This commit is contained in:
jeffvli 2022-12-21 01:25:56 -08:00
parent 2a858f3107
commit b742b814c0
7 changed files with 200 additions and 122 deletions

View file

@ -0,0 +1,83 @@
import merge from 'lodash/merge';
import create from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { AlbumListArgs, AlbumListSort, SortOrder } from '/@/renderer/api/types';
import { CardDisplayType } from '/@/renderer/types';
type TableProps = {
scrollOffset: number;
};
type ListProps<T> = {
display: CardDisplayType;
filter: T;
grid: {
scrollOffset: number;
size: number;
};
table: TableProps;
};
type AlbumListFilter = Omit<AlbumListArgs['query'], 'startIndex' | 'limit'>;
export interface AlbumState {
list: ListProps<AlbumListFilter>;
}
export interface AlbumSlice extends AlbumState {
actions: {
setFilters: (data: Partial<AlbumListFilter>) => void;
setStore: (data: Partial<AlbumSlice>) => void;
};
}
export const useAlbumStore = create<AlbumSlice>()(
persist(
devtools(
immer((set, get) => ({
actions: {
setFilters: (data) => {
set((state) => {
state.list.filter = { ...state.list.filter, ...data };
});
},
setStore: (data) => {
set({ ...get(), ...data });
},
},
list: {
display: CardDisplayType.CARD,
filter: {
musicFolderId: undefined,
sortBy: AlbumListSort.RECENTLY_ADDED,
sortOrder: SortOrder.ASC,
},
grid: {
scrollOffset: 0,
size: 50,
},
table: {
scrollOffset: 0,
},
},
})),
{ name: 'store_album' },
),
{
merge: (persistedState, currentState) => {
return merge(currentState, persistedState);
},
name: 'store_album',
version: 1,
},
),
);
export const useAlbumStoreActions = () => useAlbumStore((state) => state.actions);
export const useSetAlbumStore = () => useAlbumStore((state) => state.actions.setStore);
export const useSetAlbumFilters = () => useAlbumStore((state) => state.actions.setFilters);
export const useAlbumListStore = () => useAlbumStore((state) => state.list);

View file

@ -1,10 +1,8 @@
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import { nanoid } from 'nanoid/non-secure';
import create from 'zustand'; import create from 'zustand';
import { devtools, persist } from 'zustand/middleware'; import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer'; import { immer } from 'zustand/middleware/immer';
import { AlbumListSort, SongListSort, SortOrder } from '/@/renderer/api/types'; import { Platform } from '/@/renderer/types';
import { AdvancedFilterGroup, CardDisplayType, Platform, FilterGroupType } from '/@/renderer/types';
type SidebarProps = { type SidebarProps = {
expanded: string[]; expanded: string[];
@ -14,38 +12,12 @@ type SidebarProps = {
rightWidth: string; 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 = { type TitlebarProps = {
backgroundColor: string; backgroundColor: string;
outOfView: boolean; outOfView: boolean;
}; };
export interface AppState { export interface AppState {
albums: LibraryPageProps<AlbumListSort>;
isReorderingQueue: boolean; isReorderingQueue: boolean;
platform: Platform; platform: Platform;
sidebar: { sidebar: {
@ -55,32 +27,12 @@ export interface AppState {
rightExpanded: boolean; rightExpanded: boolean;
rightWidth: string; rightWidth: string;
}; };
songs: LibraryPageProps<SongListSort>;
titlebar: TitlebarProps; titlebar: TitlebarProps;
} }
const DEFAULT_ADVANCED_FILTERS = {
group: [],
rules: [
{
field: '',
operator: '',
uniqueId: nanoid(),
value: '',
},
],
type: FilterGroupType.AND,
uniqueId: nanoid(),
};
export interface AppSlice extends AppState { export interface AppSlice extends AppState {
actions: { actions: {
resetServerDefaults: () => void;
setAppStore: (data: Partial<AppSlice>) => void; setAppStore: (data: Partial<AppSlice>) => void;
setPage: (
page: 'albums' | 'songs',
options: Partial<LibraryPageProps<AlbumListSort | SongListSort>>,
) => void;
setSidebar: (options: Partial<SidebarProps>) => void; setSidebar: (options: Partial<SidebarProps>) => void;
setTitlebar: (options: Partial<TitlebarProps>) => void; setTitlebar: (options: Partial<TitlebarProps>) => void;
}; };
@ -91,27 +43,9 @@ export const useAppStore = create<AppSlice>()(
devtools( devtools(
immer((set, get) => ({ immer((set, get) => ({
actions: { actions: {
resetServerDefaults: () => {
set((state) => {
state.albums.list = {
...state.albums.list,
filter: {
...state.albums.list.filter,
musicFolderId: undefined,
},
gridScrollOffset: 0,
listScrollOffset: 0,
};
});
},
setAppStore: (data) => { setAppStore: (data) => {
set({ ...get(), ...data }); set({ ...get(), ...data });
}, },
setPage: (page: 'albums' | 'songs', data: any) => {
set((state) => {
state[page] = { ...state[page], ...data };
});
},
setSidebar: (options) => { setSidebar: (options) => {
set((state) => { set((state) => {
state.sidebar = { ...state.sidebar, ...options }; state.sidebar = { ...state.sidebar, ...options };
@ -123,24 +57,6 @@ export const useAppStore = create<AppSlice>()(
}); });
}, },
}, },
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, isReorderingQueue: false,
platform: Platform.WINDOWS, platform: Platform.WINDOWS,
sidebar: { sidebar: {
@ -150,24 +66,6 @@ export const useAppStore = create<AppSlice>()(
rightExpanded: false, rightExpanded: false,
rightWidth: '400px', 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: { titlebar: {
backgroundColor: '#000000', backgroundColor: '#000000',
outOfView: false, outOfView: false,
@ -187,10 +85,6 @@ export const useAppStore = create<AppSlice>()(
export const useAppStoreActions = () => useAppStore((state) => state.actions); 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 useSidebarStore = () => useAppStore((state) => state.sidebar);
export const useSidebarRightExpanded = () => useAppStore((state) => state.sidebar.rightExpanded); export const useSidebarRightExpanded = () => useAppStore((state) => state.sidebar.rightExpanded);

View file

@ -4,7 +4,7 @@ import create from 'zustand';
import { devtools, persist } from 'zustand/middleware'; import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer'; import { immer } from 'zustand/middleware/immer';
import { AlbumListSort, SortOrder } from '/@/renderer/api/types'; import { AlbumListSort, SortOrder } from '/@/renderer/api/types';
import { useAppStore } from '/@/renderer/store/app.store'; import { useAlbumStore } from '/@/renderer/store/album.store';
import { ServerListItem } from '/@/renderer/types'; import { ServerListItem } from '/@/renderer/types';
export interface AuthState { export interface AuthState {
@ -45,15 +45,10 @@ export const useAuthStore = create<AuthSlice>()(
state.currentServer = server; state.currentServer = server;
if (server) { if (server) {
useAppStore.getState().actions.setPage('albums', { useAlbumStore.getState().actions.setFilters({
list: { musicFolderId: undefined,
...useAppStore.getState().albums.list, sortBy: AlbumListSort.RECENTLY_ADDED,
filter: { sortOrder: SortOrder.ASC,
...useAppStore.getState().albums.list.filter,
sortBy: AlbumListSort.RECENTLY_ADDED,
sortOrder: SortOrder.ASC,
},
},
}); });
} }
}); });

View file

@ -1,3 +1,5 @@
export * from './auth.store'; export * from './auth.store';
export * from './player.store'; export * from './player.store';
export * from './app.store'; export * from './app.store';
export * from './album.store';
export * from './song.store';

View file

@ -6,8 +6,8 @@ import create from 'zustand';
import { devtools, persist } from 'zustand/middleware'; import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer'; import { immer } from 'zustand/middleware/immer';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { Song } from '/@/renderer/api/types'; import { QueueSong, Song } from '/@/renderer/api/types';
import { QueueSong, PlayerStatus, PlayerRepeat, PlayerShuffle, Play } from '/@/renderer/types'; import { PlayerStatus, PlayerRepeat, PlayerShuffle, Play } from '/@/renderer/types';
export interface PlayerState { export interface PlayerState {
current: { current: {

View file

@ -0,0 +1,106 @@
import merge from 'lodash/merge';
import create from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
import { SongListArgs, SongListSort, SortOrder } from '/@/renderer/api/types';
import { DataTableProps } from '/@/renderer/store/settings.store';
import { CardDisplayType, TableColumn } from '/@/renderer/types';
type TableProps = {
scrollOffset: number;
} & DataTableProps;
type ListProps<T> = {
display: CardDisplayType;
filter: T;
table: TableProps;
};
type AlbumListFilter = Omit<SongListArgs['query'], 'startIndex' | 'limit'>;
interface SongState {
list: ListProps<AlbumListFilter>;
}
export interface SongSlice extends SongState {
actions: {
setFilters: (data: Partial<AlbumListFilter>) => void;
setStore: (data: Partial<SongSlice>) => void;
};
}
export const useSongStore = create<SongSlice>()(
persist(
devtools(
immer((set, get) => ({
actions: {
setFilters: (data) => {
set((state) => {
state.list.filter = { ...state.list.filter, ...data };
});
},
setStore: (data) => {
set({ ...get(), ...data });
},
},
list: {
display: CardDisplayType.TABLE,
filter: {
musicFolderId: undefined,
sortBy: SongListSort.RECENTLY_ADDED,
sortOrder: SortOrder.ASC,
},
table: {
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,
scrollOffset: 0,
},
},
})),
{ name: 'store_song' },
),
{
merge: (persistedState, currentState) => {
return merge(currentState, persistedState);
},
name: 'store_song',
version: 1,
},
),
);
export const useSongStoreActions = () => useSongStore((state) => state.actions);
export const useSetSongStore = () => useSongStore((state) => state.actions.setStore);
export const useSongFilters = () => {
return useSongStore((state) => [state.list.filter, state.actions.setFilters]);
};
export const useSongListStore = () => useSongStore((state) => state.list);

View file

@ -1,4 +1,3 @@
import { Song } from '/@/renderer/api/types';
import { AppRoute } from '/@/renderer/router/routes'; import { AppRoute } from '/@/renderer/router/routes';
export type RouteSlug = { export type RouteSlug = {
@ -22,6 +21,7 @@ export type CardRow = {
export enum CardDisplayType { export enum CardDisplayType {
CARD = 'card', CARD = 'card',
POSTER = 'poster', POSTER = 'poster',
TABLE = 'table',
} }
export enum ListDisplayType { export enum ListDisplayType {
@ -150,8 +150,6 @@ export enum TableColumn {
YEAR = 'releaseYear', YEAR = 'releaseYear',
} }
export type QueueSong = Song & UniqueId;
export type PlayQueueAddOptions = { export type PlayQueueAddOptions = {
// byData?: any[]; // byData?: any[];
byItemType: { byItemType: {