为WebView增加词典功能

This commit is contained in:
HapeLee
2025-10-28 19:45:15 +08:00
parent f134608c32
commit 698f79d583
@@ -1,17 +1,112 @@
package io.legado.app.ui.rss.read package io.legado.app.ui.rss.read
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.ActionMode
import android.view.Menu
import android.view.MenuItem
import android.view.View import android.view.View
import android.webkit.WebView import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
import io.legado.app.R
import io.legado.app.ui.dict.DictDialog
@SuppressLint("SetJavaScriptEnabled")
class VisibleWebView( class VisibleWebView(
context: Context, context: Context,
attrs: AttributeSet? = null attrs: AttributeSet? = null
) : WebView(context, attrs) { ) : WebView(context, attrs) {
init {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
}
override fun onWindowVisibilityChanged(visibility: Int) { override fun onWindowVisibilityChanged(visibility: Int) {
super.onWindowVisibilityChanged(View.VISIBLE) super.onWindowVisibilityChanged(View.VISIBLE)
} }
override fun startActionMode(callback: ActionMode.Callback?): ActionMode {
val wrappedCallback = createWrappedCallback(callback)
return super.startActionMode(wrappedCallback)
}
override fun startActionMode(callback: ActionMode.Callback?, type: Int): ActionMode {
val wrappedCallback = createWrappedCallback(callback)
return super.startActionMode(wrappedCallback, type)
}
private fun createWrappedCallback(original: ActionMode.Callback?): ActionMode.Callback {
return object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
val result = original?.onCreateActionMode(mode, menu) ?: false
menu.add(Menu.NONE, MENU_ID_DICT, 0, R.string.dict)
getSelectedText { /* 触发缓存*/ }
return result
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
updateDictMenuItem(menu)
return original?.onPrepareActionMode(mode, menu) ?: false
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
MENU_ID_DICT -> {
getSelectedText { selectedText ->
if (selectedText.isNotBlank()) {
showDictDialog(selectedText)
}
}
mode.finish()
return true
}
else -> {
return original?.onActionItemClicked(mode, item) ?: false
}
}
}
override fun onDestroyActionMode(mode: ActionMode) {
original?.onDestroyActionMode(mode)
}
}
}
private fun updateDictMenuItem(menu: Menu) {
val dictItem = menu.findItem(MENU_ID_DICT)
dictItem?.let { item ->
getSelectedText { selectedText ->
item.isEnabled = selectedText.isNotBlank()
}
}
}
private fun getSelectedText(callback: (String) -> Unit) {
evaluateJavascript("(function(){return window.getSelection().toString();})()") { result ->
val selectedText = result
?.removeSurrounding("\"")
?.replace("\\n", "\n")
?.replace("\\t", "\t")
?.replace("\\\"", "\"")
?: ""
callback(selectedText)
}
}
private fun showDictDialog(selectedText: String) {
val activity = context as? AppCompatActivity
activity?.let {
val dialog = DictDialog(selectedText)
it.supportFragmentManager.beginTransaction()
.add(dialog, "DictDialog")
.commitAllowingStateLoss()
}
}
companion object {
private const val MENU_ID_DICT = 1001
}
} }