From 4457d9b6fbe3bcc8a7c103e0be0337106555a6e4 Mon Sep 17 00:00:00 2001 From: chrox Date: Mon, 28 Oct 2024 17:01:26 +0100 Subject: [PATCH] Unified keydown handling --- apps/readest-app/src-tauri/tauri.conf.json | 2 +- .../app/reader/components/FoliateViewer.tsx | 25 +++++++++++- .../src/app/reader/components/FooterBar.tsx | 21 +--------- .../src/app/reader/components/HeaderBar.tsx | 2 +- .../app/reader/components/ReaderContent.tsx | 40 +++++++++++++++++-- .../src/app/reader/components/TOCView.tsx | 3 +- .../src/app/reader/hooks/useFoliateEvents.ts | 40 ++++--------------- 7 files changed, 70 insertions(+), 63 deletions(-) diff --git a/apps/readest-app/src-tauri/tauri.conf.json b/apps/readest-app/src-tauri/tauri.conf.json index f2a8b74d..eec38c91 100644 --- a/apps/readest-app/src-tauri/tauri.conf.json +++ b/apps/readest-app/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "productName": "Readest", - "version": "0.3.0", + "version": "0.3.1", "identifier": "com.bilingify.digest", "build": { "frontendDist": "../out", diff --git a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx index 3e937880..91be72b9 100644 --- a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx +++ b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx @@ -62,13 +62,34 @@ const FoliateViewer: React.FC<{ bookKey: string; bookDoc: BookDoc; bookConfig: BookConfig; -}> = ({ bookKey, bookDoc, bookConfig }) => { + handleKeyDown: (event: KeyboardEvent) => void; +}> = ({ bookKey, bookDoc, bookConfig, handleKeyDown }) => { const viewRef = useRef(null); const [view, setView] = useState(null); const isViewCreated = useRef(false); const { setFoliateView } = useReaderStore(); + const setProgress = useReaderStore((state) => state.setProgress); - useFoliateEvents(bookKey, view); + const progressRelocateHandler = (event: Event) => { + const detail = (event as CustomEvent).detail; + // console.log('relocate:', detail); + setProgress( + bookKey, + detail.fraction, + detail.cfi, + detail.tocItem?.href, + detail.tocItem?.label, + detail.section, + detail.location, + ); + }; + + const docLoadHandler = (event: Event) => { + const detail = (event as CustomEvent).detail; + if (handleKeyDown) detail.doc?.addEventListener('keydown', handleKeyDown); + }; + + useFoliateEvents(view, { onLoad: docLoadHandler, onRelocate: progressRelocateHandler }); useEffect(() => { if (isViewCreated.current) return; diff --git a/apps/readest-app/src/app/reader/components/FooterBar.tsx b/apps/readest-app/src/app/reader/components/FooterBar.tsx index 1dedeb99..f9f3b43e 100644 --- a/apps/readest-app/src/app/reader/components/FooterBar.tsx +++ b/apps/readest-app/src/app/reader/components/FooterBar.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import clsx from 'clsx'; import { RiArrowLeftWideLine, RiArrowRightWideLine } from 'react-icons/ri'; @@ -9,7 +9,6 @@ interface FooterBarProps { progress: number | undefined; isHoveredAnim: boolean; hoveredBookKey: string; - sideBarBookKey: string; setHoveredBookKey: (key: string) => void; } @@ -18,7 +17,6 @@ const FooterBar: React.FC = ({ progress, isHoveredAnim, hoveredBookKey, - sideBarBookKey, setHoveredBookKey, }) => { const { getFoliateView } = useReaderStore(); @@ -39,23 +37,6 @@ const FooterBar: React.FC = ({ foliateView?.goRight(); }; - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (sideBarBookKey === bookKey) { - if (e.key === 'ArrowLeft') { - handleGoPrev(); - } else if (e.key === 'ArrowRight') { - handleGoNext(); - } - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [sideBarBookKey, bookKey]); - return (
= ({ onMouseLeave={() => setHoveredBookKey('')} >
-

+

{bookTitle}

diff --git a/apps/readest-app/src/app/reader/components/ReaderContent.tsx b/apps/readest-app/src/app/reader/components/ReaderContent.tsx index 89c6edf2..375502c5 100644 --- a/apps/readest-app/src/app/reader/components/ReaderContent.tsx +++ b/apps/readest-app/src/app/reader/components/ReaderContent.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useSearchParams, useRouter } from 'next/navigation'; import { useEnv } from '@/context/EnvContext'; @@ -22,6 +22,7 @@ const ReaderContent = () => { const { envConfig } = useEnv(); const { books, settings, initBookState, saveConfig, saveSettings } = useReaderStore(); + const { getFoliateView } = useReaderStore(); const [sideBarWidth, setSideBarWidth] = useState( settings.globalReadSettings.sideBarWidth ?? '25%', @@ -36,7 +37,27 @@ const ReaderContent = () => { const [sideBarBookKey, setSideBarBookKey] = useState(getKey(ids[0] ?? '', 0)); const [hoveredBookKey, setHoveredBookKey] = useState(''); - React.useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if ( + (e.ctrlKey && e.key === 'Tab') || + (e.altKey && e.key === 'Tab') || + (e.metaKey && e.key === 'Tab') + ) { + setSideBarBookKey((prevKey) => { + const index = ids.findIndex((id) => prevKey.startsWith(id)); + const nextIndex = (index + 1) % ids.length; + return getKey(ids[nextIndex]!, nextIndex); + }); + e.preventDefault(); + } + if (e.key === 'ArrowLeft') { + getFoliateView(sideBarBookKey)?.goLeft(); + } else if (e.key === 'ArrowRight') { + getFoliateView(sideBarBookKey)?.goRight(); + } + }; + + useEffect(() => { if (ids.length === 0) return; const uniqueIds = new Set(); ids.forEach((id, index) => { @@ -49,6 +70,13 @@ const ReaderContent = () => { }); }, [ids, settings]); + useEffect(() => { + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, [sideBarBookKey]); + const handleSideBarResize = (newWidth: string) => { setSideBarWidth(newWidth); settings.globalReadSettings.sideBarWidth = newWidth; @@ -152,7 +180,12 @@ const ReaderContent = () => { setSideBarBookKey={setSideBarBookKey} setHoveredBookKey={setHoveredBookKey} /> - + { progress={progress} isHoveredAnim={false} hoveredBookKey={hoveredBookKey} - sideBarBookKey={sideBarBookKey} setHoveredBookKey={setHoveredBookKey} />
diff --git a/apps/readest-app/src/app/reader/components/TOCView.tsx b/apps/readest-app/src/app/reader/components/TOCView.tsx index 185a1db5..5306f406 100644 --- a/apps/readest-app/src/app/reader/components/TOCView.tsx +++ b/apps/readest-app/src/app/reader/components/TOCView.tsx @@ -136,8 +136,7 @@ const TOCView: React.FC<{ } }; - const foliateView = getFoliateView(bookKey); - useFoliateEvents(bookKey, foliateView, { onRelocate: tocRelocateHandler }); + useFoliateEvents(getFoliateView(bookKey), { onRelocate: tocRelocateHandler }); useEffect(() => { setCurrentHref(href); diff --git a/apps/readest-app/src/app/reader/hooks/useFoliateEvents.ts b/apps/readest-app/src/app/reader/hooks/useFoliateEvents.ts index 54d2770b..0d5cb368 100644 --- a/apps/readest-app/src/app/reader/hooks/useFoliateEvents.ts +++ b/apps/readest-app/src/app/reader/hooks/useFoliateEvents.ts @@ -1,50 +1,24 @@ import { useEffect } from 'react'; import { FoliateView } from '@/app/reader/components/FoliateViewer'; -import { useReaderStore } from '@/store/readerStore'; type FoliateEventHandler = { onLoad?: (event: Event) => void; onRelocate?: (event: Event) => void; }; -export const useFoliateEvents = ( - bookKey: string, - view: FoliateView | null, - handlers?: FoliateEventHandler, -) => { - const setProgress = useReaderStore((state) => state.setProgress); - - const defaultLoadHandler = (event: Event) => { - const detail = (event as CustomEvent).detail; - console.log('load event:', detail); - }; - - const defaultRelocateHandler = (event: Event) => { - const detail = (event as CustomEvent).detail; - // console.log('relocate:', detail); - setProgress( - bookKey, - detail.fraction, - detail.cfi, - detail.tocItem?.href, - detail.tocItem?.label, - detail.section, - detail.location, - ); - }; - - const onLoad = handlers?.onLoad || defaultLoadHandler; - const onRelocate = handlers?.onRelocate || defaultRelocateHandler; +export const useFoliateEvents = (view: FoliateView | null, handlers?: FoliateEventHandler) => { + const onLoad = handlers?.onLoad; + const onRelocate = handlers?.onRelocate; useEffect(() => { if (!view) return; - view.addEventListener('load', onLoad); - view.addEventListener('relocate', onRelocate); + if (onLoad) view.addEventListener('load', onLoad); + if (onRelocate) view.addEventListener('relocate', onRelocate); return () => { - view.removeEventListener('load', onLoad); - view.removeEventListener('relocate', onRelocate); + if (onLoad) view.removeEventListener('load', onLoad); + if (onRelocate) view.removeEventListener('relocate', onRelocate); }; }, [view, onLoad, onRelocate, handlers]); };