Kaynağa Gözat

为WebView增加词典功能

HapeLee 1 yıl önce
ebeveyn
işleme
698f79d583

+ 95 - 0
app/src/main/java/io/legado/app/ui/rss/read/VisibleWebView.kt

@@ -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
+    }
+
 }
 }