forked from akai/readest
114 lines
3.4 KiB
TypeScript
114 lines
3.4 KiB
TypeScript
import { create } from 'zustand';
|
|
import { SystemSettings } from '@/types/settings';
|
|
import { Book, BookConfig, BookNote } from '@/types/book';
|
|
import { EnvConfigType } from '@/services/environment';
|
|
import { BookDoc } from '@/libs/document';
|
|
import { useLibraryStore } from './libraryStore';
|
|
|
|
interface BookData {
|
|
/* Persistent data shared with different views of the same book */
|
|
id: string;
|
|
book: Book | null;
|
|
file: File | null;
|
|
config: BookConfig | null;
|
|
bookDoc: BookDoc | null;
|
|
isFixedLayout: boolean;
|
|
}
|
|
|
|
interface BookDataState {
|
|
booksData: { [id: string]: BookData };
|
|
getConfig: (key: string | null) => BookConfig | null;
|
|
setConfig: (key: string, partialConfig: Partial<BookConfig>) => void;
|
|
saveConfig: (
|
|
envConfig: EnvConfigType,
|
|
bookKey: string,
|
|
config: BookConfig,
|
|
settings: SystemSettings,
|
|
) => void;
|
|
updateBooknotes: (key: string, booknotes: BookNote[]) => BookConfig | undefined;
|
|
getBookData: (keyOrId: string) => BookData | null;
|
|
}
|
|
|
|
export const useBookDataStore = create<BookDataState>((set, get) => ({
|
|
booksData: {},
|
|
getBookData: (keyOrId: string) => {
|
|
const id = keyOrId.split('-')[0]!;
|
|
return get().booksData[id] || null;
|
|
},
|
|
getConfig: (key: string | null) => {
|
|
if (!key) return null;
|
|
const id = key.split('-')[0]!;
|
|
return get().booksData[id]?.config || null;
|
|
},
|
|
setConfig: (key: string, partialConfig: Partial<BookConfig>) => {
|
|
set((state: BookDataState) => {
|
|
const id = key.split('-')[0]!;
|
|
const config = (state.booksData[id]?.config || null) as BookConfig;
|
|
if (!config) {
|
|
console.warn('No config found for book', id);
|
|
return state;
|
|
}
|
|
Object.assign(config, partialConfig);
|
|
return {
|
|
booksData: {
|
|
...state.booksData,
|
|
[id]: {
|
|
...state.booksData[id]!,
|
|
config,
|
|
},
|
|
},
|
|
};
|
|
});
|
|
},
|
|
saveConfig: async (
|
|
envConfig: EnvConfigType,
|
|
bookKey: string,
|
|
config: BookConfig,
|
|
settings: SystemSettings,
|
|
) => {
|
|
const appService = await envConfig.getAppService();
|
|
const { library, setLibrary } = useLibraryStore.getState();
|
|
const bookIndex = library.findIndex((b) => b.hash === bookKey.split('-')[0]);
|
|
if (bookIndex == -1) return;
|
|
const book = library.splice(bookIndex, 1)[0]!;
|
|
book.progress = config.progress;
|
|
book.updatedAt = Date.now();
|
|
book.downloadedAt = book.downloadedAt || Date.now();
|
|
library.unshift(book);
|
|
setLibrary([...library]);
|
|
config.updatedAt = Date.now();
|
|
await appService.saveBookConfig(book, config, settings);
|
|
await appService.saveLibraryBooks(library);
|
|
},
|
|
updateBooknotes: (key: string, booknotes: BookNote[]) => {
|
|
let updatedConfig: BookConfig | undefined;
|
|
set((state) => {
|
|
const id = key.split('-')[0]!;
|
|
const book = state.booksData[id];
|
|
if (!book) return state;
|
|
const dedupedBooknotes = Array.from(
|
|
new Map(booknotes.map((item) => [`${item.id}-${item.type}-${item.cfi}`, item])).values(),
|
|
);
|
|
updatedConfig = {
|
|
...book.config,
|
|
updatedAt: Date.now(),
|
|
booknotes: dedupedBooknotes,
|
|
};
|
|
return {
|
|
booksData: {
|
|
...state.booksData,
|
|
[id]: {
|
|
...book,
|
|
config: {
|
|
...book.config,
|
|
updatedAt: Date.now(),
|
|
booknotes: dedupedBooknotes,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|
|
return updatedConfig;
|
|
},
|
|
}));
|