diff --git a/apps/readest-app/src/app/library/page.tsx b/apps/readest-app/src/app/library/page.tsx index e461d2dd..060f46ef 100644 --- a/apps/readest-app/src/app/library/page.tsx +++ b/apps/readest-app/src/app/library/page.tsx @@ -34,6 +34,7 @@ import { useTheme } from '@/hooks/useTheme'; import { useUICSS } from '@/hooks/useUICSS'; import { useDemoBooks } from './hooks/useDemoBooks'; import { useBooksSync } from './hooks/useBooksSync'; +import { useBookDataStore } from '@/store/bookDataStore'; import { useScreenWakeLock } from '@/hooks/useScreenWakeLock'; import { useOpenWithBooks } from '@/hooks/useOpenWithBooks'; import { SelectedFile, useFileSelector } from '@/hooks/useFileSelector'; @@ -87,6 +88,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP const _ = useTranslation(); const { selectFiles } = useFileSelector(appService, _); const { safeAreaInsets: insets, isRoundedWindow } = useThemeStore(); + const { clearBookData } = useBookDataStore(); const { settings, setSettings, saveSettings } = useSettingsStore(); const { isSettingsDialogOpen, setSettingsDialogOpen } = useSettingsStore(); const [showCatalogManager, setShowCatalogManager] = useState(false); @@ -531,6 +533,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP try { await appService?.deleteBook(book, deleteAction); await updateBook(envConfig, book); + clearBookData(book.hash); if (syncBooks) pushLibrary(); eventDispatcher.dispatch('toast', { type: 'info', diff --git a/apps/readest-app/src/components/metadata/BookDetailModal.tsx b/apps/readest-app/src/components/metadata/BookDetailModal.tsx index 60e67ac1..64a3718a 100644 --- a/apps/readest-app/src/components/metadata/BookDetailModal.tsx +++ b/apps/readest-app/src/components/metadata/BookDetailModal.tsx @@ -5,7 +5,6 @@ import { Book } from '@/types/book'; import { BookMetadata } from '@/libs/document'; import { useEnv } from '@/context/EnvContext'; import { useThemeStore } from '@/store/themeStore'; -import { useSettingsStore } from '@/store/settingsStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useMetadataEdit } from './useMetadataEdit'; import { DeleteAction } from '@/types/system'; @@ -46,14 +45,13 @@ const BookDetailModal: React.FC = ({ handleBookMetadataUpdate, }) => { const _ = useTranslation(); + const { envConfig } = useEnv(); const { safeAreaInsets } = useThemeStore(); const [loading, setLoading] = useState(false); const [activeDeleteAction, setActiveDeleteAction] = useState(null); const [editMode, setEditMode] = useState(false); const [bookMeta, setBookMeta] = useState(null); const [fileSize, setFileSize] = useState(null); - const { envConfig } = useEnv(); - const { settings } = useSettingsStore(); // Initialize metadata edit hook const { @@ -97,7 +95,7 @@ const BookDetailModal: React.FC = ({ const fetchBookDetails = async () => { const appService = await envConfig.getAppService(); try { - const details = book.metadata || (await appService.fetchBookDetails(book, settings)); + const details = book.metadata || (await appService.fetchBookDetails(book)); setBookMeta(details); const size = await appService.getBookFileSize(book); setFileSize(size); diff --git a/apps/readest-app/src/components/settings/LangPanel.tsx b/apps/readest-app/src/components/settings/LangPanel.tsx index e1fca07d..f65c111d 100644 --- a/apps/readest-app/src/components/settings/LangPanel.tsx +++ b/apps/readest-app/src/components/settings/LangPanel.tsx @@ -19,7 +19,8 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset const { token } = useAuth(); const { envConfig } = useEnv(); const { settings, applyUILanguage } = useSettingsStore(); - const { getViewSettings, setViewSettings, recreateViewer } = useReaderStore(); + const { getView, getViewSettings, setViewSettings, recreateViewer } = useReaderStore(); + const view = getView(bookKey); const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; const [uiLanguage, setUILanguage] = useState(viewSettings.uiLanguage); @@ -191,7 +192,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset bookKey, 'replaceQuotationMarks', replaceQuotationMarks, - true, + false, false, ).then(() => { recreateViewer(envConfig, bookKey); @@ -231,7 +232,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset bookKey, 'convertChineseVariant', convertChineseVariant, - true, + false, false, ).then(() => { recreateViewer(envConfig, bookKey); @@ -268,6 +269,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset className='toggle' checked={translationEnabled} onChange={() => setTranslationEnabled(!translationEnabled)} + disabled={!bookKey} /> @@ -311,7 +313,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset - {isCJKEnv() && ( + {(isCJKEnv() || view?.language.isCJK) && (

{_('Punctuation')}

@@ -333,7 +335,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset
)} - {isCJKEnv() && ( + {(isCJKEnv() || view?.language.isCJK) && (

{_('Convert Simplified and Traditional Chinese')}

diff --git a/apps/readest-app/src/services/appService.ts b/apps/readest-app/src/services/appService.ts index 8e569e21..bb99cad8 100644 --- a/apps/readest-app/src/services/appService.ts +++ b/apps/readest-app/src/services/appService.ts @@ -668,7 +668,7 @@ export abstract class BaseAppService implements AppService { return null; } - async loadBookContent(book: Book, settings: SystemSettings): Promise { + async loadBookContent(book: Book): Promise { let file: File; const fp = getLocalBookFilename(book); if (await this.fs.exists(fp, 'Books')) { @@ -692,7 +692,7 @@ export abstract class BaseAppService implements AppService { throw new Error(BOOK_FILE_NOT_FOUND_ERROR); } } - return { book, file, config: await this.loadBookConfig(book, settings) }; + return { book, file }; } async loadBookConfig(book: Book, settings: SystemSettings): Promise { @@ -711,13 +711,13 @@ export abstract class BaseAppService implements AppService { } } - async fetchBookDetails(book: Book, settings: SystemSettings) { + async fetchBookDetails(book: Book) { const fp = getLocalBookFilename(book); if (!(await this.fs.exists(fp, 'Books')) && book.uploadedAt) { await this.downloadBook(book); } - const { file } = (await this.loadBookContent(book, settings)) as BookContent; - const bookDoc = (await new DocumentLoader(file).open()).book as BookDoc; + const { file } = await this.loadBookContent(book); + const bookDoc = (await new DocumentLoader(file).open()).book; const f = file as ClosableFile; if (f && f.close) { await f.close(); diff --git a/apps/readest-app/src/store/bookDataStore.ts b/apps/readest-app/src/store/bookDataStore.ts index 03b77d4b..85a93e02 100644 --- a/apps/readest-app/src/store/bookDataStore.ts +++ b/apps/readest-app/src/store/bookDataStore.ts @@ -27,6 +27,7 @@ interface BookDataState { ) => void; updateBooknotes: (key: string, booknotes: BookNote[]) => BookConfig | undefined; getBookData: (keyOrId: string) => BookData | null; + clearBookData: (keyOrId: string) => void; } export const useBookDataStore = create((set, get) => ({ @@ -35,6 +36,16 @@ export const useBookDataStore = create((set, get) => ({ const id = keyOrId.split('-')[0]!; return get().booksData[id] || null; }, + clearBookData: (keyOrId: string) => { + const id = keyOrId.split('-')[0]!; + set((state) => { + const newBooksData = { ...state.booksData }; + delete newBooksData[id]; + return { + booksData: newBooksData, + }; + }); + }, getConfig: (key: string | null) => { if (!key) return null; const id = key.split('-')[0]!; diff --git a/apps/readest-app/src/store/readerStore.ts b/apps/readest-app/src/store/readerStore.ts index e5f06c33..6a177bcd 100644 --- a/apps/readest-app/src/store/readerStore.ts +++ b/apps/readest-app/src/store/readerStore.ts @@ -144,51 +144,53 @@ export const useReaderStore = create((set, get) => ({ }, })); try { + const appService = await envConfig.getAppService(); const { settings } = useSettingsStore.getState(); - if (!bookData || reload) { - const appService = await envConfig.getAppService(); - const { library } = useLibraryStore.getState(); - const book = library.find((b) => b.hash === id); - if (!book) { - throw new Error('Book not found'); - } - const content = (await appService.loadBookContent(book, settings)) as BookContent; - const { file, config } = content; - console.log('Loading book', key); - const { book: bookDoc } = await new DocumentLoader(file).open(); - await updateToc( - bookDoc, - config.viewSettings?.sortedTOC ?? false, - config.viewSettings?.convertChineseVariant ?? 'none', - ); - if (!bookDoc.metadata.title) { - bookDoc.metadata.title = getBaseFilename(file.name); - } - book.sourceTitle = formatTitle(bookDoc.metadata.title); - // Correct language codes mistakenly set with language names - if (typeof bookDoc.metadata?.language === 'string') { - if (bookDoc.metadata.language in SUPPORTED_LANGNAMES) { - bookDoc.metadata.language = SUPPORTED_LANGNAMES[bookDoc.metadata.language]!; - } - } - // Set the book's language for formerly imported books, newly imported books have this field set - const primaryLanguage = getPrimaryLanguage(bookDoc.metadata.language); - book.primaryLanguage = book.primaryLanguage ?? primaryLanguage; - book.metadata = book.metadata ?? bookDoc.metadata; - // TODO: uncomment this when we can ensure metaHash is correctly generated for all books - // book.metaHash = book.metaHash ?? getMetadataHash(bookDoc.metadata); - book.metaHash = getMetadataHash(bookDoc.metadata); - - const isFixedLayout = FIXED_LAYOUT_FORMATS.has(book.format); - useBookDataStore.setState((state) => ({ - booksData: { - ...state.booksData, - [id]: { id, book, file, config, bookDoc, isFixedLayout }, - }, - })); + const { library } = useLibraryStore.getState(); + const book = library.find((b) => b.hash === id); + if (!book) { + throw new Error('Book not found'); } - const booksData = useBookDataStore.getState().booksData; - const config = booksData[id]?.config as BookConfig; + let bookDoc = bookData?.bookDoc; + let file = bookData?.file; + if (!bookDoc || !file || reload) { + const content = (await appService.loadBookContent(book)) as BookContent; + file = content.file; + console.log('Loading book', key); + const doc = await new DocumentLoader(file).open(); + bookDoc = doc.book; + } + const config = await appService.loadBookConfig(book, settings); + await updateToc( + bookDoc, + config.viewSettings?.sortedTOC ?? false, + config.viewSettings?.convertChineseVariant ?? 'none', + ); + if (!bookDoc.metadata.title) { + bookDoc.metadata.title = getBaseFilename(file.name); + } + book.sourceTitle = formatTitle(bookDoc.metadata.title); + // Correct language codes mistakenly set with language names + if (typeof bookDoc.metadata?.language === 'string') { + if (bookDoc.metadata.language in SUPPORTED_LANGNAMES) { + bookDoc.metadata.language = SUPPORTED_LANGNAMES[bookDoc.metadata.language]!; + } + } + // Set the book's language for formerly imported books, newly imported books have this field set + const primaryLanguage = getPrimaryLanguage(bookDoc.metadata.language); + book.primaryLanguage = book.primaryLanguage ?? primaryLanguage; + book.metadata = book.metadata ?? bookDoc.metadata; + // TODO: uncomment this when we can ensure metaHash is correctly generated for all books + // book.metaHash = book.metaHash ?? getMetadataHash(bookDoc.metadata); + book.metaHash = getMetadataHash(bookDoc.metadata); + + const isFixedLayout = FIXED_LAYOUT_FORMATS.has(book.format); + useBookDataStore.setState((state) => ({ + booksData: { + ...state.booksData, + [id]: { id, book, file, config, bookDoc, isFixedLayout }, + }, + })); const configViewSettings = config.viewSettings!; const globalViewSettings = settings.globalViewSettings; set((state) => ({ diff --git a/apps/readest-app/src/types/book.ts b/apps/readest-app/src/types/book.ts index e384352d..4912e241 100644 --- a/apps/readest-app/src/types/book.ts +++ b/apps/readest-app/src/types/book.ts @@ -293,5 +293,4 @@ export interface BooksGroup { export interface BookContent { book: Book; file: File; - config: BookConfig; } diff --git a/apps/readest-app/src/types/system.ts b/apps/readest-app/src/types/system.ts index 9cd5e8ac..5677e45f 100644 --- a/apps/readest-app/src/types/system.ts +++ b/apps/readest-app/src/types/system.ts @@ -112,9 +112,9 @@ export interface AppService { isBookAvailable(book: Book): Promise; getBookFileSize(book: Book): Promise; loadBookConfig(book: Book, settings: SystemSettings): Promise; - fetchBookDetails(book: Book, settings: SystemSettings): Promise; + fetchBookDetails(book: Book): Promise; saveBookConfig(book: Book, config: BookConfig, settings?: SystemSettings): Promise; - loadBookContent(book: Book, settings: SystemSettings): Promise; + loadBookContent(book: Book): Promise; loadLibraryBooks(): Promise; saveLibraryBooks(books: Book[]): Promise; getCoverImageUrl(book: Book): string;