From 952fc96574dd0af23a016047628071823cc9102d Mon Sep 17 00:00:00 2001 From: Horis <821938089@qq.com> Date: Sat, 24 Feb 2024 09:28:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/constant/PageAnim.kt | 1 + .../main/java/io/legado/app/model/ReadBook.kt | 101 +++++++++++++----- .../app/ui/book/read/ReadBookActivity.kt | 39 ------- .../ui/book/read/page/entities/TextChapter.kt | 11 +- .../read/page/provider/TextChapterLayout.kt | 43 ++++---- 5 files changed, 100 insertions(+), 95 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/PageAnim.kt b/app/src/main/java/io/legado/app/constant/PageAnim.kt index ac98ef023..ec505b455 100644 --- a/app/src/main/java/io/legado/app/constant/PageAnim.kt +++ b/app/src/main/java/io/legado/app/constant/PageAnim.kt @@ -2,6 +2,7 @@ package io.legado.app.constant import androidx.annotation.IntDef +@Suppress("ConstPropertyName") object PageAnim { const val coverPageAnim = 0 diff --git a/app/src/main/java/io/legado/app/model/ReadBook.kt b/app/src/main/java/io/legado/app/model/ReadBook.kt index 68b01eb34..4182b33b1 100644 --- a/app/src/main/java/io/legado/app/model/ReadBook.kt +++ b/app/src/main/java/io/legado/app/model/ReadBook.kt @@ -1,6 +1,7 @@ package io.legado.app.model import io.legado.app.constant.AppLog +import io.legado.app.constant.PageAnim.scrollPageAnim import io.legado.app.data.appDb import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter @@ -32,6 +33,7 @@ import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.delay import kotlinx.coroutines.launch import splitties.init.appCtx +import kotlin.math.max import kotlin.math.min @@ -241,7 +243,6 @@ object ReadBook : CoroutineScope by MainScope() { callBack?.upMenuView() AppLog.putDebug("moveToNextChapter-curPageChanged()") curPageChanged() - curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) } return true } else { AppLog.putDebug("跳转下一章失败,没有下一章") @@ -271,7 +272,6 @@ object ReadBook : CoroutineScope by MainScope() { saveRead() callBack?.upMenuView() curPageChanged() - curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) } return true } else { return false @@ -321,7 +321,7 @@ object ReadBook : CoroutineScope by MainScope() { */ private fun curPageChanged(pageChanged: Boolean = false) { callBack?.pageChanged() - if (BaseReadAloudService.isRun) { + if (BaseReadAloudService.isRun && isLayoutAvailable) { val scrollPageAnim = pageAnim() == 3 if (scrollPageAnim && pageChanged) { ReadAloud.pause(appCtx) @@ -350,6 +350,13 @@ object ReadBook : CoroutineScope by MainScope() { return curTextChapter?.getPageIndexByCharIndex(durChapterPos) ?: durChapterPos } + /** + * 是否排版到了当前阅读位置 + */ + val isLayoutAvailable inline get() = durPageIndex >= 0 + + val isScroll inline get() = pageAnim() == scrollPageAnim + /** * chapterOnDur: 0为当前页,1为下一页,-1为上一页 */ @@ -522,7 +529,8 @@ object ReadBook : CoroutineScope by MainScope() { .getContent(book, chapter, content, includeTitle = false) val textChapter = ChapterProvider.getTextChapterAsync(chapter, displayTitle, contents, chapterSize) - when (val offset = chapter.index - durChapterIndex) { + val offset = chapter.index - durChapterIndex + when (offset) { 0 -> { curTextChapter?.cancelLayout() curTextChapter = textChapter @@ -530,44 +538,83 @@ object ReadBook : CoroutineScope by MainScope() { callBack?.resetPageOffset() } callBack?.upMenuView() - curPageChanged() - callBack?.contentLoadFinish() - callBack?.onCurrentTextChapterChanged(textChapter, upContent) + textChapter.setProgressListener(object : LayoutProgressListener { + var available = false + + override fun onLayoutPageCompleted(index: Int, page: TextPage) { + if (!available && page.containPos(durChapterPos)) { + curPageChanged() + callBack?.contentLoadFinish() + if (upContent) { + callBack?.upContent(offset, resetPageOffset) + } + available = true + } + if (upContent && isScroll) { + val pageIndex = durPageIndex + if (max(index - 3, 0) < pageIndex) { + callBack?.upContent(offset, resetPageOffset) + } + } + callBack?.onLayoutPageCompleted(index, page) + } + + override fun onLayoutCompleted() { + if (upContent) callBack?.upContent(offset, resetPageOffset) + success?.invoke() + callBack?.onLayoutCompleted() + } + + override fun onLayoutException(e: Throwable) { + AppLog.put("ChapterProvider ERROR", e) + appCtx.toastOnUi("ChapterProvider ERROR:\n${e.stackTraceStr}") + callBack?.onLayoutException(e) + } + }) } -1 -> { prevTextChapter?.cancelLayout() prevTextChapter = textChapter - if (upContent) { - textChapter.setProgressListener(object : LayoutProgressListener { - override fun onLayoutCompleted() { - callBack?.upContent(offset, resetPageOffset) - } - }) - } + textChapter.setProgressListener(object : LayoutProgressListener { + override fun onLayoutCompleted() { + if (upContent) callBack?.upContent(offset, resetPageOffset) + success?.invoke() + } + + override fun onLayoutException(e: Throwable) { + AppLog.put("ChapterProvider ERROR", e) + appCtx.toastOnUi("ChapterProvider ERROR:\n${e.stackTraceStr}") + } + }) } 1 -> { nextTextChapter?.cancelLayout() nextTextChapter = textChapter - if (upContent) { - textChapter.setProgressListener(object : LayoutProgressListener { - override fun onLayoutPageCompleted(index: Int, page: TextPage) { - if (index > 1) { - return - } - callBack?.upContent(offset, resetPageOffset) + textChapter.setProgressListener(object : LayoutProgressListener { + override fun onLayoutPageCompleted(index: Int, page: TextPage) { + if (index > 1) { + return } - }) - } + if (upContent) callBack?.upContent(offset, resetPageOffset) + } + + override fun onLayoutCompleted() { + success?.invoke() + } + + override fun onLayoutException(e: Throwable) { + AppLog.put("ChapterProvider ERROR", e) + appCtx.toastOnUi("ChapterProvider ERROR:\n${e.stackTraceStr}") + } + }) } } textChapter.createLayout(this@ReadBook, book, contents) }.onError { AppLog.put("ChapterProvider ERROR", it) appCtx.toastOnUi("ChapterProvider ERROR:\n${it.stackTraceStr}") - }.onSuccess { - success?.invoke() } } @@ -679,7 +726,7 @@ object ReadBook : CoroutineScope by MainScope() { curTextChapter?.cancelLayout() } - interface CallBack { + interface CallBack : LayoutProgressListener { fun upMenuView() fun loadChapterList(book: Book) @@ -698,8 +745,6 @@ object ReadBook : CoroutineScope by MainScope() { fun notifyBookChanged() - fun onCurrentTextChapterChanged(textChapter: TextChapter, upContent: Boolean = true) - fun resetPageOffset() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index e84901a42..1be4a9460 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -77,7 +77,6 @@ import io.legado.app.ui.book.read.config.TipConfigDialog.Companion.TIP_DIVIDER_C import io.legado.app.ui.book.read.page.ContentTextView import io.legado.app.ui.book.read.page.ReadView import io.legado.app.ui.book.read.page.entities.PageDirection -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 @@ -115,7 +114,6 @@ import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEventSticky import io.legado.app.utils.postEvent import io.legado.app.utils.showDialogFragment -import io.legado.app.utils.stackTraceStr import io.legado.app.utils.startActivity import io.legado.app.utils.sysScreenOffTime import io.legado.app.utils.throttle @@ -126,7 +124,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlin.math.max /** * 阅读界面 @@ -1373,47 +1370,11 @@ class ReadBookActivity : BaseReadBookActivity(), binding.readView.autoPager.resume() } - 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() - } - - override fun onLayoutException(e: Throwable) { - AppLog.put("ChapterProvider ERROR", e) - toastOnUi("ChapterProvider ERROR:\n${e.stackTraceStr}") - binding.readView.onLayoutException(e) - } - override fun resetPageOffset() { binding.readView.resetPageOffset() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt index e309c33dd..b01ecebe3 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt @@ -96,8 +96,7 @@ data class TextChapter( } fun isLastIndexCurrent(index: Int): Boolean { - // 未完成排版时,最后一页是正在排版中的,需要去掉 - return index >= if (isCompleted) pages.size - 1 else pages.size - 2 + return index >= pages.size - 1 } /** @@ -212,16 +211,12 @@ data class TextChapter( if (pageSize == 0) { return -1 } - val size = if (isCompleted) pageSize else pageSize - 1 - val bIndex = pages.fastBinarySearchBy(charIndex, 0, size) { + val bIndex = pages.fastBinarySearchBy(charIndex, 0, pageSize) { it.lines.first().chapterPosition } val index = abs(bIndex + 1) - 1 - if (index == -1) { - return -1 - } // 判断是否已经排版到 charIndex ,没有则返回 -1 - if (!isCompleted && index == size - 1) { + if (!isCompleted && index == pageSize - 1) { val page = pages[index] val line = page.lines.first() val pageEndPos = line.chapterPosition + page.charSize diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt index 0cb676946..d8a868b85 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt @@ -67,6 +67,8 @@ class TextChapterLayout( private val indentCharWidth = ChapterProvider.indentCharWidth private val stringBuilder = StringBuilder() + private var pendingTextPage = TextPage() + private var isCompleted = false private val job: Coroutine<*> private val bookChapter inline get() = textChapter.chapter @@ -167,7 +169,6 @@ class TextChapterLayout( val contents = bookContent.textList var absStartX = paddingLeft var durY = 0f - textPages.add(TextPage()) if (ReadBookConfig.titleMode != 2 || bookChapter.isVolume) { //标题非隐藏 displayTitle.splitNotBlank("\n").forEach { text -> @@ -185,7 +186,7 @@ class TextChapterLayout( durY = it.second } } - textPages.last().lines.last().isParagraphEnd = true + pendingTextPage.lines.last().isParagraphEnd = true stringBuilder.append("\n") durY += titleBottomSpacing } @@ -244,7 +245,6 @@ class TextChapterLayout( matcher.group(1)!!, absStartX, durY, - textPages, contentPaintTextHeight, stringBuilder, book.getImageStyle() @@ -270,10 +270,11 @@ class TextChapterLayout( } } } - textPages.last().lines.last().isParagraphEnd = true + pendingTextPage.lines.last().isParagraphEnd = true stringBuilder.append("\n") } - val textPage = textPages.last() + textPages.add(pendingTextPage) + val textPage = pendingTextPage val endPadding = 20.dpToPx() val durYPadding = durY + endPadding if (textPage.height < durYPadding) { @@ -295,7 +296,6 @@ class TextChapterLayout( src: String, x: Int, y: Float, - textPages: ArrayList, textHeight: Float, stringBuilder: StringBuilder, imageStyle: String?, @@ -305,15 +305,16 @@ class TextChapterLayout( val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource) if (size.width > 0 && size.height > 0) { if (durY > visibleHeight) { - val textPage = textPages.last() + val textPage = pendingTextPage if (textPage.height < durY) { textPage.height = durY } textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" } stringBuilder.clear() + textPages.add(textPage) coroutineContext.ensureActive() onPageCompleted() - textPages.add(TextPage()) + pendingTextPage = TextPage() durY = 0f } var height = size.height @@ -334,7 +335,7 @@ class TextChapterLayout( height = visibleHeight } if (durY + height > visibleHeight) { - val textPage = textPages.last() + val textPage = pendingTextPage if (doublePage && absStartX < viewWidth / 2) { //当前页面左列结束 textPage.leftLineSize = textPage.lineSize @@ -346,9 +347,10 @@ class TextChapterLayout( } textPage.text = stringBuilder.toString().ifEmpty { "本页无文字内容" } stringBuilder.clear() + textPages.add(textPage) coroutineContext.ensureActive() onPageCompleted() - textPages.add(TextPage()) + pendingTextPage = TextPage() } // 双页的 durY 不正确,可能会小于实际高度 if (textPage.height < durY) { @@ -373,7 +375,7 @@ class TextChapterLayout( ) calcTextLinePosition(textPages, textLine, stringBuilder.length) stringBuilder.append(" ") // 确保翻页时索引计算正确 - textPages.last().addLine(textLine) + pendingTextPage.addLine(textLine) } return absStartX to durY + textHeight * paragraphSpacing / 10f } @@ -403,8 +405,8 @@ class TextChapterLayout( } var durY = when { //标题y轴居中 - emptyContent && textPages.size == 1 -> { - val textPage = textPages.last() + emptyContent && textPages.isEmpty() -> { + val textPage = pendingTextPage if (textPage.lineSize == 0) { val ty = (visibleHeight - layout.lineCount * textHeight) / 2 if (ty > titleTopSpacing) ty else titleTopSpacing.toFloat() @@ -423,7 +425,7 @@ class TextChapterLayout( } } - isTitle && textPages.size == 1 && textPages.last().lines.isEmpty() -> + isTitle && textPages.isEmpty() && pendingTextPage.lines.isEmpty() -> y + titleTopSpacing else -> y @@ -431,7 +433,7 @@ class TextChapterLayout( for (lineIndex in 0 until layout.lineCount) { val textLine = TextLine(isTitle = isTitle) if (durY + textHeight > visibleHeight) { - val textPage = textPages.last() + val textPage = pendingTextPage if (doublePage && absStartX < viewWidth / 2) { //当前页面左列结束 textPage.leftLineSize = textPage.lineSize @@ -442,10 +444,11 @@ class TextChapterLayout( textPage.leftLineSize = textPage.lineSize } textPage.text = stringBuilder.toString() + textPages.add(textPage) coroutineContext.ensureActive() onPageCompleted() //新建页面 - textPages.add(TextPage()) + pendingTextPage = TextPage() stringBuilder.clear() absStartX = paddingLeft } @@ -514,7 +517,7 @@ class TextChapterLayout( calcTextLinePosition(textPages, textLine, stringBuilder.length) stringBuilder.append(lineText) textLine.upTopBottom(durY, textHeight, fontMetrics) - val textPage = textPages.last() + val textPage = pendingTextPage textPage.addLine(textLine) durY += textHeight * lineSpacingExtra if (textPage.height < durY) { @@ -530,8 +533,8 @@ class TextChapterLayout( textLine: TextLine, sbLength: Int ) { - val lastLine = textPages.last().lines.lastOrNull { it.paragraphNum > 0 } - ?: textPages.getOrNull(textPages.lastIndex - 1)?.lines?.lastOrNull { it.paragraphNum > 0 } + val lastLine = pendingTextPage.lines.lastOrNull { it.paragraphNum > 0 } + ?: textPages.lastOrNull()?.lines?.lastOrNull { it.paragraphNum > 0 } val paragraphNum = when { lastLine == null -> 1 lastLine.isParagraphEnd -> lastLine.paragraphNum + 1 @@ -539,7 +542,7 @@ class TextChapterLayout( } textLine.paragraphNum = paragraphNum textLine.chapterPosition = - (textPages.getOrNull(textPages.lastIndex - 1)?.lines?.lastOrNull()?.run { + (textPages.lastOrNull()?.lines?.lastOrNull()?.run { chapterPosition + charSize + if (isParagraphEnd) 1 else 0 } ?: 0) + sbLength textLine.pagePosition = sbLength