import type { ItemListStateItem } from '/@/renderer/components/item-list/helpers/item-list-state'; import type { LibraryItem } from '/@/shared/types/domain-types'; import merge from 'lodash/merge'; import { devtools, persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; import { createWithEqualityFn } from 'zustand/traditional'; import { AlbumListSort, SortOrder } from '/@/shared/types/domain-types'; import { Platform } from '/@/shared/types/types'; export interface AppSlice extends AppState { actions: { setAlbumArtistDetailGroupingType: (groupingType: 'all' | 'primary') => void; setAlbumArtistDetailSort: (sortBy: AlbumListSort, sortOrder: SortOrder) => void; setAlbumArtistIdsMode: (mode: 'and' | 'or') => void; setAlbumArtistSelectMode: (mode: 'multi' | 'single') => void; setAppStore: (data: Partial) => void; setArtistIdsMode: (mode: 'and' | 'or') => void; setArtistSelectMode: (mode: 'multi' | 'single') => void; setGenreIdsMode: (mode: 'and' | 'or') => void; setGenreSelectMode: (mode: 'multi' | 'single') => void; setGlobalExpanded: (value: GlobalExpandedState | null) => void; setPageSidebar: (key: string, value: boolean) => void; setPrivateMode: (enabled: boolean) => void; setShowTimeRemaining: (enabled: boolean) => void; setSideBar: (options: Partial) => void; setTitleBar: (options: Partial) => void; }; } export interface AppState { albumArtistDetailSort: { groupingType: 'all' | 'primary'; sortBy: AlbumListSort; sortOrder: SortOrder; }; albumArtistIdsMode: 'and' | 'or'; albumArtistSelectMode: 'multi' | 'single'; artistIdsMode: 'and' | 'or'; artistSelectMode: 'multi' | 'single'; commandPalette: CommandPaletteProps; genreIdsMode: 'and' | 'or'; genreSelectMode: 'multi' | 'single'; globalExpanded: GlobalExpandedState | null; isReorderingQueue: boolean; pageSidebar: Record; platform: Platform; privateMode: boolean; showTimeRemaining: boolean; sidebar: SidebarProps; titlebar: TitlebarProps; } export interface GlobalExpandedState { item: ItemListStateItem; itemType: LibraryItem; } type CommandPaletteProps = { close: () => void; open: () => void; opened: boolean; toggle: () => void; }; type SidebarProps = { collapsed: boolean; expanded: string[]; image: boolean; leftWidth: string; rightExpanded: boolean; rightWidth: string; }; type TitlebarProps = { backgroundColor: string; outOfView: boolean; }; export const useAppStore = createWithEqualityFn()( persist( devtools( immer((set, get) => ({ actions: { setAlbumArtistDetailGroupingType: (groupingType) => { set((state) => { state.albumArtistDetailSort.groupingType = groupingType; }); }, setAlbumArtistDetailSort: (sortBy, sortOrder) => { set((state) => { state.albumArtistDetailSort = { ...state.albumArtistDetailSort, sortBy, sortOrder, }; }); }, setAlbumArtistIdsMode: (mode) => { set((state) => { state.albumArtistIdsMode = mode; }); }, setAlbumArtistSelectMode: (mode) => { set((state) => { state.albumArtistSelectMode = mode; }); }, setAppStore: (data) => { set({ ...get(), ...data }); }, setArtistIdsMode: (mode) => { set((state) => { state.artistIdsMode = mode; }); }, setArtistSelectMode: (mode) => { set((state) => { state.artistSelectMode = mode; }); }, setGenreIdsMode: (mode) => { set((state) => { state.genreIdsMode = mode; }); }, setGenreSelectMode: (mode) => { set((state) => { state.genreSelectMode = mode; }); }, setGlobalExpanded: (value) => { set((state) => { state.globalExpanded = value; }); }, setPageSidebar: (key, value) => { set((state) => { state.pageSidebar[key] = value; }); }, setPrivateMode: (privateMode) => { set((state) => { state.privateMode = privateMode; }); }, setShowTimeRemaining: (showTimeRemaining) => { set((state) => { state.showTimeRemaining = showTimeRemaining; }); }, setSideBar: (options) => { set((state) => { state.sidebar = { ...state.sidebar, ...options }; }); }, setTitleBar: (options) => { set((state) => { state.titlebar = { ...state.titlebar, ...options }; }); }, }, albumArtistDetailSort: { groupingType: 'primary', sortBy: AlbumListSort.RELEASE_DATE, sortOrder: SortOrder.DESC, }, albumArtistIdsMode: 'and', albumArtistSelectMode: 'multi', artistIdsMode: 'and', artistSelectMode: 'multi', commandPalette: { close: () => { set((state) => { state.commandPalette.opened = false; }); }, open: () => { set((state) => { state.commandPalette.opened = true; }); }, opened: false, toggle: () => { set((state) => { state.commandPalette.opened = !state.commandPalette.opened; }); }, }, genreIdsMode: 'and', genreSelectMode: 'multi', globalExpanded: null, isReorderingQueue: false, pageSidebar: { album: true, song: true, }, platform: Platform.WINDOWS, privateMode: false, showTimeRemaining: false, sidebar: { collapsed: false, expanded: [], image: false, leftWidth: '400px', rightExpanded: false, rightWidth: '600px', }, titlebar: { backgroundColor: '#000000', outOfView: false, }, })), { name: 'store_app' }, ), { merge: (persistedState, currentState) => { return merge(currentState, persistedState); }, migrate: (persistedState, version) => { if (version <= 2) { return {} as AppState; } return persistedState; }, name: 'store_app', partialize: (state) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars -- ignore non-persisted state const { globalExpanded: _, ...rest } = state; return rest; }, version: 4, }, ), ); export const useAppStoreActions = () => useAppStore((state) => state.actions); 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); export const useCommandPalette = () => useAppStore((state) => state.commandPalette); export const usePageSidebar = (key: string): [boolean, (value: boolean) => void] => { const isOpen = useAppStore((state) => state.pageSidebar[key] ?? false); const setPageSidebar = useAppStore((state) => state.actions.setPageSidebar); const setIsOpen = (value: boolean) => { setPageSidebar(key, value); }; return [isOpen, setIsOpen]; }; export const useGlobalExpanded = () => useAppStore((state) => state.globalExpanded); export const useSetGlobalExpanded = () => useAppStore((state) => state.actions.setGlobalExpanded); export const useGlobalExpandedState = () => { const globalExpanded = useGlobalExpanded(); const setGlobalExpanded = useSetGlobalExpanded(); const clearGlobalExpanded = () => setGlobalExpanded(null); return { clearGlobalExpanded, globalExpanded, setGlobalExpanded }; };