fix(annotator): fix instant action on Android (#3042)

This commit is contained in:
Huang Xin
2026-01-23 17:18:51 +01:00
committed by GitHub
parent 481d8198e9
commit 6c0f1b8b5f
37 changed files with 232 additions and 142 deletions
@@ -872,7 +872,6 @@
"Show Results": "عرض النتائج",
"Clear search": "مسح البحث",
"Clear search history": "مسح سجل البحث",
"Quick action disabled": "الإجراء السريع معطل",
"Tap to Toggle Footer": "انقر لتبديل التذييل",
"Exported successfully": "تم التصدير بنجاح",
"Book exported successfully.": "تم تصدير الكتاب بنجاح.",
@@ -930,5 +929,8 @@
"Select Voice": "اختر الصوت",
"Toggle Sticky Bottom TTS Bar": "تبديل شريط TTS الثابت",
"Display what I'm reading on Discord": "عرض ما أقرأه على Discord",
"Show on Discord": "عرض على Discord"
"Show on Discord": "عرض على Discord",
"Instant {{action}}": "{{action}} فوري",
"Instant {{action}} Disabled": "تم تعطيل {{action}} فوري",
"Annotation": "التعليق"
}
@@ -832,7 +832,6 @@
"Show Results": "ফলাফল দেখুন",
"Clear search": "অনুসন্ধান সাফ করুন",
"Clear search history": "অনুসন্ধান ইতিহাস সাফ করুন",
"Quick action disabled": "দ্রুত কার্যক্রম অক্ষম",
"Tap to Toggle Footer": "ফুটার টগল করতে আলতো চাপুন",
"Exported successfully": "সফলভাবে রপ্তানি হয়েছে",
"Book exported successfully.": "বইটি সফলভাবে রপ্তানি হয়েছে।",
@@ -890,5 +889,8 @@
"Select Voice": "ভয়েস নির্বাচন করুন",
"Toggle Sticky Bottom TTS Bar": "স্থির TTS বার টগল করুন",
"Display what I'm reading on Discord": "Discord-এ পড়ছি যা দেখান",
"Show on Discord": "Discord-এ দেখান"
"Show on Discord": "Discord-এ দেখান",
"Instant {{action}}": "তাৎক্ষণিক {{action}}",
"Instant {{action}} Disabled": "তাৎক্ষণিক {{action}} নিষ্ক্রিয়",
"Annotation": "টীকা"
}
@@ -822,7 +822,6 @@
"Show Results": "འབྲས་བུ་སྟོན།",
"Clear search": "འཚོལ་བཤེར་གཙང་སེལ།",
"Clear search history": "འཚོལ་བཤེར་ལོ་རྒྱུས་གཙང་སེལ།",
"Quick action disabled": "མྱུར་མགྱོགས་བྱ་འགུལ་བཀག་འགོག",
"Tap to Toggle Footer": "ཞབས་མཇུག་སྒོ་འབྱེད་བྱེད་པར་གནོན།",
"Exported successfully": "ཕྱིར་འདོན་ལེགས་གྲུབ་བྱུང་།",
"Book exported successfully.": "དཔེ་དེབ་ཕྱིར་འདོན་ལེགས་གྲུབ་བྱུང་།",
@@ -880,5 +879,8 @@
"Select Voice": "སྐད་གདངས་འདེམས།",
"Toggle Sticky Bottom TTS Bar": "TTS སྡོམ་ཐིག་བརྗེ་བ།",
"Display what I'm reading on Discord": "Discord ཐོག་ཀློག་བཞིན་པའི་དཔེ་ཆ་སྟོན།",
"Show on Discord": "Discord ཐོག་སྟོན།"
"Show on Discord": "Discord ཐོག་སྟོན།",
"Instant {{action}}": "འཕྲལ་མར་{{action}}",
"Instant {{action}} Disabled": "འཕྲལ་མར་{{action}}་ལྕོགས་མིན་བཟོས།",
"Annotation": "མཆན་འགྲེལ།"
}
@@ -832,7 +832,6 @@
"Show Results": "Ergebnisse anzeigen",
"Clear search": "Suche löschen",
"Clear search history": "Suchverlauf löschen",
"Quick action disabled": "Schnellaktion deaktiviert",
"Tap to Toggle Footer": "Tippen, um Fußzeile umzuschalten",
"Exported successfully": "Erfolgreich exportiert",
"Book exported successfully.": "Buch erfolgreich exportiert.",
@@ -890,5 +889,8 @@
"Select Voice": "Stimme auswählen",
"Toggle Sticky Bottom TTS Bar": "Fixierte TTS-Leiste umschalten",
"Display what I'm reading on Discord": "Zeige was ich auf Discord lese",
"Show on Discord": "Auf Discord zeigen"
"Show on Discord": "Auf Discord zeigen",
"Instant {{action}}": "Sofort {{action}}",
"Instant {{action}} Disabled": "Sofort {{action}} deaktiviert",
"Annotation": "Anmerkung"
}
@@ -832,7 +832,6 @@
"Show Results": "Εμφάνιση αποτελεσμάτων",
"Clear search": "Εκκαθάριση αναζήτησης",
"Clear search history": "Εκκαθάριση ιστορικού αναζήτησης",
"Quick action disabled": "Η γρήγορη ενέργεια απενεργοποιήθηκε",
"Tap to Toggle Footer": "Πατήστε για εναλλαγή υποσέλιδου",
"Exported successfully": "Εξαγωγή επιτυχής",
"Book exported successfully.": "Το βιβλίο εξήχθη επιτυχώς.",
@@ -890,5 +889,8 @@
"Select Voice": "Επιλογή φωνής",
"Toggle Sticky Bottom TTS Bar": "Εναλλαγή καρφιτσωμένης μπάρας TTS",
"Display what I'm reading on Discord": "Εμφάνιση του βιβλίου που διαβάζω στο Discord",
"Show on Discord": "Εμφάνιση στο Discord"
"Show on Discord": "Εμφάνιση στο Discord",
"Instant {{action}}": "Άμεση {{action}}",
"Instant {{action}} Disabled": "Άμεση {{action}} απενεργοποιημένη",
"Annotation": "Σημείωση"
}
@@ -842,7 +842,6 @@
"Show Results": "Mostrar resultados",
"Clear search": "Borrar búsqueda",
"Clear search history": "Borrar historial de búsqueda",
"Quick action disabled": "Acción rápida desactivada",
"Tap to Toggle Footer": "Toca para alternar pie de página",
"Exported successfully": "Exportado con éxito",
"Book exported successfully.": "Libro exportado con éxito.",
@@ -900,5 +899,8 @@
"Select Voice": "Seleccionar voz",
"Toggle Sticky Bottom TTS Bar": "Alternar barra TTS fija",
"Display what I'm reading on Discord": "Mostrar lo que estoy leyendo en Discord",
"Show on Discord": "Mostrar en Discord"
"Show on Discord": "Mostrar en Discord",
"Instant {{action}}": "{{action}} instantáneo",
"Instant {{action}} Disabled": "{{action}} instantáneo desactivado",
"Annotation": "Anotación"
}
@@ -832,7 +832,6 @@
"Show Results": "نمایش نتایج",
"Clear search": "پاک کردن جستجو",
"Clear search history": "پاک کردن تاریخچه جستجو",
"Quick action disabled": "عملکرد سریع غیرفعال است",
"Tap to Toggle Footer": "برای تغییر پاورقی ضربه بزنید",
"Exported successfully": "صادرات موفق",
"Book exported successfully.": "کتاب با موفقیت صادر شد.",
@@ -890,5 +889,8 @@
"Select Voice": "انتخاب صدا",
"Toggle Sticky Bottom TTS Bar": "تغییر نوار TTS ثابت",
"Display what I'm reading on Discord": "نمایش کتاب در حال خواندن در Discord",
"Show on Discord": "نمایش در Discord"
"Show on Discord": "نمایش در Discord",
"Instant {{action}}": "{{action}} فوری",
"Instant {{action}} Disabled": "{{action}} فوری غیرفعال شد",
"Annotation": "یادداشت"
}
@@ -842,7 +842,6 @@
"Show Results": "Afficher les résultats",
"Clear search": "Effacer la recherche",
"Clear search history": "Effacer l'historique de recherche",
"Quick action disabled": "Action rapide désactivée",
"Tap to Toggle Footer": "Appuyez pour afficher/masquer le pied de page",
"Exported successfully": "Exporté avec succès",
"Book exported successfully.": "Livre exporté avec succès.",
@@ -900,5 +899,8 @@
"Select Voice": "Sélectionner la voix",
"Toggle Sticky Bottom TTS Bar": "Basculer la barre TTS fixée",
"Display what I'm reading on Discord": "Afficher ce que je lis sur Discord",
"Show on Discord": "Afficher sur Discord"
"Show on Discord": "Afficher sur Discord",
"Instant {{action}}": "{{action}} instantané",
"Instant {{action}} Disabled": "{{action}} instantané désactivé",
"Annotation": "Annotation"
}
@@ -832,7 +832,6 @@
"Show Results": "परिणाम दिखाएं",
"Clear search": "खोज साफ़ करें",
"Clear search history": "खोज इतिहास साफ़ करें",
"Quick action disabled": "त्वरित क्रिया अक्षम",
"Tap to Toggle Footer": "फुटर टॉगल करने के लिए टैप करें",
"Exported successfully": "सफलतापूर्वक निर्यात किया गया",
"Book exported successfully.": "पुस्तक सफलतापूर्वक निर्यात की गई।",
@@ -890,5 +889,8 @@
"Select Voice": "आवाज़ चुनें",
"Toggle Sticky Bottom TTS Bar": "स्थिर TTS बार टॉगल करें",
"Display what I'm reading on Discord": "Discord पर पढ़ रही किताब दिखाएं",
"Show on Discord": "Discord पर दिखाएं"
"Show on Discord": "Discord पर दिखाएं",
"Instant {{action}}": "तत्काल {{action}}",
"Instant {{action}} Disabled": "तत्काल {{action}} अक्षम",
"Annotation": "टिप्पणी"
}
@@ -822,7 +822,6 @@
"Show Results": "Tampilkan Hasil",
"Clear search": "Hapus pencarian",
"Clear search history": "Hapus riwayat pencarian",
"Quick action disabled": "Tindakan cepat dinonaktifkan",
"Tap to Toggle Footer": "Ketuk untuk beralih footer",
"Exported successfully": "Berhasil diekspor",
"Book exported successfully.": "Buku berhasil diekspor.",
@@ -880,5 +879,8 @@
"Select Voice": "Pilih suara",
"Toggle Sticky Bottom TTS Bar": "Alihkan bilah TTS tetap",
"Display what I'm reading on Discord": "Tampilkan buku yang sedang dibaca di Discord",
"Show on Discord": "Tampilkan di Discord"
"Show on Discord": "Tampilkan di Discord",
"Instant {{action}}": "{{action}} Instan",
"Instant {{action}} Disabled": "{{action}} Instan Dinonaktifkan",
"Annotation": "Anotasi"
}
@@ -842,7 +842,6 @@
"Show Results": "Mostra risultati",
"Clear search": "Cancella ricerca",
"Clear search history": "Cancella cronologia ricerche",
"Quick action disabled": "Azione rapida disattivata",
"Tap to Toggle Footer": "Tocca per mostrare/nascondere il piè di pagina",
"Exported successfully": "Esportato con successo",
"Book exported successfully.": "Libro esportato con successo.",
@@ -900,5 +899,8 @@
"Select Voice": "Seleziona voce",
"Toggle Sticky Bottom TTS Bar": "Attiva/disattiva barra TTS fissa",
"Display what I'm reading on Discord": "Mostra cosa sto leggendo su Discord",
"Show on Discord": "Mostra su Discord"
"Show on Discord": "Mostra su Discord",
"Instant {{action}}": "{{action}} istantaneo",
"Instant {{action}} Disabled": "{{action}} istantaneo disattivato",
"Annotation": "Annotazione"
}
@@ -822,7 +822,6 @@
"Show Results": "結果を表示",
"Clear search": "検索をクリア",
"Clear search history": "検索履歴をクリア",
"Quick action disabled": "クイックアクション無効",
"Tap to Toggle Footer": "タップでフッターを切り替え",
"Exported successfully": "エクスポート成功",
"Book exported successfully.": "書籍のエクスポートに成功しました。",
@@ -880,5 +879,8 @@
"Select Voice": "音声選択",
"Toggle Sticky Bottom TTS Bar": "TTSバー固定切替",
"Display what I'm reading on Discord": "読書中の本をDiscordに表示",
"Show on Discord": "Discordに表示"
"Show on Discord": "Discordに表示",
"Instant {{action}}": "インスタント{{action}}",
"Instant {{action}} Disabled": "インスタント{{action}}を無効化",
"Annotation": "注釈"
}
@@ -822,7 +822,6 @@
"Show Results": "결과 표시",
"Clear search": "검색 지우기",
"Clear search history": "검색 기록 지우기",
"Quick action disabled": "빠른 작업 비활성화됨",
"Tap to Toggle Footer": "탭하여 바닥글 전환",
"Exported successfully": "내보내기 성공",
"Book exported successfully.": "책을 성공적으로 내보냈습니다.",
@@ -880,5 +879,8 @@
"Select Voice": "음성 선택",
"Toggle Sticky Bottom TTS Bar": "고정 TTS 바 전환",
"Display what I'm reading on Discord": "Discord에 읽는 책 표시",
"Show on Discord": "Discord에 표시"
"Show on Discord": "Discord에 표시",
"Instant {{action}}": "즉시 {{action}}",
"Instant {{action}} Disabled": "즉시 {{action}} 비활성화",
"Annotation": "주석"
}
@@ -822,7 +822,6 @@
"Show Results": "Tunjukkan Hasil",
"Clear search": "Kosongkan carian",
"Clear search history": "Kosongkan sejarah carian",
"Quick action disabled": "Tindakan pantas dilumpuhkan",
"Tap to Toggle Footer": "Ketik untuk togol pengaki",
"Exported successfully": "Berjaya dieksport",
"Book exported successfully.": "Buku berjaya dieksport.",
@@ -880,5 +879,8 @@
"Select Voice": "Pilih suara",
"Toggle Sticky Bottom TTS Bar": "Togol bar TTS melekit",
"Display what I'm reading on Discord": "Papar buku yang sedang dibaca di Discord",
"Show on Discord": "Papar di Discord"
"Show on Discord": "Papar di Discord",
"Instant {{action}}": "{{action}} Segera",
"Instant {{action}} Disabled": "{{action}} Segera Dilumpuhkan",
"Annotation": "Anotasi"
}
@@ -832,7 +832,6 @@
"Show Results": "Resultaten tonen",
"Clear search": "Zoekopdracht wissen",
"Clear search history": "Zoekgeschiedenis wissen",
"Quick action disabled": "Snelle actie uitgeschakeld",
"Tap to Toggle Footer": "Tik om voettekst te wisselen",
"Exported successfully": "Succesvol geëxporteerd",
"Book exported successfully.": "Boek succesvol geëxporteerd.",
@@ -890,5 +889,8 @@
"Select Voice": "Stem selecteren",
"Toggle Sticky Bottom TTS Bar": "Vaste TTS-balk schakelen",
"Display what I'm reading on Discord": "Toon wat ik lees op Discord",
"Show on Discord": "Toon op Discord"
"Show on Discord": "Toon op Discord",
"Instant {{action}}": "Directe {{action}}",
"Instant {{action}} Disabled": "Directe {{action}} uitgeschakeld",
"Annotation": "Annotatie"
}
@@ -852,7 +852,6 @@
"Show Results": "Pokaż wyniki",
"Clear search": "Wyczyść wyszukiwanie",
"Clear search history": "Wyczyść historię wyszukiwania",
"Quick action disabled": "Szybka akcja wyłączona",
"Tap to Toggle Footer": "Dotknij, aby przełączyć stopkę",
"Exported successfully": "Wyeksportowano pomyślnie",
"Book exported successfully.": "Książka została wyeksportowana pomyślnie.",
@@ -910,5 +909,8 @@
"Select Voice": "Wybierz głos",
"Toggle Sticky Bottom TTS Bar": "Przełącz przypiętą dolną belkę TTS",
"Display what I'm reading on Discord": "Wyświetl to, co czytam na Discord",
"Show on Discord": "Pokaż na Discord"
"Show on Discord": "Pokaż na Discord",
"Instant {{action}}": "Natychmiastowe {{action}}",
"Instant {{action}} Disabled": "Natychmiastowe {{action}} wyłączone",
"Annotation": "Adnotacja"
}
@@ -842,7 +842,6 @@
"Show Results": "Mostrar resultados",
"Clear search": "Limpar pesquisa",
"Clear search history": "Limpar histórico de pesquisa",
"Quick action disabled": "Ação rápida desativada",
"Tap to Toggle Footer": "Toque para alternar rodapé",
"Exported successfully": "Exportado com sucesso",
"Book exported successfully.": "Livro exportado com sucesso.",
@@ -900,5 +899,8 @@
"Select Voice": "Selecionar voz",
"Toggle Sticky Bottom TTS Bar": "Alternar barra TTS fixada",
"Display what I'm reading on Discord": "Mostrar o que estou lendo no Discord",
"Show on Discord": "Mostrar no Discord"
"Show on Discord": "Mostrar no Discord",
"Instant {{action}}": "{{action}} instantâneo",
"Instant {{action}} Disabled": "{{action}} instantâneo desativado",
"Annotation": "Anotação"
}
@@ -852,7 +852,6 @@
"Show Results": "Показать результаты",
"Clear search": "Очистить поиск",
"Clear search history": "Очистить историю поиска",
"Quick action disabled": "Быстрое действие отключено",
"Tap to Toggle Footer": "Нажмите для переключения нижнего колонтитула",
"Exported successfully": "Успешно экспортировано",
"Book exported successfully.": "Книга успешно экспортирована.",
@@ -910,5 +909,8 @@
"Select Voice": "Выбрать голос",
"Toggle Sticky Bottom TTS Bar": "Переключить закреплённую панель TTS",
"Display what I'm reading on Discord": "Показывать книгу в Discord",
"Show on Discord": "Показать в Discord"
"Show on Discord": "Показать в Discord",
"Instant {{action}}": "Мгновенное {{action}}",
"Instant {{action}} Disabled": "Мгновенное {{action}} отключено",
"Annotation": "Аннотация"
}
@@ -832,7 +832,6 @@
"Show Results": "ප්‍රතිඵල පෙන්වන්න",
"Clear search": "සෙවුම හිස් කරන්න",
"Clear search history": "සෙවුම් ඉතිහාසය හිස් කරන්න",
"Quick action disabled": "ඉක්මන් ක්‍රියාව අක්‍රීයයි",
"Tap to Toggle Footer": "පාදකය ටොගල් කිරීමට තට්ටු කරන්න",
"Exported successfully": "සාර්ථකව අපනයනය කරන ලදී",
"Book exported successfully.": "පොත සාර්ථකව අපනයනය කරන ලදී.",
@@ -890,5 +889,8 @@
"Select Voice": "හඬ තෝරන්න",
"Toggle Sticky Bottom TTS Bar": "ඇලවූ TTS තීරුව මාරු කරන්න",
"Display what I'm reading on Discord": "Discord හි කියවන පොත පෙන්වන්න",
"Show on Discord": "Discord හි පෙන්වන්න"
"Show on Discord": "Discord හි පෙන්වන්න",
"Instant {{action}}": "ක්ෂණික {{action}}",
"Instant {{action}} Disabled": "ක්ෂණික {{action}} අබල කර ඇත",
"Annotation": "විවරණය"
}
@@ -832,7 +832,6 @@
"Show Results": "Visa resultat",
"Clear search": "Rensa sökning",
"Clear search history": "Rensa sökhistorik",
"Quick action disabled": "Snabbåtgärd inaktiverad",
"Tap to Toggle Footer": "Tryck för att växla sidfot",
"Exported successfully": "Exporterad",
"Book exported successfully.": "Boken har exporterats.",
@@ -890,5 +889,8 @@
"Select Voice": "Välj röst",
"Toggle Sticky Bottom TTS Bar": "Växla fast TTS-fält",
"Display what I'm reading on Discord": "Visa vad jag läser på Discord",
"Show on Discord": "Visa på Discord"
"Show on Discord": "Visa på Discord",
"Instant {{action}}": "Omedelbar {{action}}",
"Instant {{action}} Disabled": "Omedelbar {{action}} inaktiverad",
"Annotation": "Anteckning"
}
@@ -832,7 +832,6 @@
"Show Results": "முடிவுகளைக் காட்டு",
"Clear search": "தேடலை அழி",
"Clear search history": "தேடல் வரலாற்றை அழி",
"Quick action disabled": "விரைவு செயல் முடக்கப்பட்டது",
"Tap to Toggle Footer": "அடிக்குறிப்பை மாற்ற தட்டவும்",
"Exported successfully": "ஏற்றுமதி வெற்றி",
"Book exported successfully.": "புத்தகம் வெற்றிகரமாக ஏற்றுமதி செய்யப்பட்டது.",
@@ -890,5 +889,8 @@
"Select Voice": "குரலைத் தேர்ந்தெடுக்கவும்",
"Toggle Sticky Bottom TTS Bar": "நிலையான TTS பட்டியை மாற்றவும்",
"Display what I'm reading on Discord": "Discord இல் படிக்கும் புத்தகத்தை காட்டு",
"Show on Discord": "Discord இல் காட்டு"
"Show on Discord": "Discord இல் காட்டு",
"Instant {{action}}": "உடனடி {{action}}",
"Instant {{action}} Disabled": "உடனடி {{action}} முடக்கப்பட்டது",
"Annotation": "குறிப்பு"
}
@@ -822,7 +822,6 @@
"Show Results": "แสดงผลลัพธ์",
"Clear search": "ล้างการค้นหา",
"Clear search history": "ล้างประวัติการค้นหา",
"Quick action disabled": "ปิดใช้งานการดำเนินการด่วน",
"Tap to Toggle Footer": "แตะเพื่อสลับส่วนท้าย",
"Exported successfully": "ส่งออกสำเร็จ",
"Book exported successfully.": "ส่งออกหนังสือสำเร็จ",
@@ -880,5 +879,8 @@
"Select Voice": "เลือกเสียง",
"Toggle Sticky Bottom TTS Bar": "สลับแถบ TTS แบบติด",
"Display what I'm reading on Discord": "แสดงหนังสือที่กำลังอ่านบน Discord",
"Show on Discord": "แสดงบน Discord"
"Show on Discord": "แสดงบน Discord",
"Instant {{action}}": "{{action}}ทันที",
"Instant {{action}} Disabled": "{{action}}ทันทีถูกปิดใช้งาน",
"Annotation": "คำอธิบาย"
}
@@ -832,7 +832,6 @@
"Show Results": "Sonuçları Göster",
"Clear search": "Aramayı temizle",
"Clear search history": "Arama geçmişini temizle",
"Quick action disabled": "Hızlı eylem devre dışı",
"Tap to Toggle Footer": "Altbilgiyi değiştirmek için dokunun",
"Exported successfully": "Başarıyla dışa aktarıldı",
"Book exported successfully.": "Kitap başarıyla dışa aktarıldı.",
@@ -890,5 +889,8 @@
"Select Voice": "Ses seç",
"Toggle Sticky Bottom TTS Bar": "Sabit TTS çubuğunu değiştir",
"Display what I'm reading on Discord": "Discord'da okuduğumu göster",
"Show on Discord": "Discord'da göster"
"Show on Discord": "Discord'da göster",
"Instant {{action}}": "Anında {{action}}",
"Instant {{action}} Disabled": "Anında {{action}} Devre Dışı",
"Annotation": "Açıklama"
}
@@ -852,7 +852,6 @@
"Show Results": "Показати результати",
"Clear search": "Очистити пошук",
"Clear search history": "Очистити історію пошуку",
"Quick action disabled": "Швидку дію вимкнено",
"Tap to Toggle Footer": "Торкніться, щоб перемкнути нижній колонтитул",
"Exported successfully": "Успішно експортовано",
"Book exported successfully.": "Книгу успішно експортовано.",
@@ -910,5 +909,8 @@
"Select Voice": "Вибрати голос",
"Toggle Sticky Bottom TTS Bar": "Перемкнути закріплену панель TTS",
"Display what I'm reading on Discord": "Показувати книгу в Discord",
"Show on Discord": "Показати в Discord"
"Show on Discord": "Показати в Discord",
"Instant {{action}}": "Миттєва {{action}}",
"Instant {{action}} Disabled": "Миттєву {{action}} вимкнено",
"Annotation": "Анотація"
}
@@ -822,7 +822,6 @@
"Show Results": "Hiển thị kết quả",
"Clear search": "Xóa tìm kiếm",
"Clear search history": "Xóa lịch sử tìm kiếm",
"Quick action disabled": "Đã tắt thao tác nhanh",
"Tap to Toggle Footer": "Nhấn để bật/tắt chân trang",
"Exported successfully": "Xuất thành công",
"Book exported successfully.": "Sách đã được xuất thành công.",
@@ -880,5 +879,8 @@
"Select Voice": "Chọn giọng nói",
"Toggle Sticky Bottom TTS Bar": "Bật/tắt thanh TTS cố định",
"Display what I'm reading on Discord": "Hiển thị sách đang đọc trên Discord",
"Show on Discord": "Hiện trên Discord"
"Show on Discord": "Hiện trên Discord",
"Instant {{action}}": "{{action}} tức thì",
"Instant {{action}} Disabled": "{{action}} tức thì đã tắt",
"Annotation": "Chú thích"
}
@@ -822,7 +822,6 @@
"Show Results": "显示结果",
"Clear search": "清除搜索",
"Clear search history": "清除搜索历史",
"Quick action disabled": "快捷操作已禁用",
"Tap to Toggle Footer": "点击切换页脚",
"Exported successfully": "导出成功",
"Book exported successfully.": "书籍导出成功。",
@@ -880,5 +879,8 @@
"Select Voice": "选择语音",
"Toggle Sticky Bottom TTS Bar": "切换固定TTS栏",
"Display what I'm reading on Discord": "在Discord显示阅读状态",
"Show on Discord": "在Discord显示"
"Show on Discord": "在Discord显示",
"Instant {{action}}": "即时{{action}}",
"Instant {{action}} Disabled": "即时{{action}}已禁用",
"Annotation": "标注"
}
@@ -822,7 +822,6 @@
"Show Results": "顯示結果",
"Clear search": "清除搜尋",
"Clear search history": "清除搜尋歷史",
"Quick action disabled": "快捷操作已停用",
"Tap to Toggle Footer": "點擊切換頁尾",
"Exported successfully": "匯出成功",
"Book exported successfully.": "書籍匯出成功。",
@@ -880,5 +879,8 @@
"Select Voice": "選擇語音",
"Toggle Sticky Bottom TTS Bar": "切換固定TTS欄",
"Display what I'm reading on Discord": "在Discord顯示閱讀狀態",
"Show on Discord": "在Discord顯示"
"Show on Discord": "在Discord顯示",
"Instant {{action}}": "即時{{action}}",
"Instant {{action}} Disabled": "即時{{action}}已停用",
"Annotation": "註解"
}
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { RiDeleteBinLine } from 'react-icons/ri';
import * as CFI from 'foliate-js/epubcfi.js';
@@ -89,6 +89,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const [selectedColor, setSelectedColor] = useState<HighlightColor>(
settings.globalReadSettings.highlightStyles[selectedStyle],
);
const androidTouchEndRef = useRef(false);
const showingPopup =
showAnnotPopup ||
@@ -239,8 +240,10 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const handleNativeTouch = (event: CustomEvent) => {
const ev = event.detail as NativeTouchEventType;
if (ev.type === 'touchstart') {
androidTouchEndRef.current = false;
handleTouchStart();
} else if (ev.type === 'touchend') {
androidTouchEndRef.current = true;
handleTouchEnd();
handlePointerUp(doc, index);
}
@@ -414,6 +417,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const handleQuickAction = () => {
const action = viewSettings.annotationQuickAction;
if (appService?.isAndroidApp && !androidTouchEndRef.current) return;
switch (action) {
case 'copy':
handleCopy(false);
@@ -27,7 +27,11 @@ const QuickActionMenu: React.FC<QuickActionMenuProps> = ({
eventDispatcher.dispatch('toast', {
type: 'info',
timeout: 2000,
message: _('Quick action disabled'),
message: _('Instant {{action}} Disabled', {
action: _(
annotationToolQuickActions.find((btn) => btn.type === action)?.label || _('Annotation'),
),
}),
});
} else {
eventDispatcher.dispatch('toast', {
@@ -53,7 +57,7 @@ const QuickActionMenu: React.FC<QuickActionMenuProps> = ({
{annotationToolQuickActions.map((button) => (
<MenuItem
key={button.type}
label={_(button.label)}
label={_('Instant {{action}}', { action: _(button.label) })}
tooltip={_(button.tooltip)}
buttonClass={selectedAction === button.type ? 'bg-base-300/85' : ''}
Icon={button.Icon}
@@ -1,7 +1,7 @@
import clsx from 'clsx';
import React from 'react';
import { IoIosList, IoMdCloseCircle } from 'react-icons/io';
import { HiArrowLongLeft, HiArrowLongRight } from 'react-icons/hi2';
import { MdChevronLeft, MdChevronRight } from 'react-icons/md';
import { Insets } from '@/types/misc';
import { useEnv } from '@/context/EnvContext';
@@ -39,8 +39,6 @@ const ContentNavBar: React.FC<ContentNavBarProps> = ({
showListButton = true,
hasPrevious,
hasNext,
previousLabel,
nextLabel,
previousTitle,
nextTitle,
showResultsTitle,
@@ -55,14 +53,13 @@ const ContentNavBar: React.FC<ContentNavBarProps> = ({
const { getViewSettings } = useReaderStore();
const viewSettings = getViewSettings(bookKey);
const iconSize16 = useResponsiveSize(16);
const iconSize18 = useResponsiveSize(18);
const iconSize20 = useResponsiveSize(20);
const showSection = appService?.isMobile || !viewSettings?.showHeader;
return (
<div
className='results-nav-bar pointer-events-none absolute inset-0 z-30 flex flex-col items-center justify-between px-4 py-1'
className='results-nav-bar pointer-events-none absolute inset-0 z-30 flex flex-col items-center justify-end'
style={{
top: gridInsets.top,
right: gridInsets.right,
@@ -70,70 +67,74 @@ const ContentNavBar: React.FC<ContentNavBarProps> = ({
left: gridInsets.left,
}}
>
{/* Top bar: Info */}
<div className='bg-base-100 pointer-events-auto relative flex items-center justify-between overflow-hidden rounded-xl px-2 py-1 shadow-lg sm:gap-6'>
{progress !== undefined && progress < 1 && (
<div
className='bg-base-200 absolute inset-y-0 left-0 transition-all duration-300'
style={{ width: `${progress * 100}%` }}
/>
)}
{progress === 1 && <div className='bg-base-200 absolute inset-0' />}
{showListButton && onShowResults ? (
<div className='bg-base-100 mx-auto flex w-full items-center justify-center'>
{/* Bottom bar: Navigation buttons and Info */}
<div className='pointer-events-auto flex h-[52px] max-w-3xl items-center gap-2'>
{/* Previous button */}
<button
title={showResultsTitle || _('Show Results')}
onClick={onShowResults}
className='btn btn-ghost relative z-10 h-8 min-h-8 w-8 p-0 hover:bg-transparent'
title={previousTitle || _('Previous')}
onClick={onPrevious}
disabled={!hasPrevious}
className={clsx(
'flex h-10 w-10 items-center justify-center rounded-full shadow-lg transition-all disabled:opacity-40',
'bg-base-200 hover:bg-base-300 hover:disabled:bg-base-200',
!hasPrevious && 'opacity-40',
)}
>
<IoIosList size={iconSize20} className='text-base-content' />
<MdChevronLeft size={iconSize20} className='text-base-content' />
</button>
) : (
<div className='relative z-10 w-8' />
)}
<div className='relative z-10 flex flex-1 flex-col items-center px-2'>
<span className='line-clamp-1 text-sm font-medium'>{title}</span>
{section && showSection && (
<span className='text-base-content/70 line-clamp-1 text-xs'>{section}</span>
)}
{/* Info bar */}
<div className='bg-base-100 relative flex flex-1 items-center justify-between overflow-hidden rounded-xl px-2 py-1 shadow-lg sm:gap-6'>
{progress !== undefined && progress < 1 && (
<div
className='bg-base-200 absolute inset-y-0 left-0 transition-all duration-300'
style={{ width: `${progress * 100}%` }}
/>
)}
{progress === 1 && <div className='bg-base-200 absolute inset-0' />}
{showListButton && onShowResults ? (
<button
title={showResultsTitle || _('Show Results')}
onClick={onShowResults}
className='btn btn-ghost relative z-10 h-8 min-h-8 w-8 p-0 hover:bg-transparent'
>
<IoIosList size={iconSize20} className='text-base-content' />
</button>
) : (
<div className='relative z-10 w-8' />
)}
<div className='relative z-10 flex flex-1 flex-col items-center px-2'>
<span className='line-clamp-1 text-sm font-medium'>{title}</span>
{section && showSection && (
<span className='text-base-content/70 line-clamp-1 text-xs'>{section}</span>
)}
</div>
<button
title={closeTitle || _('Close')}
onClick={onClose}
className='btn btn-ghost relative z-10 h-8 min-h-8 w-8 p-0 hover:bg-transparent'
>
<IoMdCloseCircle size={iconSize16} />
</button>
</div>
{/* Next button */}
<button
title={nextTitle || _('Next')}
onClick={onNext}
disabled={!hasNext}
className={clsx(
'flex h-10 w-10 items-center justify-center rounded-full shadow-lg transition-all',
'bg-base-200 hover:bg-base-300 hover:disabled:bg-base-200',
!hasNext && 'opacity-40',
)}
>
<MdChevronRight size={iconSize20} className='text-base-content' />
</button>
</div>
<button
title={closeTitle || _('Close')}
onClick={onClose}
className='btn btn-ghost relative z-10 h-8 min-h-8 w-8 p-0 hover:bg-transparent'
>
<IoMdCloseCircle size={iconSize16} />
</button>
</div>
{/* Bottom bar: Navigation buttons */}
<div className='bg-base-200 pointer-events-auto flex items-center justify-between gap-6 rounded-xl px-4 py-0 shadow-lg'>
<button
title={previousTitle || _('Previous')}
onClick={onPrevious}
disabled={!hasPrevious}
className={clsx(
'btn btn-ghost flex h-auto min-h-0 flex-1 flex-col items-center gap-0 p-1 hover:bg-transparent',
!hasPrevious && 'opacity-40 disabled:bg-transparent',
)}
>
<HiArrowLongLeft size={iconSize18} className='text-base-content' />
<span className='text-sm font-medium'>{previousLabel || _('Previous')}</span>
</button>
<button
title={nextTitle || _('Next')}
onClick={onNext}
disabled={!hasNext}
className={clsx(
'btn btn-ghost flex h-auto min-h-0 flex-1 flex-col items-center gap-0 p-1 hover:bg-transparent',
!hasNext && 'opacity-40 disabled:bg-transparent',
)}
>
<HiArrowLongRight size={iconSize18} className='text-base-content' />
<span className='text-sm font-medium'>{nextLabel || _('Next')}</span>
</button>
</div>
</div>
);
@@ -345,7 +345,7 @@ const SearchBar: React.FC<SearchBarProps> = ({ isVisible, bookKey, onHideSearchB
{searchTerm && (
<button
onClick={handleClearInput}
className='absolute end-8 flex h-8 w-8 items-center justify-center bg-transparent'
className='absolute end-10 flex h-8 w-8 items-center justify-center bg-transparent'
aria-label={_('Clear search')}
>
<IoMdCloseCircle size={iconSize16} className='text-base-content/75' />
@@ -15,7 +15,7 @@ import { TTSController, SILENCE_DATA, TTSMark, TTSHighlightOptions } from '@/ser
import { getMediaSession, TauriMediaSession } from '@/libs/mediaSession';
import { getPopupPosition, Position } from '@/utils/sel';
import { eventDispatcher } from '@/utils/event';
import { parseSSMLLang } from '@/utils/ssml';
import { genSSMLRaw, parseSSMLLang } from '@/utils/ssml';
import { throttle } from '@/utils/throttle';
import { Insets } from '@/types/misc';
import { Overlay } from '@/components/Overlay';
@@ -75,6 +75,7 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
const mediaSessionRef = useRef<TauriMediaSession | MediaSession | null>(null);
const [ttsController, setTtsController] = useState<TTSController | null>(null);
const [ttsClientsInited, setTtsClientsInitialized] = useState(false);
const ttsOnRef = useRef(false);
// this enables WebAudio to play even when the mute toggle switch is ON
const unblockAudio = () => {
@@ -347,6 +348,8 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
const handleTTSSpeak = async (event: CustomEvent) => {
const { bookKey: ttsBookKey, range, oneTime = false } = event.detail;
if (bookKey !== ttsBookKey) return;
if (ttsOnRef.current) return;
ttsOnRef.current = true;
const view = getView(bookKey);
const progress = getProgress(bookKey);
@@ -361,7 +364,8 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
return;
}
let ttsFromRange = range;
const ttsSpeakRange = range as Range | null;
let ttsFromRange = ttsSpeakRange;
if (!ttsFromRange && viewSettings.ttsLocation) {
const { location } = progress;
const ttsCfi = viewSettings.ttsLocation;
@@ -394,9 +398,7 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
await initMediaSession();
setTtsClientsInitialized(false);
if (!oneTime) {
setShowIndicator(true);
}
setShowIndicator(true);
const ttsController = new TTSController(appService, view, !!user?.id, preprocessSSMLForTTS);
ttsControllerRef.current = ttsController;
setTtsController(ttsController);
@@ -405,7 +407,10 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
await ttsController.initViewTTS(
getTTSHighlightOptions(viewSettings.ttsHighlightOptions, viewSettings.isEink),
);
const ssml = view.tts?.from(ttsFromRange);
const ssml =
oneTime && ttsSpeakRange
? genSSMLRaw(ttsSpeakRange.toString().trim())
: view.tts?.from(ttsFromRange);
if (ssml) {
const lang = parseSSMLLang(ssml, primaryLang) || 'en';
setIsPlaying(true);
@@ -413,7 +418,7 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
ttsController.setLang(lang);
ttsController.setRate(viewSettings.ttsRate);
ttsController.speak(ssml, oneTime);
ttsController.speak(ssml, oneTime, () => handleStop(bookKey));
ttsController.setTargetLang(getTTSTargetLang() || '');
}
setTtsClientsInitialized(true);
@@ -507,6 +512,7 @@ const TTSControl: React.FC<TTSControlProps> = ({ bookKey, gridInsets }) => {
}
await deinitMediaSession();
setTTSEnabled(bookKey, false);
ttsOnRef.current = false;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[appService],
@@ -145,6 +145,9 @@ export const useTextSelector = (
} else if (isPointerInside) {
isUpToPopup.current = true;
makeSelection(sel, index, true);
} else if (appService?.isAndroidApp) {
isUpToPopup.current = false;
makeSelection(sel, index, true);
}
}
};
+3 -1
View File
@@ -165,7 +165,9 @@ export const Toast = () => {
onClick={handleDismiss}
className={clsx(
'flex-shrink-0 rounded-lg p-1 transition-colors',
toastType === 'info' ? 'hover:bg-base-300' : 'hover:bg-white/20 active:bg-white/30',
toastType === 'info'
? 'hover:bg-base-300 hidden'
: 'hover:bg-white/20 active:bg-white/30',
)}
aria-label='Dismiss'
>
@@ -197,13 +197,15 @@ export class TTSController extends EventTarget {
}
const { plainText, marks } = parseSSMLMarks(ssml);
if ((!plainText || marks.length === 0) && !oneTime) {
resolve();
return await this.forward();
} else {
this.dispatchSpeakMark(marks[0]);
if (!oneTime) {
if (!plainText || marks.length === 0) {
resolve();
return await this.forward();
} else {
this.dispatchSpeakMark(marks[0]);
}
await this.preloadSSML(ssml, signal);
}
await this.preloadSSML(ssml, signal);
const iter = await this.ttsClient.speak(ssml, signal);
let lastCode;
for await (const { code } of iter) {
@@ -236,11 +238,19 @@ export class TTSController extends EventTarget {
await this.#currentSpeakPromise.catch((e) => this.error(e));
}
async speak(ssml: string | Promise<string>, oneTime = false) {
async speak(ssml: string | Promise<string>, oneTime = false, oneTimeCallback?: () => void) {
await this.initViewTTS();
this.#speak(ssml, oneTime).catch((e) => this.error(e));
this.preloadNextSSML();
this.dispatchSpeakMark();
this.#speak(ssml, oneTime)
.then(() => {
if (oneTime && oneTimeCallback) {
oneTimeCallback();
}
})
.catch((e) => this.error(e));
if (!oneTime) {
this.preloadNextSSML();
this.dispatchSpeakMark();
}
}
play() {
@@ -391,7 +401,7 @@ export class TTSController extends EventTarget {
dispatchSpeakMark(mark?: TTSMark) {
this.dispatchEvent(new CustomEvent('tts-speak-mark', { detail: mark || { text: '' } }));
if (mark) {
if (mark && mark.name !== '-1') {
const range = this.view.tts?.setMark(mark.name);
this.dispatchEvent(new CustomEvent('tts-highlight-mark', { detail: range }));
}
+1 -1
View File
@@ -78,7 +78,7 @@ export const isPointerInsideSelection = (selection: Selection, ev: PointerEvent)
if (selection.rangeCount === 0) return false;
const range = selection.getRangeAt(0);
const rects = range.getClientRects();
const padding = 80;
const padding = 50;
for (let i = 0; i < rects.length; i++) {
const rect = rects[i]!;
if (
+6
View File
@@ -17,6 +17,12 @@ export const genSSML = (lang: string, text: string, voice: string, rate: number)
`;
};
export const genSSMLRaw = (text: string) => {
return `
<speak xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="en"><mark name="-1"/>${text}</speak>
`;
};
export const parseSSMLLang = (ssml: string, primaryLang?: string): string => {
let lang = 'en';
const match = ssml.match(/xml:lang\s*=\s*"([^"]+)"/);