diff --git a/apps/readest-app/src/app/library/components/LibraryHeader.tsx b/apps/readest-app/src/app/library/components/LibraryHeader.tsx index 6798b9cc..d91da5c1 100644 --- a/apps/readest-app/src/app/library/components/LibraryHeader.tsx +++ b/apps/readest-app/src/app/library/components/LibraryHeader.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import React, { useEffect, useRef } from 'react'; +import React, { useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { FaSearch } from 'react-icons/fa'; import { PiPlus } from 'react-icons/pi'; @@ -16,6 +16,7 @@ import WindowButtons from '@/components/WindowButtons'; import Dropdown from '@/components/Dropdown'; import SettingsMenu from './SettingsMenu'; import ImportMenu from './ImportMenu'; +import useShortcuts from '@/hooks/useShortcuts'; interface LibraryHeaderProps { isSelectMode: boolean; @@ -37,17 +38,9 @@ const LibraryHeader: React.FC = ({ const iconSize16 = useResponsiveSize(16); const iconSize20 = useResponsiveSize(20); - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (e.ctrlKey || e.shiftKey) { - onToggleSelectMode(); - } - }; - window.addEventListener('keydown', handleKeyDown); - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [onToggleSelectMode]); + useShortcuts({ + onToggleSelectMode, + }); const windowButtonVisible = appService?.hasWindowBar && !isTrafficLightVisible; const isInGroupView = !!searchParams?.get('group'); diff --git a/apps/readest-app/src/app/library/page.tsx b/apps/readest-app/src/app/library/page.tsx index 92d8c352..9bbb3a06 100644 --- a/apps/readest-app/src/app/library/page.tsx +++ b/apps/readest-app/src/app/library/page.tsx @@ -27,6 +27,8 @@ import { useSettingsStore } from '@/store/settingsStore'; import { usePullToRefresh } from '@/hooks/usePullToRefresh'; import { useDemoBooks } from './hooks/useDemoBooks'; import { useBooksSync } from './hooks/useBooksSync'; +import { useScreenWakeLock } from '@/hooks/useScreenWakeLock'; +import { tauriQuitApp } from '@/utils/window'; import { AboutWindow } from '@/components/AboutWindow'; import { Toast } from '@/components/Toast'; @@ -34,7 +36,7 @@ import Spinner from '@/components/Spinner'; import LibraryHeader from './components/LibraryHeader'; import Bookshelf from './components/Bookshelf'; import BookDetailModal from '@/components/BookDetailModal'; -import { useScreenWakeLock } from '@/hooks/useScreenWakeLock'; +import useShortcuts from '@/hooks/useShortcuts'; const LibraryPage = () => { const router = useRouter(); @@ -69,6 +71,14 @@ const LibraryPage = () => { usePullToRefresh(containerRef, pullLibrary); useScreenWakeLock(settings.screenWakeLock); + useShortcuts({ + onQuitApp: async () => { + if (isTauriAppPlatform()) { + await tauriQuitApp(); + } + }, + }); + useEffect(() => { updateAppTheme('base-200'); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -339,7 +349,7 @@ const LibraryPage = () => { if (!isSelectMode && appService?.isMobile) { impactFeedback('medium'); } - setIsSelectMode(!isSelectMode); + setIsSelectMode((pre) => !pre); }; const handleSetSelectMode = (selectMode: boolean) => { diff --git a/apps/readest-app/src/app/reader/hooks/useBookShortcuts.ts b/apps/readest-app/src/app/reader/hooks/useBookShortcuts.ts index a4b5fe2f..80676aaa 100644 --- a/apps/readest-app/src/app/reader/hooks/useBookShortcuts.ts +++ b/apps/readest-app/src/app/reader/hooks/useBookShortcuts.ts @@ -7,7 +7,7 @@ import { useSidebarStore } from '@/store/sidebarStore'; import { useSettingsStore } from '@/store/settingsStore'; import { useTheme } from '@/hooks/useTheme'; import { getStyles } from '@/utils/style'; -import { eventDispatcher } from '@/utils/event'; +import { tauriQuitApp } from '@/utils/window'; import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, ZOOM_STEP } from '@/services/constants'; interface UseBookShortcutsProps { @@ -88,9 +88,7 @@ const useBookShortcuts = ({ sideBarBookKey, bookKeys }: UseBookShortcutsProps) = const quitApp = async () => { // on web platform use browser's default shortcut to close the tab if (isTauriAppPlatform()) { - await eventDispatcher.dispatch('quit-app'); - const { exit } = await import('@tauri-apps/plugin-process'); - await exit(0); + await tauriQuitApp(); } }; diff --git a/apps/readest-app/src/helpers/shortcuts.ts b/apps/readest-app/src/helpers/shortcuts.ts index 0a7e1a67..8dbd382c 100644 --- a/apps/readest-app/src/helpers/shortcuts.ts +++ b/apps/readest-app/src/helpers/shortcuts.ts @@ -4,6 +4,7 @@ export interface ShortcutConfig { onToggleNotebook: string[]; onToggleSearchBar: string[]; onToggleScrollMode: string[]; + onToggleSelectMode: string[]; onOpenFontLayoutSettings: string[]; onReloadPage: string[]; onQuitApp: string[]; @@ -28,6 +29,7 @@ const DEFAULT_SHORTCUTS: ShortcutConfig = { onToggleNotebook: ['n'], onToggleSearchBar: ['ctrl+f', 'cmd+f'], onToggleScrollMode: ['shift+j'], + onToggleSelectMode: ['shift+s'], onOpenFontLayoutSettings: ['shift+f'], onReloadPage: ['shift+r'], onQuitApp: ['ctrl+q', 'cmd+q'], diff --git a/apps/readest-app/src/utils/window.ts b/apps/readest-app/src/utils/window.ts index c4d2b0ba..aa91024d 100644 --- a/apps/readest-app/src/utils/window.ts +++ b/apps/readest-app/src/utils/window.ts @@ -1,3 +1,5 @@ +import { eventDispatcher } from './event'; + export const tauriGetWindowLogicalPosition = async () => { const { getCurrentWindow } = await import('@tauri-apps/api/window'); const currentWindow = getCurrentWindow(); @@ -41,3 +43,9 @@ export const tauriHandleOnWindowFocus = async (callback: () => void) => { await callback(); }); }; + +export const tauriQuitApp = async () => { + await eventDispatcher.dispatch('quit-app'); + const { exit } = await import('@tauri-apps/plugin-process'); + await exit(0); +};