This commit is contained in:
Horis 2024-02-22 12:35:48 +08:00
parent d32f1f37ca
commit ea47a24737
6 changed files with 92 additions and 42 deletions

View File

@ -19,7 +19,9 @@ import io.legado.app.model.localBook.TextFile
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.BaseReadAloudService 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.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.ChapterProvider
import io.legado.app.ui.book.read.page.provider.LayoutProgressListener
import io.legado.app.utils.stackTraceStr import io.legado.app.utils.stackTraceStr
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -214,6 +216,7 @@ object ReadBook : CoroutineScope by MainScope() {
durChapterPos = 0 durChapterPos = 0
durChapterIndex++ durChapterIndex++
prevTextChapter?.cancelLayout() prevTextChapter?.cancelLayout()
curTextChapter?.setProgressListener(null)
prevTextChapter = curTextChapter prevTextChapter = curTextChapter
curTextChapter = nextTextChapter curTextChapter = nextTextChapter
nextTextChapter = null nextTextChapter = null
@ -230,7 +233,7 @@ object ReadBook : CoroutineScope by MainScope() {
callBack?.upMenuView() callBack?.upMenuView()
AppLog.putDebug("moveToNextChapter-curPageChanged()") AppLog.putDebug("moveToNextChapter-curPageChanged()")
curPageChanged() curPageChanged()
curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it) } curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) }
return true return true
} else { } else {
AppLog.putDebug("跳转下一章失败,没有下一章") AppLog.putDebug("跳转下一章失败,没有下一章")
@ -247,6 +250,7 @@ object ReadBook : CoroutineScope by MainScope() {
durChapterPos = if (toLast) prevTextChapter?.lastReadLength ?: Int.MAX_VALUE else 0 durChapterPos = if (toLast) prevTextChapter?.lastReadLength ?: Int.MAX_VALUE else 0
durChapterIndex-- durChapterIndex--
nextTextChapter?.cancelLayout() nextTextChapter?.cancelLayout()
curTextChapter?.setProgressListener(null)
nextTextChapter = curTextChapter nextTextChapter = curTextChapter
curTextChapter = prevTextChapter curTextChapter = prevTextChapter
prevTextChapter = null prevTextChapter = null
@ -260,7 +264,7 @@ object ReadBook : CoroutineScope by MainScope() {
saveRead() saveRead()
callBack?.upMenuView() callBack?.upMenuView()
curPageChanged() curPageChanged()
curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it) } curTextChapter?.let { callBack?.onCurrentTextChapterChanged(it, upContent) }
return true return true
} else { } else {
return false return false
@ -495,24 +499,52 @@ object ReadBook : CoroutineScope by MainScope() {
when (val offset = chapter.index - durChapterIndex) { when (val offset = chapter.index - durChapterIndex) {
0 -> { 0 -> {
curTextChapter?.cancelLayout() curTextChapter?.cancelLayout()
curTextChapter?.setProgressListener(null)
curTextChapter = textChapter curTextChapter = textChapter
if (upContent) callBack?.upContent(offset, resetPageOffset) if (textChapter.isCompleted) {
if (upContent) callBack?.upContent(offset, resetPageOffset)
} else if (resetPageOffset) {
callBack?.resetPageOffset()
}
callBack?.upMenuView() callBack?.upMenuView()
curPageChanged() curPageChanged()
callBack?.contentLoadFinish() callBack?.contentLoadFinish()
callBack?.onCurrentTextChapterChanged(textChapter) callBack?.onCurrentTextChapterChanged(textChapter, upContent)
} }
-1 -> { -1 -> {
prevTextChapter?.cancelLayout() prevTextChapter?.cancelLayout()
prevTextChapter = textChapter prevTextChapter = textChapter
if (upContent) callBack?.upContent(offset, resetPageOffset) if (upContent) {
if (textChapter.isCompleted) {
callBack?.upContent(offset, resetPageOffset)
} else {
textChapter.setProgressListener(object : LayoutProgressListener {
override fun onLayoutCompleted() {
callBack?.upContent(offset, resetPageOffset)
}
})
}
}
} }
1 -> { 1 -> {
nextTextChapter?.cancelLayout() nextTextChapter?.cancelLayout()
nextTextChapter = textChapter nextTextChapter = textChapter
if (upContent) callBack?.upContent(offset, resetPageOffset) if (upContent) {
if (textChapter.isCompleted) {
callBack?.upContent(offset, resetPageOffset)
} else {
textChapter.setProgressListener(object : LayoutProgressListener {
override fun onLayoutPageCompleted(index: Int, page: TextPage) {
if (index > 1) {
return
}
callBack?.upContent(offset, resetPageOffset)
}
})
}
}
} }
} }
Unit Unit
@ -650,7 +682,9 @@ object ReadBook : CoroutineScope by MainScope() {
fun notifyBookChanged() fun notifyBookChanged()
fun onCurrentTextChapterChanged(textChapter: TextChapter) fun onCurrentTextChapterChanged(textChapter: TextChapter, upContent: Boolean = true)
fun resetPageOffset()
} }
} }

View File

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

View File

@ -662,34 +662,11 @@ class ReadView(context: Context, attrs: AttributeSet) :
} }
override fun onLayoutPageCompleted(index: Int, page: TextPage) { 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() upProgressThrottle.invoke()
} }
override fun onLayoutCompleted() { fun resetPageOffset() {
post { curPage.resetPageOffset()
upContent(resetPageOffset = false)
}
}
override fun onLayoutException(e: Throwable) {
// no op
} }
override val currentChapter: TextChapter? override val currentChapter: TextChapter?

View File

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

View File

@ -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) {}
} }

View File

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