[优化] 支持更多Sigma版本特性(@Luoyacheng)
This commit is contained in:
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
Reference in new issue
Block a user