This commit is contained in:
Horis
2025-02-16 19:44:28 +08:00
parent 4cd31e1df8
commit 1bd879e9c3
10 changed files with 143 additions and 113 deletions
@@ -1,6 +1,5 @@
package io.legado.app.help.glide package io.legado.app.help.glide
import android.net.Uri
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.HttpException import com.bumptech.glide.load.HttpException
@@ -8,14 +7,14 @@ import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.util.ContentLengthInputStream import com.bumptech.glide.util.ContentLengthInputStream
import com.bumptech.glide.util.Preconditions
import io.legado.app.data.entities.BaseSource import io.legado.app.data.entities.BaseSource
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.http.CookieManager.cookieJarHeader import io.legado.app.help.http.CookieManager.cookieJarHeader
import io.legado.app.help.http.addHeaders import io.legado.app.help.http.addHeaders
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import io.legado.app.help.http.okHttpClientManga
import io.legado.app.help.source.SourceHelp import io.legado.app.help.source.SourceHelp
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.utils.ImageUtils import io.legado.app.utils.ImageUtils
import io.legado.app.utils.isWifiConnect import io.legado.app.utils.isWifiConnect
import okhttp3.Call import okhttp3.Call
@@ -38,6 +37,7 @@ class OkHttpStreamFetcher(
private var responseBody: ResponseBody? = null private var responseBody: ResponseBody? = null
private var callback: DataFetcher.DataCallback<in InputStream>? = null private var callback: DataFetcher.DataCallback<in InputStream>? = null
private var source: BaseSource? = null private var source: BaseSource? = null
private val manga = options.get(OkHttpModelLoader.mangaOption) == true
@Volatile @Volatile
private var call: Call? = null private var call: Call? = null
@@ -71,7 +71,11 @@ class OkHttpStreamFetcher(
requestBuilder.addHeaders(headerMap) requestBuilder.addHeaders(headerMap)
val request: Request = requestBuilder.build() val request: Request = requestBuilder.build()
this.callback = callback this.callback = callback
call = okHttpClient.newCall(request) call = if (manga) {
okHttpClientManga.newCall(request)
} else {
okHttpClient.newCall(request)
}
call?.enqueue(this) call?.enqueue(this)
} }
@@ -102,14 +106,13 @@ class OkHttpStreamFetcher(
override fun onResponse(call: Call, response: Response) { override fun onResponse(call: Call, response: Response) {
responseBody = response.body responseBody = response.body
if (response.isSuccessful) { if (response.isSuccessful) {
val manga = options.get(OkHttpModelLoader.mangaOption) == true
val decodeResult = if (manga) { val decodeResult = if (manga) {
ImageUtils.decode( ImageUtils.decode(
Uri.decode(oldUrl.toStringUrl()), oldUrl.toString(),
responseBody!!.byteStream().readBytes(), responseBody!!.bytes(),
isCover = false, isCover = false,
source, source,
ReadMange.book ReadManga.book
)?.let { )?.let {
ByteArrayInputStream(it) ByteArrayInputStream(it)
} }
@@ -123,13 +126,15 @@ class OkHttpStreamFetcher(
callback?.onLoadFailed(NoStackTraceException("封面二次解密失败")) callback?.onLoadFailed(NoStackTraceException("封面二次解密失败"))
} else { } else {
val contentLength: Long = val contentLength: Long =
if (decodeResult is ByteArrayInputStream) decodeResult.available() if (decodeResult is ByteArrayInputStream) decodeResult.available().toLong()
.toLong() else Preconditions.checkNotNull(responseBody).contentLength() else responseBody!!.contentLength()
stream = ContentLengthInputStream.obtain(decodeResult, contentLength) stream = ContentLengthInputStream.obtain(decodeResult, contentLength)
callback?.onDataReady(stream) callback?.onDataReady(stream)
} }
} else { } else {
failUrl.add(url.toStringUrl()) if (!manga) {
failUrl.add(url.toStringUrl())
}
callback?.onLoadFailed(HttpException(response.message, response.code)) callback?.onLoadFailed(HttpException(response.message, response.code))
} }
} }
@@ -1,6 +1,6 @@
package io.legado.app.help.glide.progress package io.legado.app.help.glide.progress
import android.text.TextUtils import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.runOnUI import io.legado.app.utils.runOnUI
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -31,21 +31,35 @@ object ProgressManager {
} }
fun addListener(url: String, listener: OnProgressListener) { fun addListener(url: String, listener: OnProgressListener) {
if (!TextUtils.isEmpty(url) && listener != null) { if (url.isNotEmpty() && listener != null) {
val url = getUrlNoOption(url)
listenersMap[url] = listener listenersMap[url] = listener
listener.invoke(false, 1, 0, 0) listener.invoke(false, 1, 0, 0)
} }
} }
fun removeListener(url: String) { fun removeListener(url: String) {
if (!TextUtils.isEmpty(url)) { if (url.isNotEmpty()) {
val url = getUrlNoOption(url)
listenersMap.remove(url) listenersMap.remove(url)
} }
} }
fun getProgressListener(url: String?): OnProgressListener { fun getProgressListener(url: String): OnProgressListener {
return if (TextUtils.isEmpty(url) || listenersMap.size == 0) { return if (url.isEmpty() || listenersMap.isEmpty()) {
null null
} else listenersMap[url] } else {
listenersMap[url]
}
} }
private fun getUrlNoOption(url: String): String {
val urlMatcher = AnalyzeUrl.paramPattern.matcher(url)
return if (urlMatcher.find()) {
url.substring(0, urlMatcher.start())
} else {
url
}
}
} }
@@ -3,10 +3,10 @@ package io.legado.app.help.http
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.help.CacheManager import io.legado.app.help.CacheManager
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.glide.progress.ProgressManager
import io.legado.app.help.glide.progress.ProgressManager.LISTENER import io.legado.app.help.glide.progress.ProgressManager.LISTENER
import io.legado.app.help.glide.progress.ProgressResponseBody import io.legado.app.help.glide.progress.ProgressResponseBody
import io.legado.app.help.http.CookieManager.cookieJarHeader import io.legado.app.help.http.CookieManager.cookieJarHeader
import io.legado.app.model.ReadManga
import io.legado.app.utils.NetworkUtils import io.legado.app.utils.NetworkUtils
import okhttp3.ConnectionSpec import okhttp3.ConnectionSpec
import okhttp3.Cookie import okhttp3.Cookie
@@ -96,15 +96,7 @@ val okHttpClient: OkHttpClient by lazy {
if (enableCookieJar) { if (enableCookieJar) {
CookieManager.saveResponse(networkResponse) CookieManager.saveResponse(networkResponse)
} }
networkResponse.newBuilder() networkResponse
.body(
ProgressResponseBody(
request.url.toString(),
LISTENER,
networkResponse.body!!
)
)
.build()
} }
if (AppConfig.isCronet) { if (AppConfig.isCronet) {
if (Cronet.loader?.install() == true) { if (Cronet.loader?.install() == true) {
@@ -128,6 +120,26 @@ val okHttpClient: OkHttpClient by lazy {
} }
} }
val okHttpClientManga by lazy {
okHttpClient.newBuilder().run {
val interceptors = interceptors()
interceptors.add(1) { chain ->
val request = chain.request()
val response = chain.proceed(request)
val url = request.url.toString()
response.newBuilder()
.body(ProgressResponseBody(url, LISTENER, response.body!!))
.build()
}
interceptors.add(1) { chain ->
ReadManga.rateLimiter.withLimitBlocking {
chain.proceed(chain.request())
}
}
build()
}
}
/** /**
* 缓存代理okHttp * 缓存代理okHttp
*/ */
@@ -97,7 +97,6 @@ object BookCover {
/** /**
* 加载漫画图片 * 加载漫画图片
*/ */
fun loadManga( fun loadManga(
context: Context, context: Context,
path: String?, path: String?,
@@ -9,6 +9,7 @@ import io.legado.app.data.entities.BookProgress
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.ReadRecord import io.legado.app.data.entities.ReadRecord
import io.legado.app.help.AppWebDav import io.legado.app.help.AppWebDav
import io.legado.app.help.ConcurrentRateLimiter
import io.legado.app.help.book.BookHelp import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.book.isLocal import io.legado.app.help.book.isLocal
@@ -41,7 +42,7 @@ import kotlinx.coroutines.launch
import kotlin.math.min import kotlin.math.min
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
object ReadMange : CoroutineScope by MainScope() { object ReadManga : CoroutineScope by MainScope() {
var inBookshelf = false var inBookshelf = false
var tocChanged = false var tocChanged = false
var chapterChanged = false var chapterChanged = false
@@ -67,10 +68,11 @@ object ReadMange : CoroutineScope by MainScope() {
private val downloadLoadingChapters = arrayListOf<Int>() private val downloadLoadingChapters = arrayListOf<Int>()
var isMangaMode = false var isMangaMode = false
val downloadScope = CoroutineScope(SupervisorJob() + IO) val downloadScope = CoroutineScope(SupervisorJob() + IO)
var rateLimiter = ConcurrentRateLimiter(null)
fun saveRead(pageChanged: Boolean = false) { fun saveRead(pageChanged: Boolean = false) {
executor.execute { executor.execute {
val book = ReadMange.book ?: return@execute val book = ReadManga.book ?: return@execute
book.lastCheckCount = 0 book.lastCheckCount = 0
book.durChapterTime = System.currentTimeMillis() book.durChapterTime = System.currentTimeMillis()
val chapterChanged = book.durChapterIndex != durChapterPagePos val chapterChanged = book.durChapterIndex != durChapterPagePos
@@ -89,7 +91,7 @@ object ReadMange : CoroutineScope by MainScope() {
} }
fun upData(book: Book) { fun upData(book: Book) {
ReadMange.book = book ReadManga.book = book
isMangaMode = true isMangaMode = true
durChapterPageCount = appDb.bookChapterDao.getChapterCount(book.bookUrl) durChapterPageCount = appDb.bookChapterDao.getChapterCount(book.bookUrl)
simulatedChapterSize = if (book.readSimulating()) { simulatedChapterSize = if (book.readSimulating()) {
@@ -103,14 +105,13 @@ object ReadMange : CoroutineScope by MainScope() {
durChapterPos = book.durChapterPos durChapterPos = book.durChapterPos
} }
upWebBook(book) upWebBook(book)
synchronized(this) { synchronized(this) {
loadingChapters.clear() loadingChapters.clear()
} }
} }
fun resetData(book: Book) { fun resetData(book: Book) {
ReadMange.book = book ReadManga.book = book
isMangaMode = true isMangaMode = true
readRecord.bookName = book.name readRecord.bookName = book.name
readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0 readRecord.readTime = appDb.readRecordDao.getReadTime(book.name) ?: 0
@@ -131,6 +132,7 @@ object ReadMange : CoroutineScope by MainScope() {
fun upWebBook(book: Book) { fun upWebBook(book: Book) {
appDb.bookSourceDao.getBookSource(book.origin)?.let { appDb.bookSourceDao.getBookSource(book.origin)?.let {
bookSource = it bookSource = it
rateLimiter = ConcurrentRateLimiter(it)
} ?: let { } ?: let {
bookSource = null bookSource = null
} }
@@ -193,8 +195,8 @@ object ReadMange : CoroutineScope by MainScope() {
scope: CoroutineScope, scope: CoroutineScope,
chapter: BookChapter, chapter: BookChapter,
) { ) {
val book = ReadMange.book ?: return removeLoading(chapter.index) val book = ReadManga.book ?: return removeLoading(chapter.index)
val bookSource = ReadMange.bookSource val bookSource = ReadManga.bookSource
if (bookSource != null) { if (bookSource != null) {
getContent(bookSource, scope, chapter, book) getContent(bookSource, scope, chapter, book)
} }
@@ -210,7 +212,7 @@ object ReadMange : CoroutineScope by MainScope() {
) { ) {
if (addLoading(index)) { if (addLoading(index)) {
Coroutine.async { Coroutine.async {
val book = ReadMange.book!! val book = ReadManga.book!!
appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter -> appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let { chapter ->
getContent( getContent(
downloadScope, downloadScope,
@@ -368,7 +370,7 @@ object ReadMange : CoroutineScope by MainScope() {
if (System.currentTimeMillis() - book.lastCheckTime < 600000) return if (System.currentTimeMillis() - book.lastCheckTime < 600000) return
book.lastCheckTime = System.currentTimeMillis() book.lastCheckTime = System.currentTimeMillis()
WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList -> WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList ->
if (book.bookUrl == ReadMange.book?.bookUrl if (book.bookUrl == ReadManga.book?.bookUrl
&& cList.size > durChapterPageCount && cList.size > durChapterPageCount
) { ) {
appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.delByBook(book.bookUrl)
@@ -532,7 +534,7 @@ object ReadMange : CoroutineScope by MainScope() {
if (System.currentTimeMillis() - book.lastCheckTime < 600000) return if (System.currentTimeMillis() - book.lastCheckTime < 600000) return
book.lastCheckTime = System.currentTimeMillis() book.lastCheckTime = System.currentTimeMillis()
WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList -> WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList ->
if (book.bookUrl == ReadMange.book?.bookUrl if (book.bookUrl == ReadManga.book?.bookUrl
&& cList.size > durChapterPageCount && cList.size > durChapterPageCount
) { ) {
appDb.bookChapterDao.delByBook(book.bookUrl) appDb.bookChapterDao.delByBook(book.bookUrl)
@@ -609,7 +611,7 @@ object ReadMange : CoroutineScope by MainScope() {
loadContent(durChapterPagePos) loadContent(durChapterPagePos)
} else { } else {
Coroutine.async { Coroutine.async {
val book = ReadMange.book!! val book = ReadManga.book!!
appDb.bookChapterDao.getChapter(book.bookUrl, durChapterPagePos) appDb.bookChapterDao.getChapter(book.bookUrl, durChapterPagePos)
?.let { chapter -> ?.let { chapter ->
getContent( getContent(
@@ -24,7 +24,7 @@ import io.legado.app.R
import io.legado.app.help.glide.progress.OnProgressListener import io.legado.app.help.glide.progress.OnProgressListener
import io.legado.app.help.glide.progress.ProgressManager import io.legado.app.help.glide.progress.ProgressManager
import io.legado.app.model.BookCover import io.legado.app.model.BookCover
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getCompatDrawable
import io.legado.app.utils.printOnDebug import io.legado.app.utils.printOnDebug
@@ -74,7 +74,7 @@ open class MangaVH<VB : ViewBinding>(val binding: VB, private val context: Conte
BookCover.loadManga( BookCover.loadManga(
context, context,
imageUrl, imageUrl,
sourceOrigin = ReadMange.book?.origin, sourceOrigin = ReadManga.book?.origin,
manga = true, manga = true,
useDefaultCover = context.getCompatDrawable(R.color.book_ant_10) useDefaultCover = context.getCompatDrawable(R.color.book_ant_10)
).addListener(object : RequestListener<Drawable> { ).addListener(object : RequestListener<Drawable> {
@@ -18,7 +18,7 @@ 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.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.mapParallelSafe import io.legado.app.utils.mapParallelSafe
@@ -42,13 +42,13 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
*/ */
fun initData(intent: Intent, success: (() -> Unit)? = null) { fun initData(intent: Intent, success: (() -> Unit)? = null) {
execute { execute {
ReadMange.inBookshelf = intent.getBooleanExtra("inBookshelf", true) ReadManga.inBookshelf = intent.getBooleanExtra("inBookshelf", true)
ReadMange.tocChanged = intent.getBooleanExtra("tocChanged", false) ReadManga.tocChanged = intent.getBooleanExtra("tocChanged", false)
val bookUrl = intent.getStringExtra("bookUrl") val bookUrl = intent.getStringExtra("bookUrl")
val book = when { val book = when {
bookUrl.isNullOrEmpty() -> appDb.bookDao.lastReadBook bookUrl.isNullOrEmpty() -> appDb.bookDao.lastReadBook
else -> appDb.bookDao.getBook(bookUrl) else -> appDb.bookDao.getBook(bookUrl)
} ?: ReadMange.book } ?: ReadManga.book
when { when {
book != null -> initMange(book) book != null -> initMange(book)
else -> context.getString(R.string.no_book)//没有找到书 else -> context.getString(R.string.no_book)//没有找到书
@@ -59,16 +59,16 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
val msg = "初始化数据失败\n${it.localizedMessage}" val msg = "初始化数据失败\n${it.localizedMessage}"
AppLog.put(msg, it) AppLog.put(msg, it)
}.onFinally { }.onFinally {
ReadMange.saveRead() ReadManga.saveRead()
} }
} }
private suspend fun initMange(book: Book) { private suspend fun initMange(book: Book) {
val isSameBook = ReadMange.book?.bookUrl == book.bookUrl val isSameBook = ReadManga.book?.bookUrl == book.bookUrl
if (isSameBook) { if (isSameBook) {
ReadMange.upData(book) ReadManga.upData(book)
} else { } else {
ReadMange.resetData(book) ReadManga.resetData(book)
} }
if (!book.isLocal && book.tocUrl.isEmpty() && !loadBookInfo(book)) { if (!book.isLocal && book.tocUrl.isEmpty() && !loadBookInfo(book)) {
return return
@@ -78,7 +78,7 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
return return
} }
if ((ReadMange.durChapterPageCount == 0 || book.isLocalModified()) && !loadChapterListAwait( if ((ReadManga.durChapterPageCount == 0 || book.isLocalModified()) && !loadChapterListAwait(
book book
) )
) { ) {
@@ -87,17 +87,17 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
ensureChapterExist() ensureChapterExist()
//开始加载内容 //开始加载内容
ReadMange.loadContent() ReadManga.loadContent()
//自动换源 //自动换源
if (!book.isLocal && ReadMange.bookSource == null) { if (!book.isLocal && ReadManga.bookSource == null) {
autoChangeSource(book.name, book.author) autoChangeSource(book.name, book.author)
return return
} }
} }
private suspend fun loadChapterListAwait(book: Book): Boolean { private suspend fun loadChapterListAwait(book: Book): Boolean {
ReadMange.bookSource?.let { ReadManga.bookSource?.let {
val oldBook = book.copy() val oldBook = book.copy()
WebBook.getChapterListAwait(it, book, true).onSuccess { cList -> WebBook.getChapterListAwait(it, book, true).onSuccess { cList ->
if (oldBook.bookUrl == book.bookUrl) { if (oldBook.bookUrl == book.bookUrl) {
@@ -108,12 +108,12 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
} }
appDb.bookChapterDao.delByBook(oldBook.bookUrl) appDb.bookChapterDao.delByBook(oldBook.bookUrl)
appDb.bookChapterDao.insert(*cList.toTypedArray()) appDb.bookChapterDao.insert(*cList.toTypedArray())
ReadMange.durChapterPageCount = cList.size ReadManga.durChapterPageCount = cList.size
ReadMange.simulatedChapterSize = book.simulatedTotalChapterNum() ReadManga.simulatedChapterSize = book.simulatedTotalChapterNum()
return true return true
}.onFailure { }.onFailure {
//加载章节出错 //加载章节出错
ReadMange.mCallback?.loadFail("加载目录失败") ReadManga.mCallback?.loadFail("加载目录失败")
return false return false
} }
} }
@@ -126,7 +126,7 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
* 加载详情页 * 加载详情页
*/ */
private suspend fun loadBookInfo(book: Book): Boolean { private suspend fun loadBookInfo(book: Book): Boolean {
val source = ReadMange.bookSource ?: return true val source = ReadManga.bookSource ?: return true
try { try {
WebBook.getBookInfoAwait(source, book, canReName = false) WebBook.getBookInfoAwait(source, book, canReName = false)
return true return true
@@ -138,8 +138,8 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
} }
private fun ensureChapterExist() { private fun ensureChapterExist() {
if (ReadMange.simulatedChapterSize > 0 && ReadMange.durChapterPagePos > ReadMange.simulatedChapterSize - 1) { if (ReadManga.simulatedChapterSize > 0 && ReadManga.durChapterPagePos > ReadManga.simulatedChapterSize - 1) {
ReadMange.durChapterPagePos = ReadMange.simulatedChapterSize - 1 ReadManga.durChapterPagePos = ReadManga.simulatedChapterSize - 1
} }
} }
@@ -198,15 +198,15 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
changeSourceCoroutine?.cancel() changeSourceCoroutine?.cancel()
changeSourceCoroutine = execute { changeSourceCoroutine = execute {
//换源中 //换源中
ReadMange.book?.migrateTo(book, toc) ReadManga.book?.migrateTo(book, toc)
book.removeType(BookType.updateError) book.removeType(BookType.updateError)
ReadMange.book?.delete() ReadManga.book?.delete()
appDb.bookDao.insert(book) appDb.bookDao.insert(book)
appDb.bookChapterDao.insert(*toc.toTypedArray()) appDb.bookChapterDao.insert(*toc.toTypedArray())
ReadMange.resetData(book) ReadManga.resetData(book)
toc.find { it.title.contains(ReadMange.chapterTitle) }?.run { toc.find { it.title.contains(ReadManga.chapterTitle) }?.run {
ReadMange.loadContent(index) ReadManga.loadContent(index)
} ?: ReadMange.loadContent() } ?: ReadManga.loadContent()
}.onError { }.onError {
AppLog.put("换源失败\n$it", it, true) AppLog.put("换源失败\n$it", it, true)
}.onFinally { }.onFinally {
@@ -224,12 +224,12 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
} }
fun openChapter(index: Int, durChapterPos: Int = 0) { fun openChapter(index: Int, durChapterPos: Int = 0) {
if (index < ReadMange.durChapterPageCount) { if (index < ReadManga.durChapterPageCount) {
ReadMange.chapterChanged = true ReadManga.chapterChanged = true
ReadMange.durChapterPagePos = index ReadManga.durChapterPagePos = index
ReadMange.durChapterPos = durChapterPos ReadManga.durChapterPos = durChapterPos
ReadMange.saveRead() ReadManga.saveRead()
ReadMange.loadContent(index) ReadManga.loadContent(index)
} }
} }
@@ -31,8 +31,8 @@ import io.legado.app.help.book.isImage
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Backup
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.model.ReadMange.mFirstLoading import io.legado.app.model.ReadManga.mFirstLoading
import io.legado.app.model.recyclerView.MangeContent import io.legado.app.model.recyclerView.MangeContent
import io.legado.app.model.recyclerView.ReaderLoading import io.legado.app.model.recyclerView.ReaderLoading
import io.legado.app.receiver.NetworkChangedListener import io.legado.app.receiver.NetworkChangedListener
@@ -56,7 +56,7 @@ import io.legado.app.utils.visible
import splitties.dimensions.dp import splitties.dimensions.dp
class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>(), class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>(),
ReadMange.Callback, ChangeBookSourceDialog.CallBack, MangaMenu.CallBack { ReadManga.Callback, ChangeBookSourceDialog.CallBack, MangaMenu.CallBack {
private val mLayoutManager by lazy { private val mLayoutManager by lazy {
LinearLayoutManager(this@ReadMangaActivity) LinearLayoutManager(this@ReadMangaActivity)
@@ -114,7 +114,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
immersionFullScreen(windowInsetsControllerCompat) immersionFullScreen(windowInsetsControllerCompat)
ReadMange.register(this) ReadManga.register(this)
binding.mRecyclerMange.run { binding.mRecyclerMange.run {
adapter = mAdapter adapter = mAdapter
itemAnimator = null itemAnimator = null
@@ -141,7 +141,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
try { try {
val content = mAdapter.getCurrentList()[position] val content = mAdapter.getCurrentList()[position]
if (content is MangeContent) { if (content is MangeContent) {
ReadMange.durChapterPos = content.mDurChapterPos.minus(1) ReadManga.durChapterPos = content.mDurChapterPos.minus(1)
upText( upText(
content.mChapterPagePos, content.mChapterPagePos,
content.mChapterPageCount, content.mChapterPageCount,
@@ -166,15 +166,15 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
binding.llLoading.isVisible = true binding.llLoading.isVisible = true
binding.llRetry.isGone = true binding.llRetry.isGone = true
mFirstLoading = false mFirstLoading = false
ReadMange.loadContent() ReadManga.loadContent()
} }
mAdapter.addFooterView { mAdapter.addFooterView {
ViewLoadMoreBinding.bind(loadMoreView) ViewLoadMoreBinding.bind(loadMoreView)
} }
loadMoreView.setOnClickListener { loadMoreView.setOnClickListener {
if (!loadMoreView.isLoading && !ReadMange.gameOver) { if (!loadMoreView.isLoading && !ReadManga.gameOver) {
scrollToBottom(true, ReadMange.durChapterPagePos) scrollToBottom(true, ReadManga.durChapterPagePos)
} }
} }
loadMoreView.gone() loadMoreView.gone()
@@ -191,9 +191,9 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
} }
private fun scrollToBottom(forceLoad: Boolean = false, index: Int) { private fun scrollToBottom(forceLoad: Boolean = false, index: Int) {
if ((loadMoreView.hasMore && !loadMoreView.isLoading) && !ReadMange.gameOver || forceLoad) { if ((loadMoreView.hasMore && !loadMoreView.isLoading) && !ReadManga.gameOver || forceLoad) {
loadMoreView.hasMore() loadMoreView.hasMore()
ReadMange.moveToNextChapter(index) ReadManga.moveToNextChapter(index)
} }
} }
@@ -213,27 +213,27 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
if (list.size > 1) { if (list.size > 1) {
binding.infobar.isVisible = true binding.infobar.isVisible = true
upText( upText(
ReadMange.durChapterPagePos, ReadManga.durChapterPagePos,
ReadMange.durChapterPageCount, ReadManga.durChapterPageCount,
ReadMange.durChapterPos, ReadManga.durChapterPos,
ReadMange.durChapterCount ReadManga.durChapterCount
) )
} }
if (ReadMange.durChapterPos + 2 > mAdapter.getCurrentList().size - 3) { if (ReadManga.durChapterPos + 2 > mAdapter.getCurrentList().size - 3) {
val nextIndex = val nextIndex =
(mAdapter.getCurrentList().last() as ReaderLoading).mNextChapterIndex (mAdapter.getCurrentList().last() as ReaderLoading).mNextChapterIndex
scrollToBottom(index = nextIndex) scrollToBottom(index = nextIndex)
} else { } else {
binding.mRecyclerMange.scrollToPosition(ReadMange.durChapterPos) binding.mRecyclerMange.scrollToPosition(ReadManga.durChapterPos)
} }
} }
if (ReadMange.chapterChanged) { if (ReadManga.chapterChanged) {
binding.mRecyclerMange.scrollToPosition(ReadMange.durChapterPos) binding.mRecyclerMange.scrollToPosition(ReadManga.durChapterPos)
} }
ReadMange.chapterChanged = false ReadManga.chapterChanged = false
loadMoreView.visible() loadMoreView.visible()
mFirstLoading = true mFirstLoading = true
loadMoreView.stopLoad() loadMoreView.stopLoad()
@@ -259,20 +259,20 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
networkChangedListener.onNetworkChanged = { networkChangedListener.onNetworkChanged = {
// 当网络是可用状态且无需初始化时同步进度(初始化中已有同步进度逻辑) // 当网络是可用状态且无需初始化时同步进度(初始化中已有同步进度逻辑)
if (AppConfig.syncBookProgressPlus && NetworkUtils.isAvailable() && !justInitData) { if (AppConfig.syncBookProgressPlus && NetworkUtils.isAvailable() && !justInitData) {
ReadMange.syncProgress({ progress -> sureNewProgress(progress) }) ReadManga.syncProgress({ progress -> sureNewProgress(progress) })
} }
} }
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
if (ReadMange.inBookshelf) { if (ReadManga.inBookshelf) {
ReadMange.saveRead() ReadManga.saveRead()
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
if (AppConfig.syncBookProgressPlus) { if (AppConfig.syncBookProgressPlus) {
ReadMange.syncProgress() ReadManga.syncProgress()
} else { } else {
ReadMange.uploadProgress() ReadManga.uploadProgress()
} }
Backup.autoBack(this) Backup.autoBack(this)
} }
@@ -285,7 +285,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
} }
override fun loadFail(msg: String) { override fun loadFail(msg: String) {
if (!mFirstLoading || ReadMange.chapterChanged) { if (!mFirstLoading || ReadManga.chapterChanged) {
binding.llLoading.isGone = true binding.llLoading.isGone = true
binding.llRetry.isVisible = true binding.llRetry.isVisible = true
binding.tvMsg.text = msg binding.tvMsg.text = msg
@@ -299,8 +299,8 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
} }
override fun adjustmentProgress() { override fun adjustmentProgress() {
if (ReadMange.chapterChanged) { if (ReadManga.chapterChanged) {
binding.mRecyclerMange.scrollToPosition(ReadMange.durChapterPos) binding.mRecyclerMange.scrollToPosition(ReadManga.durChapterPos)
binding.flLoading.isGone = true binding.flLoading.isGone = true
} }
} }
@@ -309,7 +309,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
get() = mAdapter.getCurrentList() get() = mAdapter.getCurrentList()
override fun onDestroy() { override fun onDestroy() {
ReadMange.unregister() ReadManga.unregister()
super.onDestroy() super.onDestroy()
} }
@@ -324,19 +324,19 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
setMessage(R.string.cloud_progress_exceeds_current) setMessage(R.string.cloud_progress_exceeds_current)
okButton { okButton {
binding.flLoading.isVisible = true binding.flLoading.isVisible = true
ReadMange.setProgress(progress) ReadManga.setProgress(progress)
} }
noButton() noButton()
} }
} }
override val oldBook: Book? override val oldBook: Book?
get() = ReadMange.book get() = ReadManga.book
override fun changeTo(source: BookSource, book: Book, toc: List<BookChapter>) { override fun changeTo(source: BookSource, book: Book, toc: List<BookChapter>) {
if (book.isImage) { if (book.isImage) {
binding.flLoading.isVisible = true binding.flLoading.isVisible = true
ReadMange.chapterChanged = true ReadManga.chapterChanged = true
viewModel.changeTo(book, toc) viewModel.changeTo(book, toc)
} else { } else {
toastOnUi("所选择的源不是漫画源") toastOnUi("所选择的源不是漫画源")
@@ -356,13 +356,13 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
when (item.itemId) { when (item.itemId) {
R.id.menu_change_source -> { R.id.menu_change_source -> {
binding.mangaMenu.runMenuOut() binding.mangaMenu.runMenuOut()
ReadMange.book?.let { ReadManga.book?.let {
showDialogFragment(ChangeBookSourceDialog(it.name, it.author)) showDialogFragment(ChangeBookSourceDialog(it.name, it.author))
} }
} }
R.id.menu_catalog -> { R.id.menu_catalog -> {
ReadMange.book?.let { ReadManga.book?.let {
tocActivity.launch(it.bookUrl) tocActivity.launch(it.bookUrl)
} }
} }
@@ -371,7 +371,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangeBinding, MangaViewModel>()
} }
override fun openBookInfoActivity() { override fun openBookInfoActivity() {
ReadMange.book?.let { ReadManga.book?.let {
bookInfoActivity.launch { bookInfoActivity.launch {
putExtra("name", it.name) putExtra("name", it.name)
putExtra("author", it.author) putExtra("author", it.author)
@@ -22,7 +22,7 @@ import io.legado.app.databinding.BookComicLoadingRvBinding
import io.legado.app.databinding.BookComicRvBinding import io.legado.app.databinding.BookComicRvBinding
import io.legado.app.help.glide.progress.ProgressManager import io.legado.app.help.glide.progress.ProgressManager
import io.legado.app.model.BookCover import io.legado.app.model.BookCover
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.model.recyclerView.MangaVH import io.legado.app.model.recyclerView.MangaVH
import io.legado.app.model.recyclerView.MangeContent import io.legado.app.model.recyclerView.MangeContent
import io.legado.app.model.recyclerView.ReaderLoading import io.legado.app.model.recyclerView.ReaderLoading
@@ -66,7 +66,7 @@ class MangaAdapter(private val context: Context) :
fun submitList(contents: MutableList<Any>, runnable: Runnable) { fun submitList(contents: MutableList<Any>, runnable: Runnable) {
val currentList = mDiffer.currentList.toMutableList() val currentList = mDiffer.currentList.toMutableList()
currentList.addAll(contents) currentList.addAll(contents)
if (ReadMange.chapterChanged) { if (ReadManga.chapterChanged) {
mDiffer.submitList(contents) { mDiffer.submitList(contents) {
runnable.run() runnable.run()
} }
@@ -220,7 +220,7 @@ class MangaAdapter(private val context: Context) :
return BookCover.loadManga( return BookCover.loadManga(
context, context,
item.mImageUrl, item.mImageUrl,
sourceOrigin = ReadMange.book?.origin, sourceOrigin = ReadManga.book?.origin,
manga = true, manga = true,
useDefaultCover = context.getCompatDrawable(R.color.book_ant_10) useDefaultCover = context.getCompatDrawable(R.color.book_ant_10)
) )
@@ -6,8 +6,6 @@ import android.graphics.Color
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.animation.Animation import android.view.animation.Animation
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.view.isGone import androidx.core.view.isGone
@@ -22,7 +20,7 @@ import io.legado.app.lib.theme.bottomBackground
import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.getPrimaryTextColor
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.model.ReadMange import io.legado.app.model.ReadManga
import io.legado.app.ui.browser.WebViewActivity import io.legado.app.ui.browser.WebViewActivity
import io.legado.app.utils.ColorUtils import io.legado.app.utils.ColorUtils
import io.legado.app.utils.ConstraintModify import io.legado.app.utils.ConstraintModify
@@ -95,7 +93,7 @@ class MangaMenu @JvmOverloads constructor(
private val menuInListener = object : Animation.AnimationListener { private val menuInListener = object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) { override fun onAnimationStart(animation: Animation) {
binding.tvSourceAction.text = binding.tvSourceAction.text =
ReadMange.bookSource?.bookSourceName ?: context.getString(R.string.book_source) ReadManga.bookSource?.bookSourceName ?: context.getString(R.string.book_source)
callBack.upSystemUiVisibility(true) callBack.upSystemUiVisibility(true)
binding.tvSourceAction.isGone = false binding.tvSourceAction.isGone = false
} }
@@ -211,7 +209,7 @@ class MangaMenu @JvmOverloads constructor(
val url = tvChapterUrl.text.toString() val url = tvChapterUrl.text.toString()
putExtra("title", tvChapterName.text) putExtra("title", tvChapterName.text)
putExtra("url", url) putExtra("url", url)
IntentData.put(url, ReadMange.bookSource?.getHeaderMap(true)) IntentData.put(url, ReadManga.bookSource?.getHeaderMap(true))
} }
} }
} }