diff --git a/app/src/main/java/io/legado/app/data/local/preferences/LocalPreferences.kt b/app/src/main/java/io/legado/app/data/local/preferences/LocalPreferences.kt index d1e8083dc..7186cf33b 100644 --- a/app/src/main/java/io/legado/app/data/local/preferences/LocalPreferences.kt +++ b/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") } diff --git a/app/src/main/java/io/legado/app/di/appModule.kt b/app/src/main/java/io/legado/app/di/appModule.kt index ffee68a2f..06e110038 100644 --- a/app/src/main/java/io/legado/app/di/appModule.kt +++ b/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) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt index b17522274..11d163855 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt +++ b/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 } /** diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt index 48cb9cc04..92ac5524f 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookMenuBar.kt +++ b/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, diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 838f78b9f..7e0be067a 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/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>(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 + ) } } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 99e6932d8..751f47252 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1074,6 +1074,8 @@ 打开方式 是否使用外部浏览器打开? 该URL无法直接打开 + 已切换为浏览器打开 + 已切换为WebView打开 查看 打开 删除登录头 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 36d6626b2..7ce227d21 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1103,6 +1103,8 @@ open function Is it opened in an external browser? This URL cannot be opened directly + Switched to browser opening + Switched to WebView opening see open del login header