From 1c8b3e1c13d19fc4f603337bda8532f46cd519fc Mon Sep 17 00:00:00 2001 From: janice Date: Thu, 23 Oct 2025 19:29:57 +0530 Subject: [PATCH 1/4] Extend the text selection menu in ReaderFragment to include two new actions Translate and Dictionary. --- .../wsreader/reader/VisualReaderFragment.kt | 77 +++++++++++++++++++ app/src/main/res/menu/menu_action_mode.xml | 11 +++ app/src/main/res/values-ar/strings.xml | 2 + app/src/main/res/values-bn/strings.xml | 2 + app/src/main/res/values-cs/strings.xml | 2 + app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-es/strings.xml | 2 + app/src/main/res/values-hi/strings.xml | 2 + app/src/main/res/values-it/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 8 ++ 11 files changed, 112 insertions(+) diff --git a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt index 0b1c167..0541ff1 100644 --- a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt +++ b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt @@ -8,12 +8,14 @@ package org.cis_india.wsreader.reader import android.app.AlertDialog import android.app.SearchManager +import android.content.ActivityNotFoundException import android.content.Context import android.content.ClipData import android.content.ClipboardManager import android.content.Intent import android.graphics.Color import android.graphics.RectF +import android.net.Uri import android.os.Bundle import android.os.Build import android.view.ActionMode @@ -395,6 +397,8 @@ abstract class VisualReaderFragment : BaseReaderFragment() { menu.findItem(R.id.note).isVisible = true menu.findItem(R.id.copy).isVisible = true menu.findItem(R.id.web_search).isVisible = true + menu.findItem(R.id.dictionary).isVisible = true + menu.findItem(R.id.translate).isVisible = true } return true } @@ -406,6 +410,8 @@ abstract class VisualReaderFragment : BaseReaderFragment() { R.id.note -> showAnnotationPopup() R.id.copy -> copySelectionToClipboard() R.id.web_search -> searchSelectionOnWeb() + R.id.dictionary -> openDictionary() + R.id.translate -> openTranslate() else -> return false } @@ -614,6 +620,77 @@ abstract class VisualReaderFragment : BaseReaderFragment() { } } + private fun openDictionary() { + viewLifecycleOwner.lifecycleScope.launch { + val navigator = navigator as? SelectableNavigator ?: return@launch + val selection = navigator.currentSelection() ?: return@launch + + val selectedText = selection.locator.text.highlight.toString().trim() + + if(selectedText.isNotEmpty()) { + val dictionaryIntent = Intent(Intent.ACTION_PROCESS_TEXT).apply { + type = "text/plain" + putExtra(Intent.EXTRA_PROCESS_TEXT, selectedText) + putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true) + } + + val browserIntent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse("https://www.onelook.com/?w=${Uri.encode(selectedText)}") + } + + try { + startActivity(Intent.createChooser(dictionaryIntent, null)) + } catch (e: ActivityNotFoundException) { + try { + startActivity(Intent.createChooser(browserIntent, null)) + } catch (e: ActivityNotFoundException) { + Toast.makeText( + context, + getString(R.string.no_app_found_dictionary), + Toast.LENGTH_SHORT + ).show() + } + } + + navigator.clearSelection() + } else { + Toast.makeText( + context, + getString(R.string.no_text_selected_for_dictionary), + Toast.LENGTH_SHORT + ).show() + } + } + } + + private fun openTranslate() { + viewLifecycleOwner.lifecycleScope.launch { + val navigator = navigator as? SelectableNavigator ?: return@launch + val selection = navigator.currentSelection() ?: return@launch + + val selectedText = selection.locator.text.highlight.toString().trim() + + if (selectedText.isNotEmpty()) { + val translateUrl = "https://translate.google.com/?sl=auto&tl=en&text=${Uri.encode(selectedText)}" + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(translateUrl)) + + try { + startActivity(intent) + } catch (e: ActivityNotFoundException) { + Toast.makeText( + requireContext(), + getString(R.string.no_app_found_for_translation), + Toast.LENGTH_SHORT + ).show() + } + + navigator.clearSelection() + } else { + Toast.makeText(context, getString(R.string.no_text_selected_for_translation), Toast.LENGTH_SHORT).show() + } + } + } + private fun showFootnotePopup( text: CharSequence, ) { diff --git a/app/src/main/res/menu/menu_action_mode.xml b/app/src/main/res/menu/menu_action_mode.xml index b9c243a..2388271 100644 --- a/app/src/main/res/menu/menu_action_mode.xml +++ b/app/src/main/res/menu/menu_action_mode.xml @@ -37,4 +37,15 @@ app:showAsAction="ifRoom"> + + + \ No newline at end of file diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 5c8b4ff..8522c4f 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -41,6 +41,8 @@ تم النسخ! بحث ويب مشاركة + ترجمة + قاموس الاعدادات عام فتح الكتب الإلكترونية مع … diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index 530663b..56dae86 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -42,6 +42,8 @@ অনুলিপি করা হয়েছে! ওয়েব অনুসন্ধান শেয়ার করুন + অনুবাদ + অভিধান সেটিং সাধারণ এর মাধ্যমে ইবুক খুলুন... diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 1a0ba67..88f4fb7 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -37,6 +37,8 @@ Zkopírováno! Webový vyhledávač Sdílet + Přeložit + Slovník Nastavení Obecné Otevírat e-knihy pomocí… diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a783658..6536282 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -37,6 +37,8 @@ Kopiert! Websuche Teilen + Übersetzen + Wörterbuch Einstellungen Allgemein E-Books öffnen mit … diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 4d7a264..1d9edd3 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -37,6 +37,8 @@ ¡Copiado! Búsqueda web Compartir + Traducir + Diccionario Ajustes General Abrir ebooks con… diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 689af21..c621f10 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -41,6 +41,8 @@ कॉपी किया गया! वेब खोज साझा करें + अनुवाद करें + शब्दकोष सेटिंग्स सामान्य ईबुक्स को इसके साथ खोलें… diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 436e14d..3afa6fe 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -40,6 +40,8 @@ Copiato! Ricerca web Condividi + Traduci + Significato Impostazioni Generale Apri ebooks con… diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 3ad09c1..f32ce8b 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -41,6 +41,8 @@ 已複製! 網頁搜尋 分享 + 翻譯 + 字典 設定 一般 開啟電子書以… diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c5a9715..f50acec 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,6 +53,14 @@ Copied! Web Search Share + Translate + Dictionary + + No app found for translation + No app found for dictionary lookup + No text selected for translation + No text selected for dictionary lookup + Settings From 73f4b61a30e4c6e8338b0d583dd1111ae906a878 Mon Sep 17 00:00:00 2001 From: janice Date: Thu, 23 Oct 2025 20:49:34 +0530 Subject: [PATCH 2/4] Update openDictionary() function to allow only browser intent for dictionary lookup. --- .../wsreader/reader/VisualReaderFragment.kt | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt index 0541ff1..63777cb 100644 --- a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt +++ b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt @@ -628,28 +628,18 @@ abstract class VisualReaderFragment : BaseReaderFragment() { val selectedText = selection.locator.text.highlight.toString().trim() if(selectedText.isNotEmpty()) { - val dictionaryIntent = Intent(Intent.ACTION_PROCESS_TEXT).apply { - type = "text/plain" - putExtra(Intent.EXTRA_PROCESS_TEXT, selectedText) - putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true) - } - val browserIntent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("https://www.onelook.com/?w=${Uri.encode(selectedText)}") } try { - startActivity(Intent.createChooser(dictionaryIntent, null)) + startActivity(browserIntent) } catch (e: ActivityNotFoundException) { - try { - startActivity(Intent.createChooser(browserIntent, null)) - } catch (e: ActivityNotFoundException) { - Toast.makeText( - context, - getString(R.string.no_app_found_dictionary), - Toast.LENGTH_SHORT - ).show() - } + Toast.makeText( + context, + getString(R.string.no_app_found_dictionary), + Toast.LENGTH_SHORT + ).show() } navigator.clearSelection() From 885810cd819d0e7e9bf865926550c4c417b54b63 Mon Sep 17 00:00:00 2001 From: janice Date: Thu, 23 Oct 2025 20:53:38 +0530 Subject: [PATCH 3/4] Correct value of dictionary values-it. --- app/src/main/res/values-it/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3afa6fe..3fc3175 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -41,7 +41,7 @@ Ricerca web Condividi Traduci - Significato + Dizionario Impostazioni Generale Apri ebooks con… From 4fa38d7c8cb18fbafda3a7c3dc7741fca41dcedf Mon Sep 17 00:00:00 2001 From: janice Date: Sat, 1 Nov 2025 01:41:09 +0530 Subject: [PATCH 4/4] Add support for dictionary and translate for multiple languages by fetching language code of book and adding to room db. --- .../java/org/cis_india/wsreader/MyneApp.kt | 9 ++++- .../cis_india/wsreader/data/BookRepository.kt | 13 +++++-- .../cis_india/wsreader/data/db/AppDatabase.kt | 6 ++-- .../cis_india/wsreader/data/db/BooksDao.kt | 6 ++++ .../cis_india/wsreader/data/db/Migrations.kt | 11 ++++++ .../org/cis_india/wsreader/data/model/Book.kt | 7 +++- .../cis_india/wsreader/domain/Bookshelf.kt | 16 +++++---- .../wsreader/reader/ReaderRepository.kt | 18 ++++++++++ .../wsreader/reader/ReaderViewModel.kt | 5 +++ .../wsreader/reader/VisualReaderFragment.kt | 35 ++++++++++++++++--- .../detail/viewmodels/BookDetailViewModel.kt | 5 ++- .../wsreader/utils/DictionaryUtils.kt | 31 ++++++++++++++++ 12 files changed, 144 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/org/cis_india/wsreader/data/db/Migrations.kt create mode 100644 app/src/main/java/org/cis_india/wsreader/utils/DictionaryUtils.kt diff --git a/app/src/main/java/org/cis_india/wsreader/MyneApp.kt b/app/src/main/java/org/cis_india/wsreader/MyneApp.kt index 75e0093..e78b8b1 100644 --- a/app/src/main/java/org/cis_india/wsreader/MyneApp.kt +++ b/app/src/main/java/org/cis_india/wsreader/MyneApp.kt @@ -33,6 +33,7 @@ import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import okhttp3.OkHttpClient +import org.cis_india.wsreader.api.BookAPI import java.io.File import java.util.concurrent.TimeUnit @@ -58,6 +59,9 @@ class MyneApp : Application(), ImageLoaderFactory { lateinit var bookRepository: BookRepository private set + lateinit var bookApi: BookAPI + private set + lateinit var bookshelf: Bookshelf private set @@ -81,6 +85,8 @@ class MyneApp : Application(), ImageLoaderFactory { bookRepository = BookRepository(database.booksDao()) + bookApi = BookAPI(this) + val downloadsDir = File(cacheDir, "downloads") // Cleans the download dir. @@ -108,7 +114,8 @@ class MyneApp : Application(), ImageLoaderFactory { this@MyneApp, readium, bookRepository, - navigatorPreferences + navigatorPreferences, + bookApi ) } diff --git a/app/src/main/java/org/cis_india/wsreader/data/BookRepository.kt b/app/src/main/java/org/cis_india/wsreader/data/BookRepository.kt index 41d53bd..1320adb 100644 --- a/app/src/main/java/org/cis_india/wsreader/data/BookRepository.kt +++ b/app/src/main/java/org/cis_india/wsreader/data/BookRepository.kt @@ -83,7 +83,8 @@ class BookRepository( mediaType: MediaType, publication: Publication, cover: File, - wdIdentifier: String? = null + wdIdentifier: String? = null, + bookLanguageCode: String? = null ): Long { val book = Book( creation = Date().time, @@ -93,11 +94,19 @@ class BookRepository( identifier = wdIdentifier?: publication.metadata.identifier ?: "", mediaType = mediaType, progression = "{}", - cover = cover.path + cover = cover.path, + languageCode = bookLanguageCode ?: "en" ) return booksDao.insertBook(book) } + suspend fun updateBookLanguage(bookId: Long, languageCode: String) = + booksDao.updateBookLanguage(bookId, languageCode) + + fun getBookLanguage(bookId: Long): Flow { + return booksDao.getBookLanguage(bookId) + } + suspend fun deleteBook(id: Long) = booksDao.deleteBook(id) } diff --git a/app/src/main/java/org/cis_india/wsreader/data/db/AppDatabase.kt b/app/src/main/java/org/cis_india/wsreader/data/db/AppDatabase.kt index cf990c4..a48e242 100644 --- a/app/src/main/java/org/cis_india/wsreader/data/db/AppDatabase.kt +++ b/app/src/main/java/org/cis_india/wsreader/data/db/AppDatabase.kt @@ -19,7 +19,7 @@ import org.cis_india.wsreader.data.model.Highlight @Database( entities = [Book::class, Bookmark::class, Highlight::class, Catalog::class], - version = 1, + version = 2, exportSchema = false ) @TypeConverters( @@ -45,7 +45,9 @@ abstract class AppDatabase : RoomDatabase() { context.applicationContext, AppDatabase::class.java, "database" - ).build() + ) + .addMigrations(MIGRATION_1_2) + .build() INSTANCE = instance return instance } diff --git a/app/src/main/java/org/cis_india/wsreader/data/db/BooksDao.kt b/app/src/main/java/org/cis_india/wsreader/data/db/BooksDao.kt index 737a49f..3e58e17 100644 --- a/app/src/main/java/org/cis_india/wsreader/data/db/BooksDao.kt +++ b/app/src/main/java/org/cis_india/wsreader/data/db/BooksDao.kt @@ -123,4 +123,10 @@ interface BooksDao { "UPDATE " + Book.TABLE_NAME + " SET " + Book.PROGRESSION + " = :locator WHERE " + Book.ID + "= :id" ) suspend fun saveProgression(locator: String, id: Long) + + @Query("UPDATE " + Book.TABLE_NAME + " SET language_code = :languageCode WHERE " + Book.ID + " = :bookId") + suspend fun updateBookLanguage(bookId: Long, languageCode: String) + + @Query("SELECT language_code FROM books WHERE id = :bookId LIMIT 1") + fun getBookLanguage(bookId: Long): Flow } diff --git a/app/src/main/java/org/cis_india/wsreader/data/db/Migrations.kt b/app/src/main/java/org/cis_india/wsreader/data/db/Migrations.kt new file mode 100644 index 0000000..8edd479 --- /dev/null +++ b/app/src/main/java/org/cis_india/wsreader/data/db/Migrations.kt @@ -0,0 +1,11 @@ +package org.cis_india.wsreader.data.db + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +val MIGRATION_1_2 = object : Migration(1, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + // Add the new column language_code with default value + database.execSQL("ALTER TABLE books ADD COLUMN language_code TEXT NOT NULL DEFAULT 'auto'") + } +} \ No newline at end of file diff --git a/app/src/main/java/org/cis_india/wsreader/data/model/Book.kt b/app/src/main/java/org/cis_india/wsreader/data/model/Book.kt index 2be5558..9746738 100644 --- a/app/src/main/java/org/cis_india/wsreader/data/model/Book.kt +++ b/app/src/main/java/org/cis_india/wsreader/data/model/Book.kt @@ -35,6 +35,8 @@ data class Book( val rawMediaType: String, @ColumnInfo(name = COVER) val cover: String, + @ColumnInfo(name = LANGUAGE_CODE) + val languageCode: String ) { constructor( @@ -47,6 +49,7 @@ data class Book( progression: String? = null, mediaType: MediaType, cover: String, + languageCode: String, ) : this( id = id, creation = creation, @@ -56,7 +59,8 @@ data class Book( identifier = identifier, progression = progression, rawMediaType = mediaType.toString(), - cover = cover + cover = cover, + languageCode = languageCode ) val url: AbsoluteUrl get() = AbsoluteUrl(href)!! @@ -81,5 +85,6 @@ data class Book( const val PROGRESSION = "progression" const val MEDIA_TYPE = "media_type" const val COVER = "cover" + const val LANGUAGE_CODE = "language_code" } } diff --git a/app/src/main/java/org/cis_india/wsreader/domain/Bookshelf.kt b/app/src/main/java/org/cis_india/wsreader/domain/Bookshelf.kt index 152c91f..06e3f18 100644 --- a/app/src/main/java/org/cis_india/wsreader/domain/Bookshelf.kt +++ b/app/src/main/java/org/cis_india/wsreader/domain/Bookshelf.kt @@ -52,10 +52,11 @@ class Bookshelf( fun importPublicationFromStorage( uri: Uri, - wdIdentifier: String? = null + wdIdentifier: String? = null, + bookLanguageCode: String? = null ) { coroutineScope.launch { - addBookFeedback(publicationRetriever.retrieveFromStorage(uri),wdIdentifier) + addBookFeedback(publicationRetriever.retrieveFromStorage(uri),wdIdentifier, bookLanguageCode) } } @@ -93,10 +94,11 @@ class Bookshelf( private suspend fun addBookFeedback( retrieverResult: Try, - wdIdentifier: String? = null + wdIdentifier: String? = null, + bookLanguageCode: String? = null ) { retrieverResult - .map { addBook(it.publication.toUrl(), it.format, it.coverUrl, wdIdentifier) } + .map { addBook(it.publication.toUrl(), it.format, it.coverUrl, wdIdentifier, bookLanguageCode) } .onSuccess { channel.send(Event.ImportPublicationSuccess) } .onFailure { channel.send(Event.ImportPublicationError(it)) } } @@ -116,7 +118,8 @@ class Bookshelf( url: AbsoluteUrl, format: Format? = null, coverUrl: AbsoluteUrl? = null, - wdIdentifier: String? = null + wdIdentifier: String? = null, + bookLanguageCode: String? = null ): Try { val asset = if (format == null) { @@ -148,7 +151,8 @@ class Bookshelf( asset.format.mediaType, publication, coverFile, - wdIdentifier + wdIdentifier, + bookLanguageCode, ) if (id == -1L) { coverFile.delete() diff --git a/app/src/main/java/org/cis_india/wsreader/reader/ReaderRepository.kt b/app/src/main/java/org/cis_india/wsreader/reader/ReaderRepository.kt index 53dfd59..6136211 100644 --- a/app/src/main/java/org/cis_india/wsreader/reader/ReaderRepository.kt +++ b/app/src/main/java/org/cis_india/wsreader/reader/ReaderRepository.kt @@ -24,6 +24,7 @@ import org.readium.r2.shared.util.DebugError import org.readium.r2.shared.util.Try import org.readium.r2.shared.util.getOrElse import org.cis_india.wsreader.Readium +import org.cis_india.wsreader.api.BookAPI import org.cis_india.wsreader.data.BookRepository import org.cis_india.wsreader.domain.PublicationError import org.cis_india.wsreader.reader.preferences.AndroidTtsPreferencesManagerFactory @@ -46,6 +47,7 @@ class ReaderRepository( private val readium: Readium, private val bookRepository: BookRepository, private val preferencesDataStore: DataStore, + private val bookApi: BookAPI ) { private val coroutineQueue: CoroutineQueue = @@ -73,6 +75,9 @@ class ReaderRepository( val book = checkNotNull(bookRepository.get(bookId)) { "Cannot find book in database." } + //Update book language if not set in books entity in room db + updateBookLanguageIfAuto(bookId, book.identifier, book.languageCode) + val asset = readium.assetRetriever.retrieve( book.url, book.mediaType @@ -124,6 +129,19 @@ class ReaderRepository( } } + private suspend fun updateBookLanguageIfAuto(bookId: Long, identifier: String, currentLang: String) { + if(currentLang != "auto") return + + try { + val bookSet = bookApi.getBookById(identifier).getOrNull()!! + val language = bookSet.books.firstOrNull()?.languages?.firstOrNull()?:"en" + + bookRepository.updateBookLanguage(bookId, language) + } catch (e: Exception) { + + } + } + private suspend fun openAudio( bookId: Long, publication: Publication, diff --git a/app/src/main/java/org/cis_india/wsreader/reader/ReaderViewModel.kt b/app/src/main/java/org/cis_india/wsreader/reader/ReaderViewModel.kt index aea20bb..3f0a1ef 100644 --- a/app/src/main/java/org/cis_india/wsreader/reader/ReaderViewModel.kt +++ b/app/src/main/java/org/cis_india/wsreader/reader/ReaderViewModel.kt @@ -125,6 +125,11 @@ class ReaderViewModel( bookRepository.deleteBookmark(id) } + + val bookLanguage: Flow = bookRepository + .getBookLanguage(bookId) + .map { it ?: "en" } + // Highlights val highlights: Flow> by lazy { diff --git a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt index 63777cb..7a92afc 100644 --- a/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt +++ b/app/src/main/java/org/cis_india/wsreader/reader/VisualReaderFragment.kt @@ -18,6 +18,7 @@ import android.graphics.RectF import android.net.Uri import android.os.Bundle import android.os.Build +import android.util.Log import android.view.ActionMode import android.view.Gravity import android.view.LayoutInflater @@ -53,6 +54,7 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import androidx.core.view.MenuHost import androidx.core.view.MenuProvider +import androidx.fragment.app.activityViewModels import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope @@ -86,6 +88,7 @@ import org.cis_india.wsreader.reader.tts.TtsViewModel import org.cis_india.wsreader.utils.clearPadding import org.cis_india.wsreader.utils.extensions.confirmDialog import org.cis_india.wsreader.utils.extensions.throttleLatest +import org.cis_india.wsreader.utils.getDictionaryUrl import org.cis_india.wsreader.utils.hideSystemUi import org.cis_india.wsreader.utils.observeWhenStarted import org.cis_india.wsreader.utils.padSystemUi @@ -103,8 +106,12 @@ abstract class VisualReaderFragment : BaseReaderFragment() { protected var binding: FragmentReaderBinding by viewLifecycle() + private val viewModel: ReaderViewModel by activityViewModels() + private lateinit var navigatorFragment: Fragment + private var bookLanguage: String = "en" + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -122,6 +129,14 @@ abstract class VisualReaderFragment : BaseReaderFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.bookLanguage.collect { language -> + bookLanguage = language + } + } + } + navigatorFragment = navigator as Fragment (navigator as OverflowableNavigator).apply { @@ -592,7 +607,7 @@ abstract class VisualReaderFragment : BaseReaderFragment() { val clipboard = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("selected_text", selection.locator.text.highlight.toString()) clipboard.setPrimaryClip(clip) - + //Only show Toast in Android 12L (API level 32) and lower. Android 13 and higher has standard feedback when content enters the clipboard if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) Toast.makeText(context, R.string.copied, Toast.LENGTH_SHORT).show() @@ -628,12 +643,22 @@ abstract class VisualReaderFragment : BaseReaderFragment() { val selectedText = selection.locator.text.highlight.toString().trim() if(selectedText.isNotEmpty()) { - val browserIntent = Intent(Intent.ACTION_VIEW).apply { - data = Uri.parse("https://www.onelook.com/?w=${Uri.encode(selectedText)}") + val lang = bookLanguage.lowercase() + + val dictionaryUrl = getDictionaryUrl(lang, selectedText) + + val intent = if (dictionaryUrl != null) { + Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse(dictionaryUrl) + } + } else { + Intent(Intent.ACTION_WEB_SEARCH).apply { + putExtra(SearchManager.QUERY, selectedText) + } } try { - startActivity(browserIntent) + startActivity(intent) } catch (e: ActivityNotFoundException) { Toast.makeText( context, @@ -661,7 +686,7 @@ abstract class VisualReaderFragment : BaseReaderFragment() { val selectedText = selection.locator.text.highlight.toString().trim() if (selectedText.isNotEmpty()) { - val translateUrl = "https://translate.google.com/?sl=auto&tl=en&text=${Uri.encode(selectedText)}" + val translateUrl = "https://translate.google.com/?sl=$bookLanguage&tl=en&text=${Uri.encode(selectedText)}" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(translateUrl)) try { diff --git a/app/src/main/java/org/cis_india/wsreader/ui/screens/detail/viewmodels/BookDetailViewModel.kt b/app/src/main/java/org/cis_india/wsreader/ui/screens/detail/viewmodels/BookDetailViewModel.kt index 9fe5543..e5ac9c8 100644 --- a/app/src/main/java/org/cis_india/wsreader/ui/screens/detail/viewmodels/BookDetailViewModel.kt +++ b/app/src/main/java/org/cis_india/wsreader/ui/screens/detail/viewmodels/BookDetailViewModel.kt @@ -131,6 +131,8 @@ class BookDetailViewModel @Inject constructor( fun downloadBook( book: Book, downloadProgressListener: (Float, Int) -> Unit ) { + val languageCode = book.languages.firstOrNull()?.lowercase() ?: "en" + bookDownloader.downloadBook(book = book, downloadProgressListener = downloadProgressListener, onDownloadSuccess = { filePath -> @@ -138,7 +140,8 @@ class BookDetailViewModel @Inject constructor( val uri = Uri.fromFile(file) app.bookshelf.importPublicationFromStorage( uri = uri, - wdIdentifier = book.id.toString() + wdIdentifier = book.id.toString(), + languageCode ) //state = state.copy(bookLibraryItem = libraryDao.getItemByBookId(book.id)) } diff --git a/app/src/main/java/org/cis_india/wsreader/utils/DictionaryUtils.kt b/app/src/main/java/org/cis_india/wsreader/utils/DictionaryUtils.kt new file mode 100644 index 0000000..99a8a4a --- /dev/null +++ b/app/src/main/java/org/cis_india/wsreader/utils/DictionaryUtils.kt @@ -0,0 +1,31 @@ +package org.cis_india.wsreader.utils + +import android.net.Uri + +fun getDictionaryUrl(lang: String, word: String): String? { + val encodedWord = Uri.encode(word) + return when (lang.lowercase()) { + "as" -> "https://www.xobdo.org/dic/$encodedWord" + "fr" -> "https://www.larousse.fr/dictionnaires/francais/$encodedWord" + "es" -> "https://www.wordreference.com/definicion/$encodedWord" + "en" -> "https://www.onelook.com/?w=$encodedWord" + "bn", + "ca", + "cs", + "hi", + "id", + "it", + "kn", + "ml", + "mr", + "pl", + "sv", + "ta", + "te", + "uk", + "vi" -> + "https://$lang.wiktionary.org/wiki/$encodedWord" + + else -> null + } +} \ No newline at end of file