Horis 1 год назад
Родитель
Сommit
6f875ac04d

+ 17 - 35
app/src/main/java/io/legado/app/model/ReadManga.kt

@@ -21,8 +21,8 @@ import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.help.globalExecutor
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.ui.book.manga.entities.MangaChapter
-import io.legado.app.ui.book.manga.entities.MangaContent
 import io.legado.app.ui.book.manga.entities.MangaContentData
+import io.legado.app.ui.book.manga.entities.MangaPage
 import io.legado.app.ui.book.manga.entities.ReaderLoading
 import io.legado.app.utils.mapIndexed
 import kotlinx.coroutines.CoroutineScope
@@ -67,7 +67,6 @@ object ReadManga : CoroutineScope by MainScope() {
     var rateLimiter = ConcurrentRateLimiter(null)
     val mangaContents get() = buildContentList()
     val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1
-    val mSeekParPos = mutableMapOf<Int, MutableMap<Int, Int>>()
 
     fun resetData(book: Book) {
         ReadManga.book = book
@@ -260,14 +259,18 @@ object ReadManga : CoroutineScope by MainScope() {
     /**
      * 加载下一章
      */
-    fun moveToNextChapter(startLoad: () -> Unit): Boolean {
+    fun moveToNextChapter(toFirst: Boolean = false): Boolean {
         if (durChapterIndex < simulatedChapterSize - 1) {
+            if (toFirst) {
+                mCallback?.showLoading()
+                durChapterPos = 0
+            }
             durChapterIndex++
             prevMangaChapter = curMangaChapter
             curMangaChapter = nextMangaChapter
             nextMangaChapter = null
             if (curMangaChapter == null) {
-                startLoad.invoke()
+                mCallback?.startLoad()
                 loadContent(durChapterIndex)
             } else {
                 mCallback?.upContent()
@@ -283,8 +286,12 @@ object ReadManga : CoroutineScope by MainScope() {
         }
     }
 
-    fun moveToPrevChapter(): Boolean {
+    fun moveToPrevChapter(toFirst: Boolean = false): Boolean {
         if (durChapterIndex > 0) {
+            if (toFirst) {
+                mCallback?.showLoading()
+                durChapterPos = 0
+            }
             durChapterIndex--
             nextMangaChapter = curMangaChapter
             curMangaChapter = prevMangaChapter
@@ -561,8 +568,8 @@ object ReadManga : CoroutineScope by MainScope() {
     private suspend fun getManageChapter(chapter: BookChapter, content: String): MangaChapter {
         val list = BookHelp.flowImages(chapter, content)
             .distinctUntilChanged().mapIndexed { index, src ->
-                MangaContent(
-                    mChapterIndex = chapter.index,
+                MangaPage(
+                    chapterIndex = chapter.index,
                     chapterSize = chapterSize,
                     mImageUrl = src,
                     index = index,
@@ -577,43 +584,18 @@ object ReadManga : CoroutineScope by MainScope() {
         }
 
         val contentList = mutableListOf<Any>()
-        contentList.add(ReaderLoading(chapter.index, "阅读 ${chapter.title}"))
+        contentList.add(ReaderLoading(chapter.index, -1, "阅读 ${chapter.title}"))
         contentList.addAll(list)
-        contentList.add(ReaderLoading(chapter.index, "已读完 ${chapter.title}"))
+        contentList.add(ReaderLoading(chapter.index, imageCount, "已读完 ${chapter.title}"))
 
         return MangaChapter(chapter, contentList, imageCount)
     }
 
-    fun recordMangaPosition(dataList: MutableList<Any>) {
-        Coroutine.async {
-            var globalPosition = 0
-            val mangaList = mutableListOf<MangaContent>()
-            dataList.forEach {
-                if (it is MangaContent) {
-                    mangaList.add(it)
-                }
-            }
-            dataList.groupBy { if (it is MangaContent) it.mChapterIndex else (it as ReaderLoading).mChapterIndex }
-                .forEach { (chapterIndex, items) ->
-                    val itemMap = mutableMapOf<Int, Int>()
-                    for (i in items.indices) {
-                        val item = items[i]
-                        if (item is MangaContent) {
-                            itemMap[item.index] = globalPosition++
-                        } else {
-                            globalPosition++
-                        }
-                    }
-                    mSeekParPos[chapterIndex] = itemMap
-                }
-        }
-    }
-
-
     interface Callback {
         fun upContent()
         fun loadFail(msg: String)
         fun sureNewProgress(progress: BookProgress)
         fun showLoading()
+        fun startLoad()
     }
 }

+ 57 - 58
app/src/main/java/io/legado/app/ui/book/manga/ReadMangaActivity.kt

@@ -46,7 +46,8 @@ import io.legado.app.ui.book.manga.config.MangaColorFilterConfig
 import io.legado.app.ui.book.manga.config.MangaColorFilterDialog
 import io.legado.app.ui.book.manga.config.MangaFooterConfig
 import io.legado.app.ui.book.manga.config.MangaFooterSettingDialog
-import io.legado.app.ui.book.manga.entities.MangaContent
+import io.legado.app.ui.book.manga.entities.BaseMangaPage
+import io.legado.app.ui.book.manga.entities.MangaPage
 import io.legado.app.ui.book.manga.recyclerview.MangaAdapter
 import io.legado.app.ui.book.read.MangaMenu
 import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED
@@ -56,6 +57,8 @@ import io.legado.app.ui.widget.recycler.LoadMoreView
 import io.legado.app.utils.GSON
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.StartActivityContract
+import io.legado.app.utils.fastBinarySearch
+import io.legado.app.utils.findCenterViewPosition
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.getCompatColor
 import io.legado.app.utils.gone
@@ -187,13 +190,8 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
     override fun observeLiveBus() {
         observeEvent<MangaFooterConfig>(EventBus.UP_MANGA_CONFIG) {
             mMangaFooterConfig = it
-            upInfoBar(
-                ReadManga.durChapterIndex,
-                ReadManga.chapterSize,
-                ReadManga.durChapterPos,
-                ReadManga.durChapterImageCount,
-                ReadManga.curMangaChapter?.chapter?.title ?: ""
-            )
+            val item = mAdapter.getItem(binding.mRecyclerManga.findCenterViewPosition())
+            upInfoBar(item)
         }
     }
 
@@ -215,26 +213,18 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
             disableMangaScaling(AppConfig.disableMangaScale)
             setPreScrollListener { _, _, _, position ->
                 if (mAdapter.isNotEmpty()) {
-                    val content = mAdapter.getItem(position)
-                    if (content is MangaContent) {
-                        if (ReadManga.durChapterIndex < content.mChapterIndex) {
-                            ReadManga.moveToNextChapter {
-                                loadMoreView.startLoad()
-                            }
-                        } else if (ReadManga.durChapterIndex > content.mChapterIndex) {
+                    val item = mAdapter.getItem(position)
+                    if (item is MangaPage) {
+                        if (ReadManga.durChapterIndex < item.chapterIndex) {
+                            ReadManga.moveToNextChapter()
+                        } else if (ReadManga.durChapterIndex > item.chapterIndex) {
                             ReadManga.moveToPrevChapter()
                         } else {
-                            ReadManga.durChapterPos = content.index
+                            ReadManga.durChapterPos = item.index
                             ReadManga.curPageChanged()
                         }
-                        binding.mangaMenu.upSeekBar(content.index, content.imageCount)
-                        upInfoBar(
-                            content.mChapterIndex,
-                            content.chapterSize,
-                            content.index,
-                            content.imageCount,
-                            content.mChapterName
-                        )
+                        binding.mangaMenu.upSeekBar(item.index, item.imageCount)
+                        upInfoBar(item)
                     }
                 }
             }
@@ -279,16 +269,9 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
             val nextFinish = data.nextFinish
             mAdapter.submitList(list) {
                 binding.mangaMenu.upSeekBar(ReadManga.durChapterPos, ReadManga.durChapterImageCount)
-                ReadManga.recordMangaPosition(mAdapter.getCurrentList())
                 if (loadingViewVisible && curFinish) {
                     binding.infobar.isVisible = true
-                    upInfoBar(
-                        ReadManga.durChapterIndex,
-                        ReadManga.chapterSize,
-                        ReadManga.durChapterPos,
-                        ReadManga.durChapterImageCount,
-                        ReadManga.curMangaChapter!!.chapter.title
-                    )
+                    upInfoBar(list[pos])
                     binding.mRecyclerManga.scrollToPosition(pos)
                     binding.flLoading.isGone = true
                     loadMoreView.visible()
@@ -307,13 +290,15 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         }
     }
 
-    private fun upInfoBar(
-        chapterIndex: Int,
-        chapterSize: Int,
-        chapterPos: Int,
-        chapterImageCount: Int,
-        chapterName: String,
-    ) {
+    private fun upInfoBar(page: Any?) {
+        if (page !is MangaPage) {
+            return
+        }
+        val chapterIndex = page.index
+        val chapterSize = page.chapterSize
+        val chapterPos = page.index
+        val imageCount = page.imageCount
+        val chapterName = page.mChapterName
         mMangaFooterConfig.run {
             mLabelBuilder.clear()
             binding.infobar.isGone = hideFooter
@@ -327,7 +312,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
                 if (!hidePageNumberLabel) {
                     mLabelBuilder.append(getString(R.string.manga_check_page_number))
                 }
-                mLabelBuilder.append("${chapterPos + 1}/${chapterImageCount}").append(" ")
+                mLabelBuilder.append("${chapterPos + 1}/${imageCount}").append(" ")
             }
 
             if (!hideChapter) {
@@ -341,16 +326,16 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
                 if (!hideProgressRatioLabel) {
                     mLabelBuilder.append(getString(R.string.manga_check_progress))
                 }
-                val percent = if (chapterSize == 0 || chapterImageCount == 0 && chapterIndex == 0) {
+                val percent = if (chapterSize == 0 || imageCount == 0 && chapterIndex == 0) {
                     "0.0%"
-                } else if (chapterImageCount == 0) {
+                } else if (imageCount == 0) {
                     df.format((chapterIndex + 1.0f) / chapterSize.toDouble())
                 } else {
                     var percent =
                         df.format(
-                            chapterIndex * 1.0f / chapterSize + 1.0f / chapterSize * (chapterPos + 1) / chapterImageCount.toDouble()
+                            chapterIndex * 1.0f / chapterSize + 1.0f / chapterSize * (chapterPos + 1) / imageCount.toDouble()
                         )
-                    if (percent == "100.0%" && (chapterIndex + 1 != chapterSize || chapterPos + 1 != chapterImageCount)) {
+                    if (percent == "100.0%" && (chapterIndex + 1 != chapterSize || chapterPos + 1 != imageCount)) {
                         percent = "99.9%"
                     }
                     percent
@@ -432,6 +417,12 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         }
     }
 
+    override fun startLoad() {
+        lifecycleScope.launch {
+            loadMoreView.startLoad()
+        }
+    }
+
     override val oldBook: Book?
         get() = ReadManga.book
 
@@ -540,10 +531,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
                     if (item.isChecked) LinearLayoutManager.HORIZONTAL else LinearLayoutManager.VERTICAL
                 singlePagerScroller(item.isChecked)
                 mAdapter.isHorizontal = item.isChecked
-                mAdapter.notifyItemRangeChanged(
-                    ReadManga.durChapterPos.minus(2),
-                    mAdapter.getCurrentList().size
-                )
+                mAdapter.notifyItemRangeChanged(0, mAdapter.itemCount)
             }
 
             R.id.menu_manga_color_filter -> {
@@ -567,12 +555,6 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         toggleSystemBar(menuIsVisible)
     }
 
-    override fun moveToTargetIndex(isNext: Boolean) {
-        var targetIndex =
-            if (isNext) ReadManga.durChapterIndex + 1 else ReadManga.durChapterIndex - 1
-        viewModel.openChapter(if (isNext) targetIndex else targetIndex, 0)
-    }
-
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
         val keyCode = event.keyCode
         val action = event.action
@@ -756,10 +738,27 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         window.decorView.postInvalidate()
     }
 
-    override fun seekValue(pos: Int) {
-        val mangaIndex = ReadManga.mSeekParPos[ReadManga.durChapterIndex]
-        if (mangaIndex != null && mangaIndex[pos] != null) {
-            binding.mRecyclerManga.scrollToPosition(mangaIndex[pos]!!)
+    override fun skipToPage(pos: Int) {
+        val durChapterIndex = ReadManga.durChapterIndex
+        val pos = mAdapter.getItems().fastBinarySearch {
+            val chapterIndex: Int
+            val pageIndex: Int
+            if (it is BaseMangaPage) {
+                chapterIndex = it.chapterIndex
+                pageIndex = it.index
+            } else {
+                error("unknown item type")
+            }
+            val delta = chapterIndex - durChapterIndex
+            if (delta != 0) {
+                delta
+            } else {
+                pageIndex - pos
+            }
+        }
+        if (pos > -1) {
+            binding.mRecyclerManga.scrollToPosition(pos)
+            upInfoBar(mAdapter.getItem(pos))
         }
     }
 }

+ 6 - 0
app/src/main/java/io/legado/app/ui/book/manga/entities/BaseMangaPage.kt

@@ -0,0 +1,6 @@
+package io.legado.app.ui.book.manga.entities
+
+interface BaseMangaPage {
+    val chapterIndex: Int
+    val index: Int
+}

+ 4 - 4
app/src/main/java/io/legado/app/ui/book/manga/entities/MangaContent.kt → app/src/main/java/io/legado/app/ui/book/manga/entities/MangaPage.kt

@@ -1,10 +1,10 @@
 package io.legado.app.ui.book.manga.entities
 
-data class MangaContent(
-    val mChapterIndex: Int = 0,//总章节位置
+data class MangaPage(
+    override val chapterIndex: Int = 0,//总章节位置
     val chapterSize: Int,//总章节数量
     val mImageUrl: String = "",//当前URL
-    val index: Int = 0,//当前章节位置
+    override val index: Int = 0,//当前章节位置
     var imageCount: Int = 0,//当前章节内容总数
     val mChapterName: String = "",//章节名称
-)
+) : BaseMangaPage

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/manga/entities/ReaderLoading.kt

@@ -1,7 +1,8 @@
 package io.legado.app.ui.book.manga.entities
 
 data class ReaderLoading(
-    val mChapterIndex: Int = 0,
+    override val chapterIndex: Int = 0,
+    override val index: Int = 0,
     val mMessage: String? = null,
-    var mLoading: Boolean = false,
-)
+) : BaseMangaPage
+

+ 13 - 13
app/src/main/java/io/legado/app/ui/book/manga/recyclerview/MangaAdapter.kt

@@ -26,7 +26,7 @@ import io.legado.app.help.glide.progress.ProgressManager
 import io.legado.app.model.BookCover
 import io.legado.app.model.ReadManga
 import io.legado.app.ui.book.manga.config.MangaColorFilterConfig
-import io.legado.app.ui.book.manga.entities.MangaContent
+import io.legado.app.ui.book.manga.entities.MangaPage
 import io.legado.app.ui.book.manga.entities.ReaderLoading
 import io.legado.app.utils.getCompatDrawable
 import java.util.Collections
@@ -49,7 +49,7 @@ class MangaAdapter(private val context: Context) :
         override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean {
             return if (oldItem is ReaderLoading && newItem is ReaderLoading) {
                 newItem.mMessage == oldItem.mMessage
-            } else if (oldItem is MangaContent && newItem is MangaContent) {
+            } else if (oldItem is MangaPage && newItem is MangaPage) {
                 oldItem.mImageUrl == newItem.mImageUrl
             } else false
         }
@@ -57,7 +57,7 @@ class MangaAdapter(private val context: Context) :
         override fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean {
             return if (oldItem is ReaderLoading && newItem is ReaderLoading) {
                 oldItem == newItem
-            } else if (oldItem is MangaContent && newItem is MangaContent) {
+            } else if (oldItem is MangaPage && newItem is MangaPage) {
                 oldItem == newItem
             } else false
         }
@@ -67,7 +67,7 @@ class MangaAdapter(private val context: Context) :
 
     fun getItem(@IntRange(from = 0) position: Int) = mDiffer.currentList.getOrNull(position)
 
-    fun getCurrentList() = mDiffer.currentList
+    fun getItems() = mDiffer.currentList
 
     fun isEmpty() = mDiffer.currentList.isEmpty()
 
@@ -91,7 +91,7 @@ class MangaAdapter(private val context: Context) :
             )
             binding.retry.setOnClickListener {
                 val item = mDiffer.currentList[layoutPosition]
-                if (item is MangaContent) {
+                if (item is MangaPage) {
                     loadImageWithRetry(
                         item.mImageUrl, isHorizontal, item.imageCount == 1
                     )
@@ -99,7 +99,7 @@ class MangaAdapter(private val context: Context) :
             }
         }
 
-        fun onBind(item: MangaContent) {
+        fun onBind(item: MangaPage) {
             setImageColorFilter()
             loadImageWithRetry(item.mImageUrl, isHorizontal, item.imageCount == 1)
         }
@@ -155,7 +155,7 @@ class MangaAdapter(private val context: Context) :
     override fun getItemViewType(position: Int): Int {
         return when {
             isFooter(position) -> TYPE_FOOTER_VIEW + position - getActualItemCount()
-            getItem(position) is MangaContent -> CONTENT_VIEW
+            getItem(position) is MangaPage -> CONTENT_VIEW
             getItem(position) is ReaderLoading -> LOADING_VIEW
             else -> error("Unknown view type!")
         }
@@ -182,7 +182,7 @@ class MangaAdapter(private val context: Context) :
 
     override fun onBindViewHolder(vh: RecyclerView.ViewHolder, position: Int) {
         when (vh) {
-            is PageViewHolder -> vh.onBind(getItem(position) as MangaContent)
+            is PageViewHolder -> vh.onBind(getItem(position) as MangaPage)
             is PageMoreViewHolder -> vh.onBind(getItem(position) as ReaderLoading)
         }
     }
@@ -202,7 +202,7 @@ class MangaAdapter(private val context: Context) :
     /**
      * 除去header和footer
      */
-    fun getActualItemCount() = getCurrentList().size
+    fun getActualItemCount() = getItems().size
 
     @Synchronized
     fun removeFooterView(footer: ((parent: ViewGroup) -> ViewBinding)) {
@@ -216,13 +216,13 @@ class MangaAdapter(private val context: Context) :
     }
 
     override fun getPreloadItems(position: Int): MutableList<Any> {
-        if (getCurrentList().isEmpty()) return Collections.emptyList()
-        if (position >= getCurrentList().size) return Collections.emptyList()
-        return getCurrentList().subList(position, position + 1)
+        if (getItems().isEmpty()) return Collections.emptyList()
+        if (position >= getItems().size) return Collections.emptyList()
+        return getItems().subList(position, position + 1)
     }
 
     override fun getPreloadRequestBuilder(item: Any): RequestBuilder<*>? {
-        if (item is MangaContent) {
+        if (item is MangaPage) {
             return BookCover.loadManga(
                 context,
                 item.mImageUrl,

+ 4 - 5
app/src/main/java/io/legado/app/ui/book/read/MangaMenu.kt

@@ -236,15 +236,15 @@ class MangaMenu @JvmOverloads constructor(
         tvChapterUrl.setOnLongClickListener(chapterViewLongClickListener)
 
         tvNext.setOnClickListener {
-            callBack.moveToTargetIndex(true)
+            ReadManga.moveToNextChapter(true)
         }
         tvPre.setOnClickListener {
-            callBack.moveToTargetIndex(false)
+            ReadManga.moveToPrevChapter(true)
         }
 
         seekReadPage.setOnSeekBarChangeListener(object : SeekBarChangeListener {
             override fun onStopTrackingTouch(seekBar: SeekBar) {
-                callBack.seekValue(seekBar.progress)
+                callBack.skipToPage(seekBar.progress)
             }
         })
     }
@@ -259,8 +259,7 @@ class MangaMenu @JvmOverloads constructor(
     interface CallBack {
         fun openBookInfoActivity()
         fun upSystemUiVisibility(menuIsVisible: Boolean)
-        fun moveToTargetIndex(isNext: Boolean)
-        fun seekValue(pos: Int)
+        fun skipToPage(pos: Int)
     }
 
 }