Procházet zdrojové kódy

fix: 字典弹窗使用Compose实现

HapeLee před 4 měsíci
rodič
revize
ae56520750
1 změnil soubory, kde provedl 51 přidání a 30 odebrání
  1. 51 30
      app/src/main/java/io/legado/app/ui/dict/DictSheet.kt

+ 51 - 30
app/src/main/java/io/legado/app/ui/dict/DictSheet.kt

@@ -1,33 +1,30 @@
 package io.legado.app.ui.dict
 
-import android.text.method.LinkMovementMethod
-import android.widget.TextView
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.fromHtml
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.viewinterop.AndroidView
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import coil.compose.AsyncImage
 import io.legado.app.R
-import io.legado.app.help.GlideImageGetter
 import io.legado.app.ui.widget.components.EmptyMessage
+import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.progressIndicator.AppCircularProgressIndicator
 import io.legado.app.ui.widget.components.tabRow.AppTabRow
-import io.legado.app.utils.setHtml
 import kotlinx.coroutines.flow.Flow
 import org.koin.androidx.compose.koinViewModel
 
@@ -147,33 +144,57 @@ private fun DictContent(
     }
 }
 
+@OptIn(ExperimentalTextApi::class)
 @Composable
 private fun DictHtmlContent(
     htmlContent: String,
     modifier: Modifier = Modifier,
 ) {
-    val context = LocalContext.current
-    var glideImageGetter by remember { mutableStateOf<GlideImageGetter?>(null) }
-
-    DisposableEffect(Unit) {
-        onDispose {
-            glideImageGetter?.clear()
-            glideImageGetter = null
+    val blocks = remember(htmlContent) { parseHtmlBlocks(htmlContent) }
+    Column(modifier = modifier.padding(horizontal = 32.dp, vertical = 16.dp)) {
+        blocks.forEach { block ->
+            when (block) {
+                is HtmlBlock.Text -> {
+                    AppText(
+                        text = remember(block.content) {
+                            AnnotatedString.fromHtml(block.content)
+                        },
+                    )
+                }
+                is HtmlBlock.Image -> {
+                    AsyncImage(
+                        model = block.url,
+                        contentDescription = null,
+                        modifier = Modifier.fillMaxWidth(),
+                        contentScale = ContentScale.FillWidth,
+                    )
+                }
+            }
         }
     }
+}
 
-    AndroidView(
-        factory = { ctx ->
-            TextView(ctx).apply {
-                movementMethod = LinkMovementMethod()
-                setPadding(32, 16, 32, 16)
-            }
-        },
-        update = { textView ->
-            glideImageGetter?.clear()
-            glideImageGetter = GlideImageGetter.create(context, textView, htmlContent)
-            textView.setHtml(htmlContent, glideImageGetter)
-        },
-        modifier = modifier,
-    )
+private sealed interface HtmlBlock {
+    data class Text(val content: String) : HtmlBlock
+    data class Image(val url: String) : HtmlBlock
+}
+
+private val IMG_REGEX = Regex("""<img\s+[^>]*src\s*=\s*["']([^"']+)["'][^>]*/?>""")
+
+private fun parseHtmlBlocks(html: String): List<HtmlBlock> {
+    val blocks = mutableListOf<HtmlBlock>()
+    var lastIndex = 0
+    IMG_REGEX.findAll(html).forEach { match ->
+        if (match.range.first > lastIndex) {
+            val textPart = html.substring(lastIndex, match.range.first).trim()
+            if (textPart.isNotBlank()) blocks.add(HtmlBlock.Text(textPart))
+        }
+        blocks.add(HtmlBlock.Image(match.groupValues[1]))
+        lastIndex = match.range.last + 1
+    }
+    if (lastIndex < html.length) {
+        val remaining = html.substring(lastIndex).trim()
+        if (remaining.isNotBlank()) blocks.add(HtmlBlock.Text(remaining))
+    }
+    return blocks
 }