[优化] 支持更多Sigma版本特性(@Luoyacheng)

This commit is contained in:
HapeLee committed 2026-02-02 21:09:24 +08:00
1 parent d3c85eccfe
commit 2d14d82251
20 files changed
+200 -88

No files matched your search

@@ -35,5 +35,6 @@ object EventBus {
const val UP_MANGA_CONFIG = "upMangaConfig" const val UP_MANGA_CONFIG = "upMangaConfig"
const val PLAY_MODE_CHANGED = "playModeChanged" const val PLAY_MODE_CHANGED = "playModeChanged"
const val REFRESH_BOOK_INFO = "refreshBookInfo" const val REFRESH_BOOK_INFO = "refreshBookInfo"
const val REFRESH_BOOK_CONTENT = "refreshBookContent"
const val UP_TOC = "upToc" const val UP_TOC = "upToc"
} }
@@ -118,7 +118,7 @@ object PreferKey {
const val enableMangaEInk = "enableMangaEInk" const val enableMangaEInk = "enableMangaEInk"
const val mangaEInkThreshold = "mangaEInkThreshold" const val mangaEInkThreshold = "mangaEInkThreshold"
const val enableMangaGray = "enableMangaGray" const val enableMangaGray = "enableMangaGray"
const val mediaButtonOnExit = "mediaButtonOnExit"
const val autoRefresh = "auto_refresh" const val autoRefresh = "auto_refresh"
const val defaultToRead = "defaultToRead" const val defaultToRead = "defaultToRead"
const val exportCharset = "exportCharset" const val exportCharset = "exportCharset"
@@ -9,17 +9,21 @@ import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.data.entities.rule.RowUi import io.legado.app.data.entities.rule.RowUi
import io.legado.app.help.CacheManager import io.legado.app.help.CacheManager
import io.legado.app.help.ConcurrentRateLimiter.Companion.updateConcurrentRate
import io.legado.app.help.JsExtensions import io.legado.app.help.JsExtensions
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.crypto.SymmetricCryptoAndroid import io.legado.app.help.crypto.SymmetricCryptoAndroid
import io.legado.app.help.http.CookieStore import io.legado.app.help.http.CookieStore
import io.legado.app.help.source.clearExploreKindsCache
import io.legado.app.help.source.getShareScope import io.legado.app.help.source.getShareScope
import io.legado.app.model.SharedJsScope.remove
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.GSONStrict import io.legado.app.utils.GSONStrict
import io.legado.app.utils.fromJsonArray import io.legado.app.utils.fromJsonArray
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.has import io.legado.app.utils.has
import io.legado.app.utils.printOnDebug import io.legado.app.utils.isMainThread
import kotlinx.coroutines.runBlocking
import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.Language
/** /**
@@ -75,6 +79,9 @@ interface BaseSource : JsExtensions {
} }
} }
/**
* 调用login函数 实现登录请求
*/
@JavascriptInterface @JavascriptInterface
fun login() { fun login() {
val loginJs = getLoginJs() val loginJs = getLoginJs()
@@ -91,30 +98,6 @@ interface BaseSource : JsExtensions {
} }
} }
fun loginUi(): List<RowUi>? {
val json = loginUi?.let {
val loginJS = getLoginJs() ?: ""
try {
when {
it.startsWith("@js:") -> evalJS(loginJS + it.substring(4)){
put("result", getLoginInfoMap())
}.toString()
it.startsWith("<js>") -> evalJS(loginJS + it.substring(4,it.lastIndexOf("<"))){
put("result", getLoginInfoMap())
}.toString()
else -> it
}
} catch (e: Throwable) {
log(e)
e.printOnDebug()
null
}
}
return GSON.fromJsonArray<RowUi>(json).onFailure {
it.printOnDebug()
}.getOrNull()
}
/** /**
* 解析header规则 * 解析header规则
*/ */
@@ -152,6 +135,7 @@ interface BaseSource : JsExtensions {
/** /**
* 获取用于登录的头部信息 * 获取用于登录的头部信息
*/ */
@JavascriptInterface
fun getLoginHeader(): String? { fun getLoginHeader(): String? {
return CacheManager.get("loginHeader_${getKey()}") return CacheManager.get("loginHeader_${getKey()}")
} }
@@ -182,6 +166,7 @@ interface BaseSource : JsExtensions {
* 获取用户信息,可以用来登录 * 获取用户信息,可以用来登录
* 用户信息采用aes加密存储 * 用户信息采用aes加密存储
*/ */
@JavascriptInterface
fun getLoginInfo(): String? { fun getLoginInfo(): String? {
try { try {
val key = AppConst.androidId.encodeToByteArray(0, 16) val key = AppConst.androidId.encodeToByteArray(0, 16)
@@ -232,6 +217,7 @@ interface BaseSource : JsExtensions {
/** /**
* 保存用户信息,aes加密 * 保存用户信息,aes加密
*/ */
@JavascriptInterface
fun putLoginInfo(info: String): Boolean { fun putLoginInfo(info: String): Boolean {
return try { return try {
val key = (AppConst.androidId).encodeToByteArray(0, 16) val key = (AppConst.androidId).encodeToByteArray(0, 16)
@@ -244,6 +230,7 @@ interface BaseSource : JsExtensions {
} }
} }
@JavascriptInterface
fun removeLoginInfo() { fun removeLoginInfo() {
CacheManager.delete("userInfo_${getKey()}") CacheManager.delete("userInfo_${getKey()}")
} }
@@ -260,9 +247,23 @@ interface BaseSource : JsExtensions {
} }
} }
/**
* 设置自定义变量
* 新,统一为put名称存变量
*/
@JavascriptInterface
fun putVariable(variable: String?) {
if (variable != null) {
CacheManager.put("sourceVariable_${getKey()}", variable)
} else {
CacheManager.delete("sourceVariable_${getKey()}")
}
}
/** /**
* 获取自定义变量 * 获取自定义变量
*/ */
@JavascriptInterface
fun getVariable(): String { fun getVariable(): String {
return CacheManager.get("sourceVariable_${getKey()}") ?: "" return CacheManager.get("sourceVariable_${getKey()}") ?: ""
} }
@@ -270,6 +271,7 @@ interface BaseSource : JsExtensions {
/** /**
* 保存数据 * 保存数据
*/ */
@JavascriptInterface
fun put(key: String, value: String): String { fun put(key: String, value: String): String {
CacheManager.put("v_${getKey()}_${key}", value) CacheManager.put("v_${getKey()}_${key}", value)
return value return value
@@ -278,10 +280,44 @@ interface BaseSource : JsExtensions {
/** /**
* 获取保存的数据 * 获取保存的数据
*/ */
@JavascriptInterface
fun get(key: String): String { fun get(key: String): String {
return CacheManager.get("v_${getKey()}_${key}") ?: "" return CacheManager.get("v_${getKey()}_${key}") ?: ""
} }
/**
* 刷新发现
*/
fun refreshExplore() {
if (isMainThread) {
error("refreshExplore must be called on a background thread")
}
runBlocking {
if (this@BaseSource is BookSource) {
this@BaseSource.clearExploreKindsCache()
}
}
}
/**
* 刷新JSLib
*/
fun refreshJSLib() {
if (isMainThread) {
error("refreshJSLib must be called on a background thread")
}
runBlocking {
remove(jsLib)
}
}
/**
* 设置并发率
*/
fun putConcurrent(value: String) {
updateConcurrentRate(getKey(), value)
}
/** /**
* 执行JS * 执行JS
*/ */
@@ -16,6 +16,7 @@ import io.legado.app.data.entities.BaseSource
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig import io.legado.app.help.config.ReadBookConfig
import io.legado.app.help.config.ThemeConfig
import io.legado.app.help.http.BackstageWebView import io.legado.app.help.http.BackstageWebView
import io.legado.app.help.http.CookieManager.cookieJarHeader import io.legado.app.help.http.CookieManager.cookieJarHeader
import io.legado.app.help.http.CookieStore import io.legado.app.help.http.CookieStore
@@ -321,17 +322,6 @@ interface JsExtensions : JsEncodeUtils {
} }
} }
/**
* 打开内置视频播放器
* @param url 视频播放链接
* @param title 视频的标题
* @param float 是否悬浮窗打开
*/
@JavascriptInterface
fun openVideoPlayer(url: String, title: String, float: Boolean) {
//SourceHelp.openVideoPlayer(getSource(), url, title, float)
}
/** /**
* 使用内置浏览器打开链接,手动验证网站防爬 * 使用内置浏览器打开链接,手动验证网站防爬
* @param url 要打开的链接 * @param url 要打开的链接
@@ -1196,9 +1186,9 @@ interface JsExtensions : JsEncodeUtils {
return GSON.toJson(ReadBookConfig.durConfig) return GSON.toJson(ReadBookConfig.durConfig)
} }
//fun getReadBookConfigMap(): Map<String, Any> { fun getReadBookConfigMap(): Map<String, Any> {
// return ReadBookConfig.durConfig.toMap() return ReadBookConfig.durConfig.toMap()
//} }
/** /**
* 获取主题模式 * 获取主题模式
@@ -1211,14 +1201,14 @@ interface JsExtensions : JsEncodeUtils {
/** /**
* 获取主题配置 * 获取主题配置
*/ */
// @JavascriptInterface @JavascriptInterface
//fun getThemeConfig(): String { fun getThemeConfig(): String {
// val themeConfig = ThemeConfig.getDurConfig(appCtx) val themeConfig = ThemeConfig.getDurConfig(appCtx)
// return GSON.toJson(themeConfig) return GSON.toJson(themeConfig)
//} }
//fun getThemeConfigMap(): Map<String, Any?> { fun getThemeConfigMap(): Map<String, Any?> {
// return ThemeConfig.getDurConfig(appCtx).toMap() return ThemeConfig.getDurConfig(appCtx).toMap()
//} }
} }
@@ -31,6 +31,7 @@ import io.legado.app.utils.onEachParallel
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
@@ -47,7 +48,6 @@ import java.io.IOException
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.regex.Pattern import java.util.regex.Pattern
import java.util.zip.ZipFile import java.util.zip.ZipFile
import kotlin.coroutines.coroutineContext
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@@ -234,7 +234,7 @@ object BookHelp {
return return
} }
val analyzeUrl = AnalyzeUrl( val analyzeUrl = AnalyzeUrl(
src, source = bookSource, coroutineContext = coroutineContext src, source = bookSource, coroutineContext = currentCoroutineContext()
) )
val bytes = analyzeUrl.getByteArrayAwait() val bytes = analyzeUrl.getByteArrayAwait()
//某些图片被加密,需要进一步解密 //某些图片被加密,需要进一步解密
@@ -252,7 +252,7 @@ object BookHelp {
writeImage(book, src, it) writeImage(book, src, it)
} }
} catch (e: Exception) { } catch (e: Exception) {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
val msg = "${book.name} ${chapter?.title} 图片 $src 下载失败\n${e.localizedMessage}" val msg = "${book.name} ${chapter?.title} 图片 $src 下载失败\n${e.localizedMessage}"
AppLog.put(msg, e) AppLog.put(msg, e)
} finally { } finally {
@@ -578,7 +578,7 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val syncBookProgressPlus get() = appCtx.getPrefBoolean(PreferKey.syncBookProgressPlus, false) val syncBookProgressPlus get() = appCtx.getPrefBoolean(PreferKey.syncBookProgressPlus, false)
val mediaButtonOnExit get() = appCtx.getPrefBoolean("mediaButtonOnExit", true) val mediaButtonOnExit get() = appCtx.getPrefBoolean(PreferKey.mediaButtonOnExit, true)
val readAloudByMediaButton val readAloudByMediaButton
get() = appCtx.getPrefBoolean(PreferKey.readAloudByMediaButton, false) get() = appCtx.getPrefBoolean(PreferKey.readAloudByMediaButton, false)
@@ -788,6 +788,69 @@ object ReadBookConfig {
@Transient @Transient
private var initColorInt = false private var initColorInt = false
fun toMap() = mapOf(
"name" to name,
"bgStr" to bgStr,
"bgStrNight" to bgStrNight,
"bgStrEInk" to bgStrEInk,
"bgAlpha" to bgAlpha,
"bgType" to bgType,
"bgTypeNight" to bgTypeNight,
"bgTypeEInk" to bgTypeEInk,
"darkStatusIcon" to darkStatusIcon,
"darkStatusIconNight" to darkStatusIconNight,
"darkStatusIconEInk" to darkStatusIconEInk,
"textColor" to textColor,
"textColorNight" to textColorNight,
"textColorEInk" to textColorEInk,
"textColorInt" to textColorInt,
"textColorIntNight" to textColorIntNight,
"textColorIntEInk" to textColorIntEInk,
"textAccentColor" to textAccentColor,
"textAccentColorNight" to textAccentColorNight,
"textAccentColorEInk" to textAccentColorEInk,
"textAccentColorInt" to textAccentColorInt,
"textAccentColorIntNight" to textAccentColorIntNight,
"textAccentColorIntEInk" to textAccentColorIntEInk,
"pageAnim" to pageAnim,
"pageAnimEInk" to pageAnimEInk,
"textFont" to textFont,
"textBold" to textBold,
"textSize" to textSize,
"letterSpacing" to letterSpacing,
"lineSpacingExtra" to lineSpacingExtra,
"paragraphSpacing" to paragraphSpacing,
"titleMode" to titleMode,
"titleSize" to titleSize,
"titleTopSpacing" to titleTopSpacing,
"titleBottomSpacing" to titleBottomSpacing,
"paragraphIndent" to paragraphIndent,
"paddingBottom" to paddingBottom,
"paddingLeft" to paddingLeft,
"paddingRight" to paddingRight,
"paddingTop" to paddingTop,
"headerPaddingBottom" to headerPaddingBottom,
"headerPaddingLeft" to headerPaddingLeft,
"headerPaddingRight" to headerPaddingRight,
"headerPaddingTop" to headerPaddingTop,
"footerPaddingBottom" to footerPaddingBottom,
"footerPaddingLeft" to footerPaddingLeft,
"footerPaddingRight" to footerPaddingRight,
"footerPaddingTop" to footerPaddingTop,
"showHeaderLine" to showHeaderLine,
"showFooterLine" to showFooterLine,
"tipHeaderLeft" to tipHeaderLeft,
"tipHeaderMiddle" to tipHeaderMiddle,
"tipHeaderRight" to tipHeaderRight,
"tipFooterLeft" to tipFooterLeft,
"tipFooterMiddle" to tipFooterMiddle,
"tipFooterRight" to tipFooterRight,
"tipColor" to tipColor,
"tipDividerColor" to tipDividerColor,
"headerMode" to headerMode,
"footerMode" to footerMode
)
fun getBgPath(bgIndex: Int): String? { fun getBgPath(bgIndex: Int): String? {
val bgType = when (bgIndex) { val bgType = when (bgIndex) {
0 -> bgType 0 -> bgType
@@ -218,7 +218,6 @@ class WebJsExtensions(
val letters = "abcdefghijklmnopqrstuvwxyz" val letters = "abcdefghijklmnopqrstuvwxyz"
return letters.random() return letters.random()
} }
val uuid by lazy { val uuid by lazy {
UUID.randomUUID().toString().replace('-', getRandomLetter()).chunked(6) UUID.randomUUID().toString().replace('-', getRandomLetter()).chunked(6)
} }
@@ -41,7 +41,7 @@ object ImageProvider {
private const val M = 1024 * 1024 private const val M = 1024 * 1024
val cacheSize: Int val cacheSize: Int
get() { get() {
if (AppConfig.bitmapCacheSize <= 0 || AppConfig.bitmapCacheSize >= 2048) { if (AppConfig.bitmapCacheSize !in 1..<2048) {
AppConfig.bitmapCacheSize = 50 AppConfig.bitmapCacheSize = 50
} }
return AppConfig.bitmapCacheSize * M return AppConfig.bitmapCacheSize * M
@@ -183,6 +183,12 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
} else { } else {
appDb.bookSourceDao.getBookSource(book.origin)?.let { appDb.bookSourceDao.getBookSource(book.origin)?.let {
bookSource = it bookSource = it
SourceCallBack.callBackBook(
SourceCallBack.START_READ,
it,
book,
curTextChapter?.chapter
)
if (book.getImageStyle().isNullOrBlank()) { if (book.getImageStyle().isNullOrBlank()) {
var imageStyle = it.getContentRule().imageStyle var imageStyle = it.getContentRule().imageStyle
if (imageStyle.isNullOrBlank() && (book.isImage || book.isPdf)) { if (imageStyle.isNullOrBlank() && (book.isImage || book.isPdf)) {
@@ -978,9 +984,9 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
} }
fun saveRead(pageChanged: Boolean = false) { fun saveRead(pageChanged: Boolean = false) {
val book = book ?: return
executor.execute { executor.execute {
kotlin.runCatching { kotlin.runCatching {
val book = book ?: return@execute
book.lastCheckCount = 0 book.lastCheckCount = 0
book.durChapterTime = System.currentTimeMillis() book.durChapterTime = System.currentTimeMillis()
val chapterChanged = book.durChapterIndex != durChapterIndex val chapterChanged = book.durChapterIndex != durChapterIndex
@@ -992,9 +998,10 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(), ContentProcessor.get(book.name, book.origin).getTitleReplaceRules(),
book.getUseReplaceRule() book.getUseReplaceRule()
) )
SourceCallBack.callBackBook(SourceCallBack.SAVE_READ, bookSource, book, it)
} }
} }
appDb.bookDao.update(book) book.update()
}.onFailure { }.onFailure {
AppLog.put("保存书籍阅读进度信息出错\n$it", it) AppLog.put("保存书籍阅读进度信息出错\n$it", it)
} }
@@ -1034,17 +1041,6 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
} }
} }
private fun clearExpiredChapterLoadingJob(clearAll: Boolean = false) {
val iterator = chapterLoadingJobs.iterator()
while (iterator.hasNext()) {
val (index, job) = iterator.next()
if (clearAll || index !in durChapterIndex - 1..durChapterIndex + 1) {
job.cancel()
iterator.remove()
}
}
}
fun cancelPreDownloadTask() { fun cancelPreDownloadTask() {
if (contentLoadFinish) { if (contentLoadFinish) {
preDownloadTask?.cancel() preDownloadTask?.cancel()
@@ -1068,6 +1064,17 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
} }
} }
private fun clearExpiredChapterLoadingJob(clearAll: Boolean = false) {
val iterator = chapterLoadingJobs.iterator()
while (iterator.hasNext()) {
val (index, job) = iterator.next()
if (clearAll || index !in durChapterIndex - 1..durChapterIndex + 1) {
job.cancel()
iterator.remove()
}
}
}
/** /**
* 注册回调 * 注册回调
*/ */
@@ -1124,4 +1131,4 @@ object ReadBook : CoroutineScope by MainScope(), KoinComponent {
fun cancelSelect() fun cancelSelect()
} }
} }
@@ -969,4 +969,3 @@ class AnalyzeUrl(
) )
} }
@@ -1918,6 +1918,13 @@ class ReadBookActivity : BaseReadBookActivity(),
observeEvent<Boolean>(EventBus.UP_SEEK_BAR) { observeEvent<Boolean>(EventBus.UP_SEEK_BAR) {
readMenu.upSeekBar() readMenu.upSeekBar()
} }
observeEvent<Boolean>(EventBus.REFRESH_BOOK_CONTENT) {
ReadBook.book?.let {
ReadBook.curTextChapter = null
binding.readView.upContent()
viewModel.refreshContentDur(it)
}
}
} }
private fun upScreenTimeOut() { private fun upScreenTimeOut() {
@@ -97,7 +97,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
if (!isMainView) return if (!isMainView) return
ChapterProvider.upViewSize(w, h) ChapterProvider.upViewSize(w, h)
textPage.format() textPage.format()
//TODO: 有关测量相关问题
} }
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
@@ -267,7 +266,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
is ImageColumn -> when (AppConfig.clickImgWay) { is ImageColumn -> when (AppConfig.clickImgWay) {
"1" -> { //预览图片 "1" -> { //预览图片
activity?.showDialogFragment(PhotoDialog(column.src)) activity?.showDialogFragment(PhotoDialog(column.src, isBook = true))
handled = true handled = true
} }
"2" -> { //兼容处理 "2" -> { //兼容处理
@@ -7,12 +7,10 @@ import android.graphics.Paint.FontMetrics
import android.graphics.RectF import android.graphics.RectF
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Build import android.os.Build
import android.text.Layout
import android.text.StaticLayout import android.text.StaticLayout
import android.text.TextPaint import android.text.TextPaint
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import io.legado.app.constant.AppPattern
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
@@ -21,28 +19,18 @@ import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig import io.legado.app.help.config.ReadBookConfig
import io.legado.app.help.config.ReadBookConfig.dottedBase import io.legado.app.help.config.ReadBookConfig.dottedBase
import io.legado.app.help.config.ReadBookConfig.dottedRatio import io.legado.app.help.config.ReadBookConfig.dottedRatio
import io.legado.app.model.ImageProvider
import io.legado.app.model.ReadBook import io.legado.app.model.ReadBook
import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.ui.book.read.page.entities.TextChapter
import io.legado.app.ui.book.read.page.entities.TextLine
import io.legado.app.ui.book.read.page.entities.TextPage
import io.legado.app.ui.book.read.page.entities.column.ImageColumn
import io.legado.app.ui.book.read.page.entities.column.ReviewColumn
import io.legado.app.ui.book.read.page.entities.column.TextColumn
import io.legado.app.utils.buildMainHandler import io.legado.app.utils.buildMainHandler
import io.legado.app.utils.dpToPx import io.legado.app.utils.dpToPx
import io.legado.app.utils.fastSum
import io.legado.app.utils.isContentScheme import io.legado.app.utils.isContentScheme
import io.legado.app.utils.isPad import io.legado.app.utils.isPad
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.spToPx import io.legado.app.utils.spToPx
import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.textHeight import io.legado.app.utils.textHeight
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
import java.util.LinkedList
import java.util.Locale
/** /**
* 解析内容生成章节和页面 * 解析内容生成章节和页面
@@ -180,6 +168,7 @@ object ChapterProvider {
upStyle() upStyle()
} }
/*
/** /**
* 获取拆分完的章节数据 * 获取拆分完的章节数据
*/ */
@@ -337,6 +326,7 @@ object ChapterProvider {
bookContent.effectiveReplaceRules bookContent.effectiveReplaceRules
) )
} }
*/
fun getTextChapterAsync( fun getTextChapterAsync(
scope: CoroutineScope, scope: CoroutineScope,
@@ -362,6 +352,7 @@ object ChapterProvider {
return textChapter return textChapter
} }
/*
/** /**
* 排版图片 * 排版图片
*/ */
@@ -869,6 +860,7 @@ object ChapterProvider {
} }
return stringList to widths return stringList to widths
} }
*/
/** /**
* 更新样式 * 更新样式
@@ -47,6 +47,10 @@ class SourceLoginJsExtensions(
postEvent(EventBus.REFRESH_BOOK_INFO, true) postEvent(EventBus.REFRESH_BOOK_INFO, true)
} }
fun refreshContent() {
postEvent(EventBus.REFRESH_BOOK_CONTENT, true)
}
fun copyText(text: String) { fun copyText(text: String) {
activityRef.get()?.sendToClip(text) activityRef.get()?.sendToClip(text)
} }
@@ -28,10 +28,11 @@ import java.io.ByteArrayOutputStream
*/ */
class PhotoDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_photo_view) { class PhotoDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_photo_view) {
constructor(src: String, sourceOrigin: String? = null) : this() { constructor(src: String, sourceOrigin: String? = null, isBook: Boolean = false) : this() {
arguments = Bundle().apply { arguments = Bundle().apply {
putString("src", src) putString("src", src)
putString("sourceOrigin", sourceOrigin) putString("sourceOrigin", sourceOrigin)
putBoolean("isBook", isBook)
} }
} }
+12 -1
View File
@@ -6,7 +6,13 @@
android:id="@+id/menu_ok" android:id="@+id/menu_ok"
android:icon="@drawable/ic_check" android:icon="@drawable/ic_check"
android:title="@string/ok" android:title="@string/ok"
app:showAsAction="always" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_web_refresh"
android:icon="@drawable/ic_refresh"
android:title="@string/refresh"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/menu_open_in_browser" android:id="@+id/menu_open_in_browser"
@@ -23,6 +29,11 @@
android:title="@string/full_screen" android:title="@string/full_screen"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_show_web_log"
android:checkable="true"
android:title="@string/show_web_log" />
<item <item
android:id="@+id/menu_disable_source" android:id="@+id/menu_disable_source"
android:title="@string/disable_source" android:title="@string/disable_source"
+1
View File
@@ -57,6 +57,7 @@
<item>1</item> <item>1</item>
<item>2</item> <item>2</item>
<item>3</item> <item>3</item>
<item>4</item>
</string-array> </string-array>
<string-array name="double_page_value"> <string-array name="double_page_value">
+4 -3
View File
@@ -117,10 +117,11 @@
</string-array> </string-array>
<string-array name="click_image_way_title"> <string-array name="click_image_way_title">
<item>新包名阅读行为</item> <item>新包名行为</item>
<item>预览图片</item> <item>预览图片</item>
<item>经典阅读行为</item> <item>经典行为</item>
<item>不响应</item> <item>关闭点击</item>
<item>双击生效</item>
</string-array> </string-array>
<string-array name="double_page_title"> <string-array name="double_page_title">
+1
View File
@@ -1387,4 +1387,5 @@
<string name="audio_cache_clean_time_summary">当前%d, 输入 0 代表退出即刻清理。</string> <string name="audio_cache_clean_time_summary">当前%d, 输入 0 代表退出即刻清理。</string>
<string name="show_swipe_animation">启用滑动时动画</string> <string name="show_swipe_animation">启用滑动时动画</string>
<string name="click_image_way">点击图片行为</string> <string name="click_image_way">点击图片行为</string>
<string name="show_web_log">输出日志</string>
</resources> </resources>