fix: 章节点击事件
This commit is contained in:
7 files changed
+61
-44
No files matched your search
@@ -15,4 +15,5 @@ object LocalPreferencesKeys {
|
|||||||
val MATCH_MODE = intPreferencesKey("match_mode")
|
val MATCH_MODE = intPreferencesKey("match_mode")
|
||||||
val EXPLORE_LAYOUT_GRID_PORTRAIT = intPreferencesKey("explore_layout_grid_portrait")
|
val EXPLORE_LAYOUT_GRID_PORTRAIT = intPreferencesKey("explore_layout_grid_portrait")
|
||||||
val EXPLORE_LAYOUT_GRID_LANDSCAPE = intPreferencesKey("explore_layout_grid_landscape")
|
val EXPLORE_LAYOUT_GRID_LANDSCAPE = intPreferencesKey("explore_layout_grid_landscape")
|
||||||
|
val READ_URL_IN_BROWSER = booleanPreferencesKey("read_url_in_browser")
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,8 @@ val appModule = module {
|
|||||||
translateChapterUseCase = get(),
|
translateChapterUseCase = get(),
|
||||||
readSettingsRepository = get(),
|
readSettingsRepository = get(),
|
||||||
readBookStyleConfigRepository = get(),
|
readBookStyleConfigRepository = get(),
|
||||||
readAloudSettingsRepository = get()
|
readAloudSettingsRepository = get(),
|
||||||
|
localPreferencesRepository = get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewModelOf(::ChangeCoverViewModel)
|
viewModelOf(::ChangeCoverViewModel)
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ sealed interface ReadBookIntent {
|
|||||||
data object OpenBookInfo : ReadBookIntent
|
data object OpenBookInfo : ReadBookIntent
|
||||||
data object OpenChapterList : ReadBookIntent
|
data object OpenChapterList : ReadBookIntent
|
||||||
data object OpenChapterUrl : ReadBookIntent
|
data object OpenChapterUrl : ReadBookIntent
|
||||||
data class SetReadUrlInBrowser(val useBrowser: Boolean) : ReadBookIntent
|
data object ToggleReadUrlInBrowser : ReadBookIntent
|
||||||
|
|
||||||
// Content edit
|
// Content edit
|
||||||
data object LoadContentEdit : ReadBookIntent
|
data object LoadContentEdit : ReadBookIntent
|
||||||
@@ -523,6 +523,7 @@ sealed interface ReadBookEffect {
|
|||||||
val sourceOrigin: String?,
|
val sourceOrigin: String?,
|
||||||
val sourceName: String?,
|
val sourceName: String?,
|
||||||
val sourceType: Int?,
|
val sourceType: Int?,
|
||||||
|
val html: String? = null,
|
||||||
) : ReadBookEffect
|
) : ReadBookEffect
|
||||||
|
|
||||||
// Menu actions that need Activity
|
// Menu actions that need Activity
|
||||||
@@ -631,7 +632,6 @@ sealed interface ReadBookDialog {
|
|||||||
data class SureSyncProgress(val progress: BookProgress) : ReadBookDialog
|
data class SureSyncProgress(val progress: BookProgress) : ReadBookDialog
|
||||||
data object ConfirmSkipToChapter : ReadBookDialog
|
data object ConfirmSkipToChapter : ReadBookDialog
|
||||||
data class ConfirmChapterPay(val chapterTitle: String) : ReadBookDialog
|
data class ConfirmChapterPay(val chapterTitle: String) : ReadBookDialog
|
||||||
data object ConfirmReadUrlInBrowser : ReadBookDialog
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -849,7 +849,20 @@ private fun MenuTitleBar(
|
|||||||
) {
|
) {
|
||||||
AppText(
|
AppText(
|
||||||
text = state.chapterName,
|
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,
|
style = labelStyle,
|
||||||
color = titleTextColor,
|
color = titleTextColor,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import io.legado.app.constant.ReadMenuBlurMode
|
|||||||
import io.legado.app.constant.Status
|
import io.legado.app.constant.Status
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.Book
|
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.BookChapter
|
||||||
import io.legado.app.data.entities.BookProgress
|
import io.legado.app.data.entities.BookProgress
|
||||||
import io.legado.app.data.entities.Bookmark
|
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.isMobi
|
||||||
import io.legado.app.help.book.removeType
|
import io.legado.app.help.book.removeType
|
||||||
import io.legado.app.help.book.simulatedTotalChapterNum
|
import io.legado.app.help.book.simulatedTotalChapterNum
|
||||||
import io.legado.app.constant.AppPattern
|
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.utils.EncoderUtils
|
|
||||||
import io.legado.app.utils.openUrl
|
import io.legado.app.utils.openUrl
|
||||||
import io.legado.app.help.config.ReadBookConfig
|
import io.legado.app.help.config.ReadBookConfig
|
||||||
import io.legado.app.help.coroutine.Coroutine
|
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.callbackFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.onCompletion
|
import kotlinx.coroutines.flow.onCompletion
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -118,7 +119,8 @@ class ReadBookViewModel(
|
|||||||
val translateChapterUseCase: io.legado.app.domain.usecase.TranslateChapterUseCase,
|
val translateChapterUseCase: io.legado.app.domain.usecase.TranslateChapterUseCase,
|
||||||
private val readSettingsRepository: ReadSettingsRepository,
|
private val readSettingsRepository: ReadSettingsRepository,
|
||||||
private val readBookStyleConfigRepository: ReadBookStyleConfigRepository,
|
private val readBookStyleConfigRepository: ReadBookStyleConfigRepository,
|
||||||
private val readAloudSettingsRepository: ReadAloudSettingsRepository
|
private val readAloudSettingsRepository: ReadAloudSettingsRepository,
|
||||||
|
private val localPreferencesRepository: LocalPreferencesRepository
|
||||||
) : BaseViewModel(application), ReadBook.CallBack {
|
) : BaseViewModel(application), ReadBook.CallBack {
|
||||||
|
|
||||||
// --- MVI State ---
|
// --- MVI State ---
|
||||||
@@ -342,10 +344,7 @@ class ReadBookViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ReadBookIntent.OpenChapterUrl -> openChapterUrl()
|
is ReadBookIntent.OpenChapterUrl -> openChapterUrl()
|
||||||
is ReadBookIntent.SetReadUrlInBrowser -> {
|
is ReadBookIntent.ToggleReadUrlInBrowser -> toggleReadUrlInBrowser()
|
||||||
AppConfig.readUrlInBrowser = intent.useBrowser
|
|
||||||
openChapterUrl()
|
|
||||||
}
|
|
||||||
is ReadBookIntent.LoadContentEdit -> loadContentEdit()
|
is ReadBookIntent.LoadContentEdit -> loadContentEdit()
|
||||||
is ReadBookIntent.SaveContentEdit -> saveContentEdit(intent.content, intent.saveToSource)
|
is ReadBookIntent.SaveContentEdit -> saveContentEdit(intent.content, intent.saveToSource)
|
||||||
is ReadBookIntent.ResetContentEdit -> resetContentEdit()
|
is ReadBookIntent.ResetContentEdit -> resetContentEdit()
|
||||||
@@ -2967,47 +2966,46 @@ class ReadBookViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun openChapterUrl() {
|
private fun openChapterUrl() {
|
||||||
|
if (ReadBook.isLocalBook) return
|
||||||
val book = ReadBook.book ?: return
|
val book = ReadBook.book ?: return
|
||||||
if (book.isLocal) return
|
|
||||||
val chapter = ReadBook.curTextChapter?.chapter
|
val chapter = ReadBook.curTextChapter?.chapter
|
||||||
?: appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
|
?: appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
|
||||||
?: return
|
?: return
|
||||||
val rawUrl = chapter.getAbsoluteURL()
|
val url = chapter.getAbsoluteURL()
|
||||||
if (rawUrl.isBlank()) return
|
if (url.isBlank()) return
|
||||||
val url = resolveChapterUrl(rawUrl)
|
viewModelScope.launch {
|
||||||
if (url.isBlank()) {
|
val useBrowser = localPreferencesRepository
|
||||||
context.toastOnUi(R.string.cannot_open_url)
|
.getPreference(LocalPreferencesKeys.READ_URL_IN_BROWSER, false)
|
||||||
return
|
.first()
|
||||||
}
|
if (useBrowser) {
|
||||||
if (AppConfig.readUrlInBrowser) {
|
context.openUrl(url.substringBefore(",{"))
|
||||||
context.openUrl(url.substringBefore(",{"))
|
} else {
|
||||||
} else {
|
val bookSource = ReadBook.bookSource
|
||||||
_effects.tryEmit(
|
_effects.tryEmit(
|
||||||
ReadBookEffect.OpenWebView(
|
ReadBookEffect.OpenWebView(
|
||||||
title = chapter.title,
|
title = chapter.title,
|
||||||
url = url,
|
url = url,
|
||||||
sourceOrigin = ReadBook.bookSource?.bookSourceUrl,
|
sourceOrigin = bookSource?.bookSourceUrl,
|
||||||
sourceName = ReadBook.bookSource?.bookSourceName,
|
sourceName = bookSource?.bookSourceName,
|
||||||
sourceType = ReadBook.bookSource?.getSourceType(),
|
sourceType = bookSource?.getSourceType(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun toggleReadUrlInBrowser() {
|
||||||
* 解析章节URL,处理data:;base64,...格式
|
viewModelScope.launch {
|
||||||
* 从base64编码的JSON中提取真实URL
|
val current = localPreferencesRepository
|
||||||
*/
|
.getPreference(LocalPreferencesKeys.READ_URL_IN_BROWSER, false)
|
||||||
private fun resolveChapterUrl(url: String): String {
|
.first()
|
||||||
if (!url.startsWith("data:", ignoreCase = true)) return url
|
val newValue = !current
|
||||||
val match = AppPattern.dataUriRegex.matchEntire(url) ?: return url
|
localPreferencesRepository.updatePreference(
|
||||||
return try {
|
LocalPreferencesKeys.READ_URL_IN_BROWSER, newValue
|
||||||
val decoded = EncoderUtils.base64Decode(match.groupValues[1])
|
)
|
||||||
val json = GSON.fromJsonObject<Map<String, Any>>(decoded).getOrNull()
|
context.toastOnUi(
|
||||||
val realUrl = json?.get("url")?.toString() ?: ""
|
if (newValue) R.string.open_by_browser else R.string.open_by_webview
|
||||||
realUrl.ifBlank { url }
|
)
|
||||||
} catch (_: Exception) {
|
|
||||||
url
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1074,6 +1074,8 @@
|
|||||||
<string name="open_fun">打开方式</string>
|
<string name="open_fun">打开方式</string>
|
||||||
<string name="use_browser_open">是否使用外部浏览器打开?</string>
|
<string name="use_browser_open">是否使用外部浏览器打开?</string>
|
||||||
<string name="cannot_open_url">该URL无法直接打开</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="see">查看</string>
|
||||||
<string name="open">打开</string>
|
<string name="open">打开</string>
|
||||||
<string name="del_login_header">删除登录头</string>
|
<string name="del_login_header">删除登录头</string>
|
||||||
|
|||||||
@@ -1103,6 +1103,8 @@
|
|||||||
<string name="open_fun">open function</string>
|
<string name="open_fun">open function</string>
|
||||||
<string name="use_browser_open">Is it opened in an external browser?</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="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="see">see</string>
|
||||||
<string name="open">open</string>
|
<string name="open">open</string>
|
||||||
<string name="del_login_header">del login header</string>
|
<string name="del_login_header">del login header</string>
|
||||||
|
|||||||
Reference in new issue
Block a user