Просмотр исходного кода

Merge branch 'gedoor:master' into master

lff283 2 лет назад
Родитель
Сommit
871f383b37

+ 46 - 18
app/src/main/java/io/legado/app/model/ReadBook.kt

@@ -19,7 +19,9 @@ import io.legado.app.model.localBook.TextFile
 import io.legado.app.model.webBook.WebBook
 import io.legado.app.service.BaseReadAloudService
 import io.legado.app.ui.book.read.page.entities.TextChapter
+import io.legado.app.ui.book.read.page.entities.TextPage
 import io.legado.app.ui.book.read.page.provider.ChapterProvider
+import io.legado.app.ui.book.read.page.provider.LayoutProgressListener
 import io.legado.app.utils.stackTraceStr
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.CoroutineScope
@@ -230,7 +232,7 @@ object ReadBook : CoroutineScope by MainScope() {
             callBack?.upMenuView()
             AppLog.putDebug("moveToNextChapter-curPageChanged()")
             curPageChanged()
-            curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it) }
+            curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) }
             return true
         } else {
             AppLog.putDebug("跳转下一章失败,没有下一章")
@@ -260,7 +262,7 @@ object ReadBook : CoroutineScope by MainScope() {
             saveRead()
             callBack?.upMenuView()
             curPageChanged()
-            curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it) }
+            curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) }
             return true
         } else {
             return false
@@ -292,14 +294,27 @@ object ReadBook : CoroutineScope by MainScope() {
         curPageChanged(true)
     }
 
+    fun openChapter(index: Int, durChapterPos: Int = 0, success: (() -> Unit)? = null) {
+        if (index < chapterSize) {
+            clearTextChapter()
+            callBack?.upContent()
+            durChapterIndex = index
+            ReadBook.durChapterPos = durChapterPos
+            saveRead()
+            loadContent(resetPageOffset = true) {
+                success?.invoke()
+            }
+        }
+    }
+
     /**
      * 当前页面变化
      */
-    private fun curPageChanged(pauseReadAloud: Boolean = false) {
+    private fun curPageChanged(pageChanged: Boolean = false) {
         callBack?.pageChanged()
         if (BaseReadAloudService.isRun) {
             val scrollPageAnim = pageAnim() == 3
-            if (scrollPageAnim && pauseReadAloud) {
+            if (scrollPageAnim && pageChanged) {
                 ReadAloud.pause(appCtx)
             } else {
                 readAloud(!BaseReadAloudService.pause)
@@ -484,38 +499,49 @@ object ReadBook : CoroutineScope by MainScope() {
             )
             val contents = contentProcessor
                 .getContent(book, chapter, content, includeTitle = false)
-            val textChapter = ChapterProvider.getTextChapterAsync(
-                book,
-                chapter,
-                displayTitle,
-                contents,
-                chapterSize,
-                this@ReadBook
-            )
+            val textChapter =
+                ChapterProvider.getTextChapterAsync(chapter, displayTitle, contents, chapterSize)
             when (val offset = chapter.index - durChapterIndex) {
                 0 -> {
                     curTextChapter?.cancelLayout()
                     curTextChapter = textChapter
-                    if (upContent) callBack?.upContent(offset, resetPageOffset)
+                    if (resetPageOffset) {
+                        callBack?.resetPageOffset()
+                    }
                     callBack?.upMenuView()
                     curPageChanged()
                     callBack?.contentLoadFinish()
-                    callBack?.onCurrentTextChapterChanged(textChapter)
+                    callBack?.onCurrentTextChapterChanged(textChapter, upContent)
                 }
 
                 -1 -> {
                     prevTextChapter?.cancelLayout()
                     prevTextChapter = textChapter
-                    if (upContent) callBack?.upContent(offset, resetPageOffset)
+                    if (upContent) {
+                        textChapter.setProgressListener(object : LayoutProgressListener {
+                            override fun onLayoutCompleted() {
+                                callBack?.upContent(offset, resetPageOffset)
+                            }
+                        })
+                    }
                 }
 
                 1 -> {
                     nextTextChapter?.cancelLayout()
                     nextTextChapter = textChapter
-                    if (upContent) callBack?.upContent(offset, resetPageOffset)
+                    if (upContent) {
+                        textChapter.setProgressListener(object : LayoutProgressListener {
+                            override fun onLayoutPageCompleted(index: Int, page: TextPage) {
+                                if (index > 1) {
+                                    return
+                                }
+                                callBack?.upContent(offset, resetPageOffset)
+                            }
+                        })
+                    }
                 }
             }
-            Unit
+            textChapter.createLayout(this@ReadBook, book, contents)
         }.onError {
             AppLog.put("ChapterProvider ERROR", it)
             appCtx.toastOnUi("ChapterProvider ERROR:\n${it.stackTraceStr}")
@@ -650,7 +676,9 @@ object ReadBook : CoroutineScope by MainScope() {
 
         fun notifyBookChanged()
 
-        fun onCurrentTextChapterChanged(textChapter: TextChapter)
+        fun onCurrentTextChapterChanged(textChapter: TextChapter, upContent: Boolean = true)
+
+        fun resetPageOffset()
     }
 
 }

+ 32 - 2
app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@@ -126,6 +126,7 @@ import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import kotlin.math.max
 
 /**
  * 阅读界面
@@ -233,6 +234,7 @@ class ReadBookActivity : BaseReadBookActivity(),
             binding.readMenu.upSeekBar()
         }
     }
+    private var upContent = true
 
     //恢复跳转前进度对话框的交互结果
     private var confirmRestoreProcess: Boolean? = null
@@ -936,7 +938,9 @@ class ReadBookActivity : BaseReadBookActivity(),
     ) {
         lifecycleScope.launch {
             binding.readView.upContent(relativePosition, resetPageOffset)
-            upSeekBarProgress()
+            if (relativePosition == 0) {
+                upSeekBarProgress()
+            }
             loadStates = false
             success?.invoke()
         }
@@ -1369,16 +1373,38 @@ class ReadBookActivity : BaseReadBookActivity(),
         binding.readView.autoPager.resume()
     }
 
-    override fun onCurrentTextChapterChanged(textChapter: TextChapter) {
+    override fun onCurrentTextChapterChanged(textChapter: TextChapter, upContent: Boolean) {
+        this.upContent = upContent
         textChapter.setProgressListener(this)
     }
 
     override fun onLayoutPageCompleted(index: Int, page: TextPage) {
         upSeekBarThrottle.invoke()
+        if (upContent) {
+            val durChapterPos = ReadBook.durChapterPos
+            if (page.containPos(durChapterPos)) {
+                runOnUiThread {
+                    binding.readView.upContent(0, resetPageOffset = false)
+                }
+            }
+            if (isScroll) {
+                val pageIndex = ReadBook.durPageIndex
+                if (max(index - 3, 0) < pageIndex) {
+                    runOnUiThread {
+                        binding.readView.upContent(0, resetPageOffset = false)
+                    }
+                }
+            }
+        }
         binding.readView.onLayoutPageCompleted(index, page)
     }
 
     override fun onLayoutCompleted() {
+        if (upContent) {
+            runOnUiThread {
+                binding.readView.upContent(0, resetPageOffset = false)
+            }
+        }
         binding.readView.onLayoutCompleted()
     }
 
@@ -1388,6 +1414,10 @@ class ReadBookActivity : BaseReadBookActivity(),
         binding.readView.onLayoutException(e)
     }
 
+    override fun resetPageOffset() {
+        binding.readView.resetPageOffset()
+    }
+
     /* 全文搜索跳转 */
     private fun skipToSearch(searchResult: SearchResult) {
         val previousResult = binding.searchMenu.previousSearchResult

+ 1 - 10
app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt

@@ -317,16 +317,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
     }
 
     fun openChapter(index: Int, durChapterPos: Int = 0, success: (() -> Unit)? = null) {
-        if (index < ReadBook.chapterSize) {
-            ReadBook.clearTextChapter()
-            ReadBook.callBack?.upContent()
-            ReadBook.durChapterIndex = index
-            ReadBook.durChapterPos = durChapterPos
-            ReadBook.saveRead()
-            ReadBook.loadContent(resetPageOffset = true) {
-                success?.invoke()
-            }
-        }
+        ReadBook.openChapter(index, durChapterPos, success)
     }
 
     fun removeFromBookshelf(success: (() -> Unit)?) {

+ 4 - 0
app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt

@@ -288,6 +288,10 @@ class PageView(context: Context) : FrameLayout(context) {
         binding.contentTextView.setContent(textPage)
     }
 
+    fun invalidateContentView() {
+        binding.contentTextView.invalidate()
+    }
+
     /**
      * 设置无障碍文本
      */

+ 7 - 26
app/src/main/java/io/legado/app/ui/book/read/page/ReadView.kt

@@ -527,7 +527,11 @@ class ReadView(context: Context, attrs: AttributeSet) :
             curPage.setContentDescription(pageFactory.curPage.text)
         }
         if (isScroll && !isAutoPage) {
-            curPage.setContent(pageFactory.curPage, resetPageOffset)
+            if (relativePosition == 0) {
+                curPage.setContent(pageFactory.curPage, resetPageOffset)
+            } else {
+                curPage.invalidateContentView()
+            }
         } else {
             when (relativePosition) {
                 -1 -> prevPage.setContent(pageFactory.prevPage)
@@ -662,34 +666,11 @@ class ReadView(context: Context, attrs: AttributeSet) :
     }
 
     override fun onLayoutPageCompleted(index: Int, page: TextPage) {
-        val line = page.lines.first()
-        val durChapterPos = ReadBook.durChapterPos
-        val startPos = line.chapterPosition
-        val endPos = startPos + line.charSize
-        if (durChapterPos in startPos..<endPos) {
-            post {
-                upContent(resetPageOffset = false)
-            }
-        }
-        if (isScroll) {
-            val pageIndex = ReadBook.durPageIndex
-            if (index - 3 < pageIndex) {
-                post {
-                    upContent(resetPageOffset = false)
-                }
-            }
-        }
         upProgressThrottle.invoke()
     }
 
-    override fun onLayoutCompleted() {
-        post {
-            upContent(resetPageOffset = false)
-        }
-    }
-
-    override fun onLayoutException(e: Throwable) {
-        // no op
+    fun resetPageOffset() {
+        curPage.resetPageOffset()
     }
 
     override val currentChapter: TextChapter?

+ 5 - 2
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt

@@ -266,11 +266,11 @@ data class TextChapter(
         )
     }
 
-    fun setProgressListener(l: LayoutProgressListener) {
+    fun setProgressListener(l: LayoutProgressListener?) {
         if (isCompleted) {
             // no op
         } else if (layout?.exception != null) {
-            l.onLayoutException(layout?.exception!!)
+            l?.onLayoutException(layout?.exception!!)
         } else {
             listener = l
         }
@@ -287,12 +287,15 @@ data class TextChapter(
     }
 
     override fun onLayoutException(e: Throwable) {
+        isCompleted = true
         listener?.onLayoutException(e)
         listener = null
     }
 
     fun cancelLayout() {
         layout?.cancel()
+        isCompleted = true
+        listener = null
     }
 
     companion object {

+ 14 - 0
app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt

@@ -47,6 +47,7 @@ data class TextPage(
     var doublePage = false
     var paddingTop = 0
     var isCompleted = false
+
     @JvmField
     var textChapter = emptyTextChapter
     val pageSize get() = textChapter.pageSize
@@ -256,6 +257,19 @@ data class TextPage(
         return textChapter
     }
 
+    /**
+     * 判断章节字符位置是否在这一页中
+     *
+     * @param chapterPos 章节字符位置
+     * @return
+     */
+    fun containPos(chapterPos: Int): Boolean {
+        val line = lines.first()
+        val startPos = line.chapterPosition
+        val endPos = startPos + charSize
+        return chapterPos in startPos..<endPos
+    }
+
     fun draw(view: ContentTextView, canvas: Canvas, relativeOffset: Float) {
         render(view)
         canvas.withTranslation(0f, relativeOffset + paddingTop) {

+ 1 - 6
app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt

@@ -32,7 +32,6 @@ import io.legado.app.utils.postEvent
 import io.legado.app.utils.spToPx
 import io.legado.app.utils.splitNotBlank
 import io.legado.app.utils.textHeight
-import kotlinx.coroutines.CoroutineScope
 import splitties.init.appCtx
 import java.util.LinkedList
 import java.util.Locale
@@ -307,12 +306,10 @@ object ChapterProvider {
     }
 
     fun getTextChapterAsync(
-        book: Book,
         bookChapter: BookChapter,
         displayTitle: String,
         bookContent: BookContent,
         chapterSize: Int,
-        scope: CoroutineScope
     ): TextChapter {
 
         val textChapter = TextChapter(
@@ -323,9 +320,7 @@ object ChapterProvider {
             bookChapter.isVip,
             bookChapter.isPay,
             bookContent.effectiveReplaceRules
-        ).apply {
-            createLayout(scope, book, bookContent)
-        }
+        )
 
         return textChapter
     }

+ 3 - 3
app/src/main/java/io/legado/app/ui/book/read/page/provider/LayoutProgressListener.kt

@@ -7,16 +7,16 @@ interface LayoutProgressListener {
     /**
      * 单页排版完成
      */
-    fun onLayoutPageCompleted(index: Int, page: TextPage)
+    fun onLayoutPageCompleted(index: Int, page: TextPage) {}
 
     /**
      * 全部排版完成
      */
-    fun onLayoutCompleted()
+    fun onLayoutCompleted() {}
 
     /**
      * 排版出现异常
      */
-    fun onLayoutException(e: Throwable)
+    fun onLayoutException(e: Throwable) {}
 
 }

+ 8 - 3
app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt

@@ -90,12 +90,12 @@ class TextChapterLayout(
         }
     }
 
-    fun setProgressListener(l: LayoutProgressListener) {
+    fun setProgressListener(l: LayoutProgressListener?) {
         try {
             if (isCompleted) {
                 // no op
             } else if (exception != null) {
-                l.onLayoutException(exception!!)
+                l?.onLayoutException(exception!!)
             } else {
                 listener = l
             }
@@ -107,6 +107,7 @@ class TextChapterLayout(
 
     fun cancel() {
         job.cancel()
+        listener = null
     }
 
     private fun onPageCompleted() {
@@ -141,6 +142,7 @@ class TextChapterLayout(
 
     private fun onException(e: Throwable) {
         if (e is CancellationException) {
+            listener = null
             return
         }
         try {
@@ -280,6 +282,7 @@ class TextChapterLayout(
             textPage.height += endPadding
         }
         textPage.text = stringBuilder.toString()
+        coroutineContext.ensureActive()
         onPageCompleted()
         onCompleted()
     }
@@ -308,6 +311,7 @@ class TextChapterLayout(
                 }
                 textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
                 stringBuilder.clear()
+                coroutineContext.ensureActive()
                 onPageCompleted()
                 textPages.add(TextPage())
                 durY = 0f
@@ -342,6 +346,7 @@ class TextChapterLayout(
                             }
                             textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" }
                             stringBuilder.clear()
+                            coroutineContext.ensureActive()
                             onPageCompleted()
                             textPages.add(TextPage())
                         }
@@ -424,7 +429,6 @@ class TextChapterLayout(
             else -> y
         }
         for (lineIndex in 0 until layout.lineCount) {
-            coroutineContext.ensureActive()
             val textLine = TextLine(isTitle = isTitle)
             if (durY + textHeight > visibleHeight) {
                 val textPage = textPages.last()
@@ -438,6 +442,7 @@ class TextChapterLayout(
                         textPage.leftLineSize = textPage.lineSize
                     }
                     textPage.text = stringBuilder.toString()
+                    coroutineContext.ensureActive()
                     onPageCompleted()
                     //新建页面
                     textPages.add(TextPage())