mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
Merge branch 'gedoor:master' into master
This commit is contained in:
commit
c18c19e252
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)?) {
|
||||
|
@ -288,6 +288,10 @@ class PageView(context: Context) : FrameLayout(context) {
|
||||
binding.contentTextView.setContent(textPage)
|
||||
}
|
||||
|
||||
fun invalidateContentView() {
|
||||
binding.contentTextView.invalidate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置无障碍文本
|
||||
*/
|
||||
|
@ -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?
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {}
|
||||
|
||||
}
|
||||
|
@ -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())
|
||||
|
Loading…
Reference in New Issue
Block a user