From 8fb1745dbb8706cfb0568648bd7e77942481b684 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 30 Jul 2025 17:35:07 +0800 Subject: [PATCH] config: add an option to disable double click, closes #1713 (#1715) --- .../public/locales/ar/translation.json | 3 ++- .../public/locales/de/translation.json | 3 ++- .../public/locales/el/translation.json | 3 ++- .../public/locales/es/translation.json | 3 ++- .../public/locales/fr/translation.json | 3 ++- .../public/locales/hi/translation.json | 3 ++- .../public/locales/id/translation.json | 3 ++- .../public/locales/it/translation.json | 3 ++- .../public/locales/ja/translation.json | 3 ++- .../public/locales/ko/translation.json | 3 ++- .../public/locales/nl/translation.json | 3 ++- .../public/locales/pl/translation.json | 3 ++- .../public/locales/pt/translation.json | 3 ++- .../public/locales/ru/translation.json | 3 ++- .../public/locales/th/translation.json | 3 ++- .../public/locales/tr/translation.json | 3 ++- .../public/locales/uk/translation.json | 3 ++- .../public/locales/vi/translation.json | 3 ++- .../public/locales/zh-CN/translation.json | 3 ++- .../public/locales/zh-TW/translation.json | 3 ++- .../app/reader/components/FoliateViewer.tsx | 10 +++++++++- .../components/settings/ControlPanel.tsx | 17 ++++++++++++++++ .../app/reader/utils/iframeEventHandlers.ts | 20 ++++++++----------- apps/readest-app/src/services/constants.ts | 2 ++ apps/readest-app/src/types/book.ts | 1 + 25 files changed, 77 insertions(+), 33 deletions(-) diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index bbaccf71..c66445f4 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -476,5 +476,6 @@ "Failed to create checkout session": "فشل في إنشاء جلسة الدفع", "Storage": "التخزين", "Terms of Service": "شروط الخدمة", - "Privacy Policy": "سياسة الخصوصية" + "Privacy Policy": "سياسة الخصوصية", + "Disable Double Click": "تعطيل النقر المزدوج" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 69fbf10a..23e20a07 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -460,5 +460,6 @@ "Failed to create checkout session": "Fehler beim Erstellen der Checkout-Sitzung", "Storage": "Speicher", "Terms of Service": "Allgemeine Geschäftsbedingungen", - "Privacy Policy": "Datenschutzbestimmungen" + "Privacy Policy": "Datenschutzbestimmungen", + "Disable Double Click": "Doppelklick deaktivieren" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 5a62f15b..729bd12e 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -460,5 +460,6 @@ "Failed to create checkout session": "Αποτυχία δημιουργίας συνεδρίας πληρωμής", "Storage": "Αποθήκευση", "Terms of Service": "Όροι χρήσης", - "Privacy Policy": "Πολιτική απορρήτου" + "Privacy Policy": "Πολιτική απορρήτου", + "Disable Double Click": "Απενεργοποίηση διπλού κλικ" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index fa9c2bdd..623a0a31 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -464,5 +464,6 @@ "Failed to create checkout session": "Error al crear la sesión de pago", "Storage": "Almacenamiento", "Terms of Service": "Condiciones del servicio", - "Privacy Policy": "Política de privacidad" + "Privacy Policy": "Política de privacidad", + "Disable Double Click": "Deshabilitar Doble Clic" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index cbf7e131..8d1a60f0 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -464,5 +464,6 @@ "Failed to create checkout session": "Échec de la création de la session de paiement", "Storage": "Stockage", "Terms of Service": "Conditions d'utilisation", - "Privacy Policy": "Politique de confidentialité" + "Privacy Policy": "Politique de confidentialité", + "Disable Double Click": "Désactiver le double-clic" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index a3c29f45..1ef47c51 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -460,5 +460,6 @@ "Failed to create checkout session": "चेकआउट सत्र बनाने में विफल", "Storage": "भंडारण", "Terms of Service": "सेवा की शर्तें", - "Privacy Policy": "गोपनीयता नीति" + "Privacy Policy": "गोपनीयता नीति", + "Disable Double Click": "डबल क्लिक अक्षम करें" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index bf810e85..a550573c 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "Gagal membuat sesi checkout", "Storage": "Penyimpanan", "Terms of Service": "Ketentuan Layanan", - "Privacy Policy": "Kebijakan Privasi" + "Privacy Policy": "Kebijakan Privasi", + "Disable Double Click": "Nonaktifkan Klik Ganda" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 9fab0ba5..f0ff6cf9 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -464,5 +464,6 @@ "Failed to create checkout session": "Impossibile creare la sessione di checkout", "Storage": "Archiviazione", "Terms of Service": "Termini di servizio", - "Privacy Policy": "Informativa sulla privacy" + "Privacy Policy": "Informativa sulla privacy", + "Disable Double Click": "Disabilita Doppio Clic" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index f1522c93..d0376a88 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "チェックアウトセッションの作成に失敗しました", "Storage": "ストレージ", "Terms of Service": "利用規約", - "Privacy Policy": "プライバシーポリシー" + "Privacy Policy": "プライバシーポリシー", + "Disable Double Click": "ダブルクリック無効" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 3330e320..e19bbba2 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "체크아웃 세션 생성 실패", "Storage": "저장소", "Terms of Service": "서비스 약관", - "Privacy Policy": "개인정보 보호정책" + "Privacy Policy": "개인정보 보호정책", + "Disable Double Click": "더블 클릭 비활성화" } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index b6ad169b..d42899ed 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -460,5 +460,6 @@ "Failed to create checkout session": "Kon de afreken sessie niet aanmaken", "Storage": "Opslag", "Terms of Service": "Gebruiksvoorwaarden", - "Privacy Policy": "Privacybeleid" + "Privacy Policy": "Privacybeleid", + "Disable Double Click": "Dubbelklikken uitschakelen" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 7bb9703b..fd6737e1 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -468,5 +468,6 @@ "Failed to create checkout session": "Nie udało się utworzyć sesji zakupu", "Storage": "Przechowywanie", "Terms of Service": "Warunki korzystania z usługi", - "Privacy Policy": "Polityka prywatności" + "Privacy Policy": "Polityka prywatności", + "Disable Double Click": "Wyłącz podwójne kliknięcie" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 0130d0e6..9f39fd66 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -464,5 +464,6 @@ "Failed to create checkout session": "Falha ao criar sessão de checkout", "Storage": "Armazenamento", "Terms of Service": "Termos de Serviço", - "Privacy Policy": "Política de Privacidade" + "Privacy Policy": "Política de Privacidade", + "Disable Double Click": "Desativar Clique Duplo" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 50d8025b..ecb1c97a 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -468,5 +468,6 @@ "Failed to create checkout session": "Не удалось создать сессию оформления заказа", "Storage": "Хранилище", "Terms of Service": "Условия использования", - "Privacy Policy": "Политика конфиденциальности" + "Privacy Policy": "Политика конфиденциальности", + "Disable Double Click": "Отключить двойной клик" } diff --git a/apps/readest-app/public/locales/th/translation.json b/apps/readest-app/public/locales/th/translation.json index fdd88ffe..ad086f59 100644 --- a/apps/readest-app/public/locales/th/translation.json +++ b/apps/readest-app/public/locales/th/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "ไม่สามารถสร้างเซสชันการชำระเงินได้", "Storage": "พื้นที่เก็บข้อมูล", "Terms of Service": "ข้อกำหนดในการให้บริการ", - "Privacy Policy": "นโยบายความเป็นส่วนตัว" + "Privacy Policy": "นโยบายความเป็นส่วนตัว", + "Disable Double Click": "ปิดการคลิกสองครั้ง" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 606a84d3..1c53f420 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -460,5 +460,6 @@ "Failed to create checkout session": "Ödeme oturumu oluşturma başarısız oldu", "Storage": "Depolama", "Terms of Service": "Hizmet Şartları", - "Privacy Policy": "Gizlilik Politikası" + "Privacy Policy": "Gizlilik Politikası", + "Disable Double Click": "Çift Tıklamayı Devre Dışı Bırak" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 3b6ec7f5..14deefed 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -468,5 +468,6 @@ "Failed to create checkout session": "Не вдалося створити сесію оформлення замовлення", "Storage": "Сховище", "Terms of Service": "Умови обслуговування", - "Privacy Policy": "Політика конфіденційності" + "Privacy Policy": "Політика конфіденційності", + "Disable Double Click": "Вимкнути подвійне клацання" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index 950a6edc..3f0649ba 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "Không thể tạo phiên làm việc thanh toán", "Storage": "Lưu trữ", "Terms of Service": "Điều khoản dịch vụ", - "Privacy Policy": "Chính sách bảo mật" + "Privacy Policy": "Chính sách bảo mật", + "Disable Double Click": "Tắt Nhấp Đôi" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 773b5aa2..14ac9d15 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "创建结账会话失败", "Storage": "云同步空间", "Terms of Service": "服务条款", - "Privacy Policy": "隐私政策" + "Privacy Policy": "隐私政策", + "Disable Double Click": "禁用双击" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index f3375715..b9b1e28d 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -456,5 +456,6 @@ "Failed to create checkout session": "創建結帳會話失敗", "Storage": "雲同步空間", "Terms of Service": "服務條款", - "Privacy Policy": "隱私政策" + "Privacy Policy": "隱私政策", + "Disable Double Click": "禁用雙擊" } diff --git a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx index 0619e3d6..cbaffb7f 100644 --- a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx +++ b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx @@ -66,6 +66,7 @@ const FoliateViewer: React.FC<{ const viewRef = useRef(null); const containerRef = useRef(null); const isViewCreated = useRef(false); + const doubleClickDisabled = useRef(!!viewSettings?.disableDoubleClick); const [toastMessage, setToastMessage] = useState(''); useEffect(() => { @@ -159,7 +160,7 @@ const FoliateViewer: React.FC<{ detail.doc.addEventListener('keydown', handleKeydown.bind(null, bookKey)); detail.doc.addEventListener('mousedown', handleMousedown.bind(null, bookKey)); detail.doc.addEventListener('mouseup', handleMouseup.bind(null, bookKey)); - detail.doc.addEventListener('click', handleClick.bind(null, bookKey)); + detail.doc.addEventListener('click', handleClick.bind(null, bookKey, doubleClickDisabled)); detail.doc.addEventListener('wheel', handleWheel.bind(null, bookKey)); detail.doc.addEventListener('touchstart', handleTouchStart.bind(null, bookKey)); detail.doc.addEventListener('touchmove', handleTouchMove.bind(null, bookKey)); @@ -256,6 +257,7 @@ const FoliateViewer: React.FC<{ view.renderer.setStyles?.(getStyles(viewSettings)); applyTranslationStyle(viewSettings); + doubleClickDisabled.current = viewSettings.disableDoubleClick!; const animated = viewSettings.animated!; const maxColumnCount = viewSettings.maxColumnCount!; const maxInlineSize = getMaxInlineSize(viewSettings); @@ -325,6 +327,12 @@ const FoliateViewer: React.FC<{ // eslint-disable-next-line react-hooks/exhaustive-deps }, [themeCode, isDarkMode, viewSettings?.overrideColor, viewSettings?.invertImgColorInDark]); + useEffect(() => { + if (viewRef.current && viewRef.current.renderer) { + doubleClickDisabled.current = !!viewSettings?.disableDoubleClick; + } + }, [viewSettings?.disableDoubleClick]); + useEffect(() => { if (viewRef.current && viewRef.current.renderer && viewSettings) { applyMarginAndGap(); diff --git a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx b/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx index 44883525..e817858f 100644 --- a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx @@ -27,6 +27,9 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip!); const [isDisableClick, setIsDisableClick] = useState(viewSettings.disableClick!); const [swapClickArea, setSwapClickArea] = useState(viewSettings.swapClickArea!); + const [isDisableDoubleClick, setIsDisableDoubleClick] = useState( + viewSettings.disableDoubleClick!, + ); const [animated, setAnimated] = useState(viewSettings.animated!); const [allowScript, setAllowScript] = useState(viewSettings.allowScript!); @@ -90,6 +93,11 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes // eslint-disable-next-line react-hooks/exhaustive-deps }, [isDisableClick]); + useEffect(() => { + saveViewSettings(envConfig, bookKey, 'disableDoubleClick', isDisableDoubleClick, false, false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isDisableDoubleClick]); + useEffect(() => { saveViewSettings(envConfig, bookKey, 'swapClickArea', swapClickArea, false, false); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -172,6 +180,15 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes onChange={() => setSwapClickArea(!swapClickArea)} /> +
+ {_('Disable Double Click')} + setIsDisableDoubleClick(!isDisableDoubleClick)} + /> +
{appService?.isMobileApp && (
{_('Volume Keys for Page Flip')} diff --git a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts index 583442de..bc77d9b4 100644 --- a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts +++ b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts @@ -1,13 +1,5 @@ -import { - DISABLE_DOUBLE_CLICK_ON_MOBILE, - DOUBLE_CLICK_INTERVAL_THRESHOLD_MS, - LONG_HOLD_THRESHOLD, -} from '@/services/constants'; +import { DOUBLE_CLICK_INTERVAL_THRESHOLD_MS, LONG_HOLD_THRESHOLD } from '@/services/constants'; import { eventDispatcher } from '@/utils/event'; -import { getOSPlatform } from '@/utils/misc'; - -const doubleClickEnabled = - !DISABLE_DOUBLE_CLICK_ON_MOBILE || !['android', 'ios'].includes(getOSPlatform()); let lastClickTime = 0; let longHoldTimeout: ReturnType | null = null; @@ -93,10 +85,14 @@ export const handleWheel = (bookKey: string, event: WheelEvent) => { ); }; -export const handleClick = (bookKey: string, event: MouseEvent) => { +export const handleClick = ( + bookKey: string, + doubleClickDisabled: React.MutableRefObject, + event: MouseEvent, +) => { const now = Date.now(); - if (doubleClickEnabled && now - lastClickTime < DOUBLE_CLICK_INTERVAL_THRESHOLD_MS) { + if (!doubleClickDisabled.current && now - lastClickTime < DOUBLE_CLICK_INTERVAL_THRESHOLD_MS) { lastClickTime = now; window.postMessage( { @@ -156,7 +152,7 @@ export const handleClick = (bookKey: string, event: MouseEvent) => { '*', ); }; - if (doubleClickEnabled) { + if (!doubleClickDisabled.current) { setTimeout(() => { if (Date.now() - lastClickTime >= DOUBLE_CLICK_INTERVAL_THRESHOLD_MS) { postSingleClick(); diff --git a/apps/readest-app/src/services/constants.ts b/apps/readest-app/src/services/constants.ts index fb59e3af..0e03f0e0 100644 --- a/apps/readest-app/src/services/constants.ts +++ b/apps/readest-app/src/services/constants.ts @@ -105,6 +105,7 @@ export const DEFAULT_BOOK_LAYOUT: BookLayout = { scrolled: false, disableClick: false, swapClickArea: false, + disableDoubleClick: false, volumeKeysToFlip: false, continuousScroll: false, maxColumnCount: 2, @@ -143,6 +144,7 @@ export const DEFAULT_MOBILE_VIEW_SETTINGS: Partial = { animated: true, defaultFont: 'Sans-serif', marginBottomPx: 16, + disableDoubleClick: true, }; export const DEFAULT_CJK_VIEW_SETTINGS: Partial = { diff --git a/apps/readest-app/src/types/book.ts b/apps/readest-app/src/types/book.ts index 2d9f56be..c1c757cd 100644 --- a/apps/readest-app/src/types/book.ts +++ b/apps/readest-app/src/types/book.ts @@ -92,6 +92,7 @@ export interface BookLayout { scrolled: boolean; disableClick: boolean; swapClickArea: boolean; + disableDoubleClick: boolean; volumeKeysToFlip: boolean; continuousScroll: boolean; maxColumnCount: number;