From 123293dc0eacf9c438e61940811b18e48cac5fca Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 29 Oct 2025 10:17:17 +0800 Subject: [PATCH] fix: fixed crash when switching allow script (#2351) --- .../src/app/reader/components/BooksGrid.tsx | 7 ++-- .../app/reader/components/FoliateViewer.tsx | 1 - .../src/components/settings/ControlPanel.tsx | 8 +++-- .../src/components/settings/LangPanel.tsx | 17 +++++----- .../src/components/settings/LayoutPanel.tsx | 8 ++--- apps/readest-app/src/store/readerStore.ts | 34 +++++++++++++++++-- apps/readest-app/src/utils/reload.ts | 5 --- 7 files changed, 55 insertions(+), 25 deletions(-) delete mode 100644 apps/readest-app/src/utils/reload.ts diff --git a/apps/readest-app/src/app/reader/components/BooksGrid.tsx b/apps/readest-app/src/app/reader/components/BooksGrid.tsx index 457edd8b..474213f2 100644 --- a/apps/readest-app/src/app/reader/components/BooksGrid.tsx +++ b/apps/readest-app/src/app/reader/components/BooksGrid.tsx @@ -85,12 +85,14 @@ const BooksGrid: React.FC = ({ bookKeys, onCloseBook }) => { const config = getConfig(bookKey); const progress = getProgress(bookKey); const viewSettings = getViewSettings(bookKey); + const viewState = getViewState(bookKey); const gridInsets = calcGridInsets(index, bookKeys.length); const { book, bookDoc } = bookData || {}; - if (!book || !config || !bookDoc || !viewSettings) return null; + if (!book || !config || !bookDoc || !viewSettings || !viewState) return null; const { section, pageinfo, timeinfo, sectionLabel } = progress || {}; - const isBookmarked = getViewState(bookKey)?.ribbonVisible; + const isBookmarked = viewState.ribbonVisible; + const viewerKey = viewState.viewerKey; const horizontalGapPercent = viewSettings.gapPercent; const viewInsets = getViewInsets(viewSettings); const contentInsets = { @@ -123,6 +125,7 @@ const BooksGrid: React.FC = ({ bookKeys, onCloseBook }) => { gridInsets={gridInsets} /> = ({ bookKey, onRegisterReset }) => { const _ = useTranslation(); const { envConfig, appService } = useEnv(); - const { getView, getViewSettings } = useReaderStore(); + const { getView, getViewSettings, recreateViewer } = useReaderStore(); const { getBookData } = useBookDataStore(); const { settings } = useSettingsStore(); const { applyEinkMode } = useEinkMode(); @@ -144,7 +144,9 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes useEffect(() => { if (viewSettings.allowScript === allowScript) return; saveViewSettings(envConfig, bookKey, 'allowScript', allowScript, true, false); - saveAndReload(); + setTimeout(() => { + recreateViewer(envConfig, bookKey); + }, RELOAD_BEFORE_SAVED_TIMEOUT_MS); // eslint-disable-next-line react-hooks/exhaustive-deps }, [allowScript]); diff --git a/apps/readest-app/src/components/settings/LangPanel.tsx b/apps/readest-app/src/components/settings/LangPanel.tsx index d262fac4..60f1300b 100644 --- a/apps/readest-app/src/components/settings/LangPanel.tsx +++ b/apps/readest-app/src/components/settings/LangPanel.tsx @@ -8,9 +8,12 @@ import { useSettingsStore } from '@/store/settingsStore'; import { saveViewSettings } from '@/helpers/settings'; import { getTranslators } from '@/services/translators'; import { useResetViewSettings } from '@/hooks/useResetSettings'; -import { TRANSLATED_LANGS, TRANSLATOR_LANGS } from '@/services/constants'; +import { + RELOAD_BEFORE_SAVED_TIMEOUT_MS, + TRANSLATED_LANGS, + TRANSLATOR_LANGS, +} from '@/services/constants'; import { SettingsPanelPanelProp } from './SettingsDialog'; -import { saveAndReload } from '@/utils/reload'; import Select from '@/components/Select'; const LangPanel: React.FC = ({ bookKey, onRegisterReset }) => { @@ -18,7 +21,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset const { token } = useAuth(); const { envConfig } = useEnv(); const { settings, applyUILanguage } = useSettingsStore(); - const { getViewSettings, setViewSettings } = useReaderStore(); + const { getViewSettings, setViewSettings, recreateViewer } = useReaderStore(); const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; const [uiLanguage, setUILanguage] = useState(viewSettings.uiLanguage); @@ -141,10 +144,8 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset useEffect(() => { if (translationEnabled === viewSettings.translationEnabled) return; saveViewSettings(envConfig, bookKey, 'translationEnabled', translationEnabled, true, false); - viewSettings.translationEnabled = translationEnabled; - setViewSettings(bookKey, { ...viewSettings }); - if (!showTranslateSource && !translationEnabled) { - saveAndReload(); + if (!showTranslateSource && translationEnabled) { + setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [translationEnabled]); @@ -152,7 +153,7 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset useEffect(() => { if (showTranslateSource === viewSettings.showTranslateSource) return; saveViewSettings(envConfig, bookKey, 'showTranslateSource', showTranslateSource, false, false); - saveAndReload(); + setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS); // eslint-disable-next-line react-hooks/exhaustive-deps }, [showTranslateSource]); diff --git a/apps/readest-app/src/components/settings/LayoutPanel.tsx b/apps/readest-app/src/components/settings/LayoutPanel.tsx index 2b26e679..210d12d2 100644 --- a/apps/readest-app/src/components/settings/LayoutPanel.tsx +++ b/apps/readest-app/src/components/settings/LayoutPanel.tsx @@ -12,12 +12,11 @@ import { useTranslation } from '@/hooks/useTranslation'; import { useResetViewSettings } from '@/hooks/useResetSettings'; import { isCJKEnv } from '@/utils/misc'; import { getStyles } from '@/utils/style'; -import { saveAndReload } from '@/utils/reload'; import { getMaxInlineSize } from '@/utils/config'; import { lockScreenOrientation } from '@/utils/bridge'; import { saveViewSettings } from '@/helpers/settings'; import { getBookDirFromWritingMode, getBookLangCode } from '@/utils/book'; -import { MIGHT_BE_RTL_LANGS } from '@/services/constants'; +import { MIGHT_BE_RTL_LANGS, RELOAD_BEFORE_SAVED_TIMEOUT_MS } from '@/services/constants'; import { SettingsPanelPanelProp } from './SettingsDialog'; import Select from '@/components/Select'; import NumberInput from './NumberInput'; @@ -26,7 +25,8 @@ const LayoutPanel: React.FC = ({ bookKey, onRegisterRese const _ = useTranslation(); const { envConfig, appService } = useEnv(); const { settings } = useSettingsStore(); - const { getView, getViewSettings, getGridInsets, setViewSettings } = useReaderStore(); + const { getView, getViewSettings, getGridInsets } = useReaderStore(); + const { setViewSettings, recreateViewer } = useReaderStore(); const { getBookData } = useBookDataStore(); const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; @@ -283,7 +283,7 @@ const LayoutPanel: React.FC = ({ bookKey, onRegisterRese (['horizontal-rl', 'vertical-rl'].includes(writingMode) || ['horizontal-rl', 'vertical-rl'].includes(prevWritingMode)) ) { - saveAndReload(); + setTimeout(() => recreateViewer(envConfig, bookKey), RELOAD_BEFORE_SAVED_TIMEOUT_MS); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [writingMode]); diff --git a/apps/readest-app/src/store/readerStore.ts b/apps/readest-app/src/store/readerStore.ts index 8f71910f..d359edf5 100644 --- a/apps/readest-app/src/store/readerStore.ts +++ b/apps/readest-app/src/store/readerStore.ts @@ -20,11 +20,13 @@ import { SUPPORTED_LANGNAMES } from '@/services/constants'; import { useSettingsStore } from './settingsStore'; import { useBookDataStore } from './bookDataStore'; import { useLibraryStore } from './libraryStore'; +import { uniqueId } from '@/utils/misc'; interface ViewState { /* Unique key for each book view */ key: string; view: FoliateView | null; + viewerKey: string; isPrimary: boolean; loading: boolean; inited: boolean; @@ -72,12 +74,14 @@ interface ReaderStore { id: string, key: string, isPrimary?: boolean, + reload?: boolean, ) => Promise; clearViewState: (key: string) => void; getViewState: (key: string) => ViewState | null; getGridInsets: (key: string) => Insets | null; setGridInsets: (key: string, insets: Insets | null) => void; setViewInited: (key: string, inited: boolean) => void; + recreateViewer: (envConfig: EnvConfigType, key: string) => void; } export const useReaderStore = create((set, get) => ({ @@ -110,7 +114,13 @@ export const useReaderStore = create((set, get) => ({ }); }, getViewState: (key: string) => get().viewStates[key] || null, - initViewState: async (envConfig: EnvConfigType, id: string, key: string, isPrimary = true) => { + initViewState: async ( + envConfig: EnvConfigType, + id: string, + key: string, + isPrimary = true, + reload = false, + ) => { const booksData = useBookDataStore.getState().booksData; const bookData = booksData[id]; set((state) => ({ @@ -119,6 +129,7 @@ export const useReaderStore = create((set, get) => ({ [key]: { key: '', view: null, + viewerKey: '', isPrimary: false, loading: true, inited: false, @@ -134,7 +145,7 @@ export const useReaderStore = create((set, get) => ({ })); try { const { settings } = useSettingsStore.getState(); - if (!bookData) { + if (!bookData || reload) { const appService = await envConfig.getAppService(); const { library } = useLibraryStore.getState(); const book = library.find((b) => b.hash === id); @@ -183,6 +194,7 @@ export const useReaderStore = create((set, get) => ({ ...state.viewStates[key], key, view: null, + viewerKey: `${key}-${uniqueId()}`, isPrimary, loading: false, inited: false, @@ -205,6 +217,7 @@ export const useReaderStore = create((set, get) => ({ ...state.viewStates[key], key: '', view: null, + viewerKey: '', isPrimary: false, loading: false, inited: false, @@ -378,4 +391,21 @@ export const useReaderStore = create((set, get) => ({ }, }, })), + + recreateViewer: (envConfig: EnvConfigType, key: string) => { + const id = key.split('-')[0]!; + get() + .initViewState(envConfig, id, key, true, true) + .then(() => { + set((state) => ({ + viewStates: { + ...state.viewStates, + [key]: { + ...state.viewStates[key]!, + viewerKey: `${key}-${uniqueId()}`, + }, + }, + })); + }); + }, })); diff --git a/apps/readest-app/src/utils/reload.ts b/apps/readest-app/src/utils/reload.ts deleted file mode 100644 index 32634531..00000000 --- a/apps/readest-app/src/utils/reload.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RELOAD_BEFORE_SAVED_TIMEOUT_MS } from '@/services/constants'; - -export const saveAndReload = async () => { - setTimeout(() => window.location.reload(), RELOAD_BEFORE_SAVED_TIMEOUT_MS); -};