Merge branch 'gedoor:master' into master

This commit is contained in:
lff283 2024-02-22 21:56:04 +08:00 committed by GitHub
commit c18c19e252
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 121 additions and 70 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.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()
}
}

View File

@ -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

View File

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

View File

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

View File

@ -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?

View File

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

View File

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

View File

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

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 {
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())