HapeLee пре 5 месеци
родитељ
комит
7b9a5dca16

+ 1 - 0
app/src/main/java/io/legado/app/data/local/preferences/LocalPreferences.kt

@@ -15,4 +15,5 @@ object LocalPreferencesKeys {
     val MATCH_MODE = intPreferencesKey("match_mode")
     val EXPLORE_LAYOUT_GRID_PORTRAIT = intPreferencesKey("explore_layout_grid_portrait")
     val EXPLORE_LAYOUT_GRID_LANDSCAPE = intPreferencesKey("explore_layout_grid_landscape")
+    val READ_URL_IN_BROWSER = booleanPreferencesKey("read_url_in_browser")
 }

+ 2 - 1
app/src/main/java/io/legado/app/di/appModule.kt

@@ -268,7 +268,8 @@ val appModule = module {
             translateChapterUseCase = get(),
             readSettingsRepository = get(),
             readBookStyleConfigRepository = get(),
-            readAloudSettingsRepository = get()
+            readAloudSettingsRepository = get(),
+            localPreferencesRepository = get()
         )
     }
     viewModelOf(::ChangeCoverViewModel)

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt

@@ -310,7 +310,7 @@ sealed interface ReadBookIntent {
     data object OpenBookInfo : ReadBookIntent
     data object OpenChapterList : ReadBookIntent
     data object OpenChapterUrl : ReadBookIntent
-    data class SetReadUrlInBrowser(val useBrowser: Boolean) : ReadBookIntent
+    data object ToggleReadUrlInBrowser : ReadBookIntent
 
     // Content edit
     data object LoadContentEdit : ReadBookIntent
@@ -523,6 +523,7 @@ sealed interface ReadBookEffect {
         val sourceOrigin: String?,
         val sourceName: String?,
         val sourceType: Int?,
+        val html: String? = null,
     ) : ReadBookEffect
 
     // Menu actions that need Activity
@@ -631,7 +632,6 @@ sealed interface ReadBookDialog {
     data class SureSyncProgress(val progress: BookProgress) : ReadBookDialog
     data object ConfirmSkipToChapter : ReadBookDialog
     data class ConfirmChapterPay(val chapterTitle: String) : ReadBookDialog
-    data object ConfirmReadUrlInBrowser : ReadBookDialog
 }
 
 /**

+ 14 - 1
app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt

@@ -849,7 +849,20 @@ private fun MenuTitleBar(
             ) {
                 AppText(
                     text = state.chapterName,
-                    modifier = Modifier.weight(1f),
+                    modifier = Modifier
+                        .weight(1f)
+                        .then(
+                            if (!state.isLocalBook) {
+                                Modifier.combinedClickable(
+                                    onClick = { onIntent(ReadBookIntent.OpenChapterUrl) },
+                                    onLongClick = {
+                                        onIntent(ReadBookIntent.ToggleReadUrlInBrowser)
+                                    },
+                                )
+                            } else {
+                                Modifier
+                            }
+                        ),
                     style = labelStyle,
                     color = titleTextColor,
                     maxLines = 1,

+ 38 - 40
app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt

@@ -17,6 +17,8 @@ import io.legado.app.constant.ReadMenuBlurMode
 import io.legado.app.constant.Status
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.Book
+import io.legado.app.data.local.preferences.LocalPreferencesKeys
+import io.legado.app.data.local.preferences.LocalPreferencesRepository
 import io.legado.app.data.entities.BookChapter
 import io.legado.app.data.entities.BookProgress
 import io.legado.app.data.entities.Bookmark
@@ -39,9 +41,7 @@ import io.legado.app.help.book.isLocalTxt
 import io.legado.app.help.book.isMobi
 import io.legado.app.help.book.removeType
 import io.legado.app.help.book.simulatedTotalChapterNum
-import io.legado.app.constant.AppPattern
 import io.legado.app.help.config.AppConfig
-import io.legado.app.utils.EncoderUtils
 import io.legado.app.utils.openUrl
 import io.legado.app.help.config.ReadBookConfig
 import io.legado.app.help.coroutine.Coroutine
@@ -93,6 +93,7 @@ import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
 import kotlinx.coroutines.flow.catch
 import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.flow.onEach
@@ -118,7 +119,8 @@ class ReadBookViewModel(
     val translateChapterUseCase: io.legado.app.domain.usecase.TranslateChapterUseCase,
     private val readSettingsRepository: ReadSettingsRepository,
     private val readBookStyleConfigRepository: ReadBookStyleConfigRepository,
-    private val readAloudSettingsRepository: ReadAloudSettingsRepository
+    private val readAloudSettingsRepository: ReadAloudSettingsRepository,
+    private val localPreferencesRepository: LocalPreferencesRepository
 ) : BaseViewModel(application), ReadBook.CallBack {
 
     // --- MVI State ---
@@ -342,10 +344,7 @@ class ReadBookViewModel(
                 }
             }
             is ReadBookIntent.OpenChapterUrl -> openChapterUrl()
-            is ReadBookIntent.SetReadUrlInBrowser -> {
-                AppConfig.readUrlInBrowser = intent.useBrowser
-                openChapterUrl()
-            }
+            is ReadBookIntent.ToggleReadUrlInBrowser -> toggleReadUrlInBrowser()
             is ReadBookIntent.LoadContentEdit -> loadContentEdit()
             is ReadBookIntent.SaveContentEdit -> saveContentEdit(intent.content, intent.saveToSource)
             is ReadBookIntent.ResetContentEdit -> resetContentEdit()
@@ -2967,47 +2966,46 @@ class ReadBookViewModel(
     }
 
     private fun openChapterUrl() {
+        if (ReadBook.isLocalBook) return
         val book = ReadBook.book ?: return
-        if (book.isLocal) return
         val chapter = ReadBook.curTextChapter?.chapter
             ?: appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
             ?: return
-        val rawUrl = chapter.getAbsoluteURL()
-        if (rawUrl.isBlank()) return
-        val url = resolveChapterUrl(rawUrl)
-        if (url.isBlank()) {
-            context.toastOnUi(R.string.cannot_open_url)
-            return
-        }
-        if (AppConfig.readUrlInBrowser) {
-            context.openUrl(url.substringBefore(",{"))
-        } else {
-            _effects.tryEmit(
-                ReadBookEffect.OpenWebView(
-                    title = chapter.title,
-                    url = url,
-                    sourceOrigin = ReadBook.bookSource?.bookSourceUrl,
-                    sourceName = ReadBook.bookSource?.bookSourceName,
-                    sourceType = ReadBook.bookSource?.getSourceType(),
+        val url = chapter.getAbsoluteURL()
+        if (url.isBlank()) return
+        viewModelScope.launch {
+            val useBrowser = localPreferencesRepository
+                .getPreference(LocalPreferencesKeys.READ_URL_IN_BROWSER, false)
+                .first()
+            if (useBrowser) {
+                context.openUrl(url.substringBefore(",{"))
+            } else {
+                val bookSource = ReadBook.bookSource
+                _effects.tryEmit(
+                    ReadBookEffect.OpenWebView(
+                        title = chapter.title,
+                        url = url,
+                        sourceOrigin = bookSource?.bookSourceUrl,
+                        sourceName = bookSource?.bookSourceName,
+                        sourceType = bookSource?.getSourceType(),
+                    )
                 )
-            )
+            }
         }
     }
 
-    /**
-     * 解析章节URL,处理data:;base64,...格式
-     * 从base64编码的JSON中提取真实URL
-     */
-    private fun resolveChapterUrl(url: String): String {
-        if (!url.startsWith("data:", ignoreCase = true)) return url
-        val match = AppPattern.dataUriRegex.matchEntire(url) ?: return url
-        return try {
-            val decoded = EncoderUtils.base64Decode(match.groupValues[1])
-            val json = GSON.fromJsonObject<Map<String, Any>>(decoded).getOrNull()
-            val realUrl = json?.get("url")?.toString() ?: ""
-            realUrl.ifBlank { url }
-        } catch (_: Exception) {
-            url
+    private fun toggleReadUrlInBrowser() {
+        viewModelScope.launch {
+            val current = localPreferencesRepository
+                .getPreference(LocalPreferencesKeys.READ_URL_IN_BROWSER, false)
+                .first()
+            val newValue = !current
+            localPreferencesRepository.updatePreference(
+                LocalPreferencesKeys.READ_URL_IN_BROWSER, newValue
+            )
+            context.toastOnUi(
+                if (newValue) R.string.open_by_browser else R.string.open_by_webview
+            )
         }
     }
 

+ 2 - 0
app/src/main/res/values-zh-rCN/strings.xml

@@ -1074,6 +1074,8 @@
     <string name="open_fun">打开方式</string>
     <string name="use_browser_open">是否使用外部浏览器打开?</string>
     <string name="cannot_open_url">该URL无法直接打开</string>
+    <string name="open_by_browser">已切换为浏览器打开</string>
+    <string name="open_by_webview">已切换为WebView打开</string>
     <string name="see">查看</string>
     <string name="open">打开</string>
     <string name="del_login_header">删除登录头</string>

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -1103,6 +1103,8 @@
     <string name="open_fun">open function</string>
     <string name="use_browser_open">Is it opened in an external browser?</string>
     <string name="cannot_open_url">This URL cannot be opened directly</string>
+    <string name="open_by_browser">Switched to browser opening</string>
+    <string name="open_by_webview">Switched to WebView opening</string>
     <string name="see">see</string>
     <string name="open">open</string>
     <string name="del_login_header">del login header</string>