Files
readest/apps/readest-app/src/app/reader/components/Reader.tsx
T

150 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import clsx from 'clsx';
import * as React from 'react';
import { useEffect, Suspense } from 'react';
import { useRouter } from 'next/navigation';
import { useEnv } from '@/context/EnvContext';
import { useTheme } from '@/hooks/useTheme';
import { useLibrary } from '@/hooks/useLibrary';
import { useThemeStore } from '@/store/themeStore';
import { useReaderStore } from '@/store/readerStore';
import { useSidebarStore } from '@/store/sidebarStore';
import { useNotebookStore } from '@/store/notebookStore';
import { useSettingsStore } from '@/store/settingsStore';
import { useDeviceControlStore } from '@/store/deviceStore';
import { useScreenWakeLock } from '@/hooks/useScreenWakeLock';
import { eventDispatcher } from '@/utils/event';
import { interceptWindowOpen } from '@/utils/open';
import { mountAdditionalFonts } from '@/styles/fonts';
import { isTauriAppPlatform } from '@/services/environment';
import { getSysFontsList, setSystemUIVisibility } from '@/utils/bridge';
import { AboutWindow } from '@/components/AboutWindow';
import { UpdaterWindow } from '@/components/UpdaterWindow';
import { KOSyncSettingsWindow } from './KOSyncSettings';
import { Toast } from '@/components/Toast';
import { getLocale } from '@/utils/misc';
import { initDayjs } from '@/utils/time';
import ReaderContent from './ReaderContent';
/*
Z-Index Layering Guide:
---------------------------------
99 Window Border (Linux only)
• Ensures the border stays on top of all UI elements.
50 Loading Progress / Toast Notifications / Dialogs / Popups
• Includes Settings, About, Updater, KOSync dialogs and Annotation popups.
45 Sidebar / Notebook (Unpinned)
• Floats above the content but below global dialogs.
40 TTS Bar
• Mini controls for TTS playback on top of the TTS Control.
30 TTS Control
• Persistent TTS icon/panel.
20 Menu / Sidebar / Notebook (Pinned)
• Docked navigation or note views.
10 Headerbar / Footbar / Ribbon
• Top toolbar, bottom footbar and ribbon elements.
0 Base Content
• Main reading area or background content.
*/
const Reader: React.FC<{ ids?: string }> = ({ ids }) => {
const router = useRouter();
const { appService } = useEnv();
const { hoveredBookKey, getView } = useReaderStore();
const { settings } = useSettingsStore();
const { sideBarBookKey } = useSidebarStore();
const { isSideBarVisible, getIsSideBarVisible, setSideBarVisible } = useSidebarStore();
const { isNotebookVisible, getIsNotebookVisible, setNotebookVisible } = useNotebookStore();
const { isDarkMode, systemUIAlwaysHidden, isRoundedWindow } = useThemeStore();
const { showSystemUI, dismissSystemUI } = useThemeStore();
const { acquireBackKeyInterception, releaseBackKeyInterception } = useDeviceControlStore();
const { libraryLoaded } = useLibrary();
useTheme({ systemUIVisible: settings.alwaysShowStatusBar, appThemeColor: 'base-100' });
useScreenWakeLock(settings.screenWakeLock);
useEffect(() => {
mountAdditionalFonts(document);
interceptWindowOpen();
if (isTauriAppPlatform()) {
setTimeout(getSysFontsList, 3000);
}
initDayjs(getLocale());
}, []);
const handleKeyDown = (event: CustomEvent) => {
const view = getView(sideBarBookKey!);
if (event.detail.keyName === 'Back') {
if (getIsSideBarVisible()) {
setSideBarVisible(false);
} else if (getIsNotebookVisible()) {
setNotebookVisible(false);
} else if (view?.history.canGoBack) {
view.history.back();
} else {
eventDispatcher.dispatch('close-reader');
router.back();
}
return true;
}
return false;
};
useEffect(() => {
if (!appService?.isAndroidApp) return;
acquireBackKeyInterception();
return () => {
releaseBackKeyInterception();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [appService?.isAndroidApp]);
useEffect(() => {
if (appService?.isAndroidApp) {
eventDispatcher.onSync('native-key-down', handleKeyDown);
}
return () => {
if (appService?.isAndroidApp) {
eventDispatcher.offSync('native-key-down', handleKeyDown);
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [appService?.isAndroidApp, sideBarBookKey, isSideBarVisible, isNotebookVisible]);
useEffect(() => {
if (!appService?.isMobileApp) return;
const systemUIVisible = !!hoveredBookKey || settings.alwaysShowStatusBar;
const visible = !!(systemUIVisible && !systemUIAlwaysHidden);
setSystemUIVisibility({ visible, darkMode: isDarkMode });
if (visible) {
showSystemUI();
} else {
dismissSystemUI();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hoveredBookKey]);
return libraryLoaded && settings.globalReadSettings ? (
<div
className={clsx(
'reader-page bg-base-100 text-base-content full-height select-none overflow-hidden',
appService?.hasRoundedWindow && isRoundedWindow && 'window-border rounded-window',
)}
>
<Suspense fallback={<div className='full-height'></div>}>
<ReaderContent ids={ids} settings={settings} />
<AboutWindow />
<UpdaterWindow />
<KOSyncSettingsWindow />
<Toast />
</Suspense>
</div>
) : (
<div className={clsx('full-height', !appService?.isLinuxApp && 'bg-base-100')}></div>
);
};
export default Reader;