Quellcode durchsuchen

change popup page

Gogs vor 1 Monat
Ursprung
Commit
f70bc8ca4d
2 geänderte Dateien mit 74 neuen und 14 gelöschten Zeilen
  1. 45 0
      README.md
  2. 29 14
      app/src/main/java/com/codex/webviewgrammar/MainActivity.kt

+ 45 - 0
README.md

@@ -0,0 +1,45 @@
+# WebView Grammar App
+
+本项目是一个基于 Android WebView 的语法与语音应用。为了顺利完成构建,请根据以下说明准备依赖、配置环境变量并执行 Gradle 任务。
+
+## 依赖与版本
+- **JDK**:版本 17(`JAVA_HOME` 指向对应目录)
+- **Gradle**:使用仓库中 `gradle/wrapper/gradle-wrapper.properties` 内置的 Gradle **8.7**(通过 `./gradlew` 自动下载)
+- **Android Gradle Plugin**:`com.android.application` **8.5.0**
+- **Kotlin 插件**:`org.jetbrains.kotlin.android` **1.9.24**
+- **Android SDK**:需要安装 **API 34 (Android 14)**,并额外安装 Platform-Tools 与 Build-Tools 34.x
+
+## Android SDK 路径配置
+1. 安装 Android SDK 后,记录其根目录路径(例如 `/Users/you/Library/Android/sdk` 或 `/home/you/Android/Sdk`)。
+2. 在项目根目录创建或编辑 `local.properties`,写入:
+   ```
+   sdk.dir=/绝对路径/Android/Sdk
+   ```
+3. 若使用 CI,请通过环境变量 `ANDROID_HOME` 或 `ANDROID_SDK_ROOT` 指向相同目录。
+
+## 可选的构建常量
+`app/build.gradle` 中的接口地址可通过 Gradle Property 覆盖:
+- `grammarApiBaseUrl`:语法 API 根路径,默认 `http://aimanyi.top`
+- `ttsEndpointUrl`:TTS 接口地址,默认 `http://141.140.15.30:8028/generate`
+
+在命令行中可以这样传入:
+```
+./gradlew assembleDebug -PgrammarApiBaseUrl=https://example.com -PttsEndpointUrl=https://tts.example.com
+```
+
+## 构建步骤
+1. 确保安装 JDK 17 并配置 `JAVA_HOME`。
+2. 安装 Android SDK API 34,并按上述方式在 `local.properties` 声明 `sdk.dir`。
+3. 在项目根目录执行以下命令完成依赖下载与调试包构建:
+   ```
+   ./gradlew clean assembleDebug
+   ```
+4. 生成的 APK 位于 `app/build/outputs/apk/debug/app-debug.apk`,可通过 `adb install` 安装到设备:
+   ```
+   adb install -r app/build/outputs/apk/debug/app-debug.apk
+   ```
+
+## 常见问题
+- **Gradle 下载失败**:检查网络或配置代理,可在 `~/.gradle/gradle.properties` 中设置代理变量。
+- **SDK 路径找不到**:确认 `local.properties` 使用绝对路径,且路径中的空格已被正确转义(或使用引号)。
+- **JDK 版本不匹配**:Gradle 8.7/AGP 8.5.0 需要 JDK 17;如果使用 Android Studio,请在 `File > Settings > Build Tools > Gradle` 中指定同版本 JDK。

+ 29 - 14
app/src/main/java/com/codex/webviewgrammar/MainActivity.kt

@@ -16,7 +16,6 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.isVisible
 import androidx.lifecycle.lifecycleScope
 import com.codex.webviewgrammar.databinding.ActivityMainBinding
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -154,8 +153,13 @@ class MainActivity : AppCompatActivity() {
             val result = runCatching { requestHighlight(pageText) }
             setActionButtonsEnabled(true)
             result.onSuccess { html ->
-                binding.statusText.text = getString(R.string.status_ready)
-                showHighlightDialog(html)
+                val applied = runCatching { applyHighlightToPage(html) }
+                if (applied.getOrDefault(false)) {
+                    binding.statusText.text = getString(R.string.status_ready)
+                } else {
+                    val reason = applied.exceptionOrNull()?.message ?: "无法更新页面内容"
+                    binding.statusText.text = getString(R.string.error_highlight_failed, reason)
+                }
             }.onFailure { err ->
                 binding.statusText.text = getString(R.string.error_highlight_failed, err.message ?: "")
             }
@@ -337,17 +341,28 @@ class MainActivity : AppCompatActivity() {
         binding.ttsButton.isEnabled = enabled
     }
 
-    private fun showHighlightDialog(html: String) {
-        val dialogWebView = WebView(this).apply {
-            settings.javaScriptEnabled = false
-            settings.defaultTextEncodingName = "utf-8"
-            loadDataWithBaseURL(null, html, "text/html", "utf-8", null)
-        }
-        MaterialAlertDialogBuilder(this)
-            .setTitle(R.string.dialog_highlight_title)
-            .setView(dialogWebView)
-            .setPositiveButton(R.string.action_close, null)
-            .show()
+    private suspend fun applyHighlightToPage(html: String): Boolean {
+        val encoded = Base64.encodeToString(html.toByteArray(Charsets.UTF_8), Base64.NO_WRAP)
+        val script = """
+            (function() {
+                try {
+                    var raw = window.atob("$encoded");
+                    var parser = new DOMParser();
+                    var parsed = parser.parseFromString(raw, 'text/html');
+                    if (parsed && parsed.documentElement) {
+                        document.documentElement.innerHTML = parsed.documentElement.innerHTML;
+                        return true;
+                    }
+                    document.body.innerHTML = raw;
+                    return true;
+                } catch (e) {
+                    return false;
+                }
+            })();
+        """.trimIndent()
+        val rawResult = evaluateJavascript(script)
+        val normalized = decodeJsResult(rawResult)
+        return normalized.equals("true", ignoreCase = true)
     }
 
     private class ByteArrayMediaDataSource(private val data: ByteArray) : MediaDataSource() {