* Added support for external dictionary apps and a dictionary settings sheet. * Refactored external dictionary integration and improved package visibility - Updated `AndroidManifest.xml` with `<queries>` for common dictionary apps and intent actions (`PROCESS_TEXT`, `SEARCH`, `SEND`) to support Android 11+ package visibility. - Refactored `ExternalDictionaryHelper` to streamline dictionary discovery using `Intent.ACTION_PROCESS_TEXT` and `colordict.intent.action.SEARCH`. - Added a package blocklist in `ExternalDictionaryHelper` to filter out system services (e.g., Samsung Pass, GMS) from dictionary lists. - Simplified `launchDictionary` logic to prioritize `PROCESS_TEXT` intents. - Fixed a bug in `PdfViewerScreen` to only show the dictionary upsell dialog when `useOnlineDictionary` is enabled. * Refactored dictionary settings into a dialog and updated dictionary selection logic. - Renamed `DictionarySettingsSheet` to `DictionarySettingsDialog` and converted it from a bottom sheet to a formal dialog. - Redesigned the dictionary settings UI with a clearer distinction between AI and external app modes. - Added a "Search" option to the external dictionary list that triggers a web search. - Updated `ExternalDictionaryHelper` to include a package blocklist and support for generic web search intents. - Simplified `PdfHelper` by removing Pro user checks for the "Dictionary" action. - Updated icons for dictionary settings across the EPUB and PDF readers.
154 lines
No EOL
5.3 KiB
Kotlin
154 lines
No EOL
5.3 KiB
Kotlin
// ExternalDictionaryHelper.kt
|
|
package com.aryan.reader.epubreader
|
|
|
|
import android.app.SearchManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.pm.PackageManager
|
|
import android.graphics.drawable.Drawable
|
|
import android.os.Build
|
|
import android.widget.Toast
|
|
import timber.log.Timber
|
|
|
|
data class ExternalDictionaryApp(
|
|
val label: String,
|
|
val packageName: String,
|
|
val icon: Drawable?
|
|
)
|
|
|
|
object ExternalDictionaryHelper {
|
|
const val GOOGLE_SEARCH_PKG = "app.internal.google_search"
|
|
|
|
private val PACKAGE_BLOCKLIST = setOf(
|
|
"com.samsung.android.samsungpassautofill",
|
|
"com.samsung.android.samsungpass",
|
|
"com.samsung.android.app.pass",
|
|
"com.google.android.gms",
|
|
"com.truecaller",
|
|
"com.adobe.reader",
|
|
"com.reddit.frontpage"
|
|
)
|
|
|
|
fun getAvailableDictionaries(context: Context): List<ExternalDictionaryApp> {
|
|
val pm = context.packageManager
|
|
val apps = mutableListOf<ExternalDictionaryApp>()
|
|
val addedPackages = mutableSetOf<String>()
|
|
|
|
val processTextIntent = Intent(Intent.ACTION_PROCESS_TEXT).setType("text/plain")
|
|
val textResolvers = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
pm.queryIntentActivities(processTextIntent, PackageManager.ResolveInfoFlags.of(0))
|
|
} else {
|
|
@Suppress("DEPRECATION") pm.queryIntentActivities(processTextIntent, 0)
|
|
}
|
|
|
|
textResolvers.forEach { ri ->
|
|
val pkg = ri.activityInfo.packageName
|
|
if (!PACKAGE_BLOCKLIST.contains(pkg) && addedPackages.add(pkg)) {
|
|
apps.add(ExternalDictionaryApp(
|
|
label = ri.loadLabel(pm).toString(),
|
|
packageName = pkg,
|
|
icon = ri.loadIcon(pm)
|
|
))
|
|
}
|
|
}
|
|
|
|
val colorDictIntent = Intent("colordict.intent.action.SEARCH")
|
|
val colorResolvers = pm.queryIntentActivities(colorDictIntent, 0)
|
|
colorResolvers.forEach { ri ->
|
|
val pkg = ri.activityInfo.packageName
|
|
if (!PACKAGE_BLOCKLIST.contains(pkg) && addedPackages.add(pkg)) {
|
|
apps.add(ExternalDictionaryApp(
|
|
label = ri.loadLabel(pm).toString(),
|
|
packageName = pkg,
|
|
icon = ri.loadIcon(pm)
|
|
))
|
|
}
|
|
}
|
|
|
|
val sortedApps = apps.sortedBy { it.label }.toMutableList()
|
|
|
|
// Inject Google Search at the top
|
|
sortedApps.add(
|
|
0,
|
|
ExternalDictionaryApp(
|
|
label = "Search",
|
|
packageName = GOOGLE_SEARCH_PKG,
|
|
icon = null
|
|
)
|
|
)
|
|
|
|
return sortedApps
|
|
}
|
|
|
|
fun launchDictionary(context: Context, packageName: String, query: String) {
|
|
val pm = context.packageManager
|
|
try {
|
|
if (packageName == GOOGLE_SEARCH_PKG) {
|
|
val searchIntent = Intent(Intent.ACTION_WEB_SEARCH).apply {
|
|
putExtra(SearchManager.QUERY, query)
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
context.startActivity(searchIntent)
|
|
return
|
|
}
|
|
|
|
val processTextIntent = Intent(Intent.ACTION_PROCESS_TEXT).apply {
|
|
type = "text/plain"
|
|
putExtra(Intent.EXTRA_PROCESS_TEXT, query)
|
|
putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true)
|
|
setPackage(packageName)
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
|
|
if (processTextIntent.resolveActivity(pm) != null) {
|
|
context.startActivity(processTextIntent)
|
|
return
|
|
}
|
|
|
|
val dictIntent = Intent("colordict.intent.action.SEARCH").apply {
|
|
putExtra("EXTRA_QUERY", query)
|
|
setPackage(packageName)
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
|
|
if (dictIntent.resolveActivity(pm) != null) {
|
|
context.startActivity(dictIntent)
|
|
return
|
|
}
|
|
|
|
if (packageName == "it.t_arn.aard2") {
|
|
val aardIntent = Intent("aard2.lookup").apply {
|
|
putExtra("query", query)
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
context.startActivity(aardIntent)
|
|
return
|
|
}
|
|
|
|
launchGenericSend(context, packageName, query)
|
|
|
|
} catch (e: Exception) {
|
|
Timber.e(e, "Failed to launch dictionary app: $packageName")
|
|
Toast.makeText(context, "Error opening dictionary", Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
|
|
private fun launchGenericSend(context: Context, packageName: String, query: String) {
|
|
val sendIntent = Intent(Intent.ACTION_SEND)
|
|
sendIntent.type = "text/plain"
|
|
sendIntent.putExtra(Intent.EXTRA_TEXT, query)
|
|
sendIntent.setPackage(packageName)
|
|
sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
|
|
try {
|
|
context.startActivity(sendIntent)
|
|
} catch (e: Exception) {
|
|
val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)
|
|
if (launchIntent != null) {
|
|
context.startActivity(launchIntent)
|
|
} else {
|
|
throw e
|
|
}
|
|
}
|
|
}
|
|
} |