diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 2aa416e4b..f6f2d335c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -384,7 +384,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { // calculate search result's lineIndex val currentPage = pages[pageIndex] - val curTextLines = currentPage.textLines + val curTextLines = currentPage.lines var lineIndex = 0 var curLine = curTextLines[lineIndex] length = length - currentPage.text.length + curLine.text.length @@ -397,7 +397,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } // charIndex - val currentLine = currentPage.textLines[lineIndex] + val currentLine = currentPage.lines[lineIndex] var curLineLength = currentLine.text.length if (currentLine.isParagraphEnd) curLineLength++ length -= curLineLength @@ -411,7 +411,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { charIndex2 = charIndex + queryLength - curLineLength - 1 } // changePage - if ((lineIndex + addLine + 1) > currentPage.textLines.size) { + if ((lineIndex + addLine + 1) > currentPage.lines.size) { addLine = -1 charIndex2 = charIndex + queryLength - curLineLength - 1 } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt index 20b94dcfd..ea9c097c1 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt @@ -16,7 +16,10 @@ import io.legado.app.help.config.AppConfig import io.legado.app.help.config.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.model.ReadBook -import io.legado.app.ui.book.read.page.entities.* +import io.legado.app.ui.book.read.page.entities.TextColumn +import io.legado.app.ui.book.read.page.entities.TextLine +import io.legado.app.ui.book.read.page.entities.TextPage +import io.legado.app.ui.book.read.page.entities.TextPos import io.legado.app.ui.book.read.page.provider.ChapterProvider import io.legado.app.ui.book.read.page.provider.ImageProvider import io.legado.app.ui.book.read.page.provider.TextPageFactory @@ -105,7 +108,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at */ private fun drawPage(canvas: Canvas) { var relativeOffset = relativeOffset(0) - textPage.textLines.forEach { textLine -> + textPage.lines.forEach { textLine -> draw(canvas, textPage, textLine, relativeOffset) } if (!callBack.isScroll) return @@ -113,14 +116,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at if (!pageFactory.hasNext()) return val textPage1 = relativePage(1) relativeOffset = relativeOffset(1) - textPage1.textLines.forEach { textLine -> + textPage1.lines.forEach { textLine -> draw(canvas, textPage1, textLine, relativeOffset) } if (!pageFactory.hasNextPlus()) return relativeOffset = relativeOffset(2) if (relativeOffset < ChapterProvider.visibleHeight) { val textPage2 = relativePage(2) - textPage2.textLines.forEach { textLine -> + textPage2.lines.forEach { textLine -> draw(canvas, textPage2, textLine, relativeOffset) } } @@ -164,7 +167,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at val reviewCountPaint = TextPaint() reviewCountPaint.textSize = textPaint.textSize * 0.6F reviewCountPaint.color = textColor - textLine.textColumns.forEach { + textLine.columns.forEach { when (it.style) { 0 -> { textPaint.color = textColor @@ -460,9 +463,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at if (relativeOffset >= ChapterProvider.visibleHeight) return } val textPage = relativePage(relativePos) - for ((lineIndex, textLine) in textPage.textLines.withIndex()) { + for ((lineIndex, textLine) in textPage.lines.withIndex()) { if (textLine.isTouch(x, y, relativeOffset)) { - for ((charIndex, textColumn) in textLine.textColumns.withIndex()) { + for ((charIndex, textColumn) in textLine.columns.withIndex()) { if (textColumn.isTouch(x)) { touched.invoke( relativeOffset, @@ -486,7 +489,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectStart.lineIndex = lineIndex selectStart.charIndex = charIndex val textLine = relativePage(relativePagePos).getLine(lineIndex) - val textColumn = textLine.getTextColumn(charIndex) + val textColumn = textLine.getColumn(charIndex) upSelectedStart( textColumn.start, textLine.lineBottom + relativeOffset(relativePagePos), @@ -503,7 +506,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectEnd.lineIndex = lineIndex selectEnd.charIndex = charIndex val textLine = relativePage(relativePage).getLine(lineIndex) - val textColumn = textLine.getTextColumn(charIndex) + val textColumn = textLine.getColumn(charIndex) upSelectedEnd(textColumn.end, textLine.lineBottom + relativeOffset(relativePage)) upSelectChars() } @@ -513,14 +516,15 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at val textPos = TextPos(0, 0, 0) for (relativePos in 0..last) { textPos.relativePagePos = relativePos - for ((lineIndex, textLine) in relativePage(relativePos).textLines.withIndex()) { + for ((lineIndex, textLine) in relativePage(relativePos).lines.withIndex()) { textPos.lineIndex = lineIndex - for ((charIndex, textColumn) in textLine.textColumns.withIndex()) { + for ((charIndex, textColumn) in textLine.columns.withIndex()) { textPos.charIndex = charIndex if (textColumn.style == 2) continue textColumn.selected = textPos.compare(selectStart) >= 0 && textPos.compare(selectEnd) <= 0 - textColumn.isSearchResult = textColumn.selected && callBack.isSelectingSearchResult + textColumn.isSearchResult = + textColumn.selected && callBack.isSelectingSearchResult } } } @@ -538,8 +542,8 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at fun cancelSelect(fromSearchExit: Boolean = false) { val last = if (callBack.isScroll) 2 else 0 for (relativePos in 0..last) { - relativePage(relativePos).textLines.forEach { textLine -> - textLine.textColumns.forEach { + relativePage(relativePos).lines.forEach { textLine -> + textLine.columns.forEach { it.selected = false if (fromSearchExit) it.isSearchResult = false } @@ -555,9 +559,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at for (relativePos in selectStart.relativePagePos..selectEnd.relativePagePos) { val textPage = relativePage(relativePos) textPos.relativePagePos = relativePos - textPage.textLines.forEachIndexed { lineIndex, textLine -> + textPage.lines.forEachIndexed { lineIndex, textLine -> textPos.lineIndex = lineIndex - textLine.textColumns.forEachIndexed { charIndex, textColumn -> + textLine.columns.forEachIndexed { charIndex, textColumn -> textPos.charIndex = charIndex val compareStart = textPos.compare(selectStart) val compareEnd = textPos.compare(selectEnd) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt index 5dd38d5cf..f9040423f 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt @@ -10,7 +10,7 @@ import io.legado.app.utils.textHeight @Suppress("unused", "MemberVisibilityCanBePrivate") data class TextLine( var text: String = "", - val textColumns: ArrayList = arrayListOf(), + private val textColumns: ArrayList = arrayListOf(), val reviewCount: Int = 0, var lineTop: Float = 0f, var lineBase: Float = 0f, @@ -21,30 +21,35 @@ data class TextLine( var isImage: Boolean = false ) { + val columns: List get() = textColumns val charSize: Int get() = textColumns.size val lineStart: Float get() = textColumns.firstOrNull()?.start ?: 0f val lineEnd: Float get() = textColumns.lastOrNull()?.end ?: 0f - fun upTopBottom(durY: Float, textPaint: TextPaint) { - lineTop = ChapterProvider.paddingTop + durY - lineBottom = lineTop + textPaint.textHeight - lineBase = lineBottom - textPaint.fontMetrics.descent + fun addColumn(column: TextColumn) { + textColumns.add(column) } - fun getTextColumn(index: Int): TextColumn { + fun getColumn(index: Int): TextColumn { return textColumns.getOrElse(index) { textColumns.last() } } - fun getTextColumnReverseAt(index: Int): TextColumn { + fun getColumnReverseAt(index: Int): TextColumn { return textColumns[textColumns.lastIndex - index] } - fun getTextColumnsCount(): Int { + fun getColumnsCount(): Int { return textColumns.size } + fun upTopBottom(durY: Float, textPaint: TextPaint) { + lineTop = ChapterProvider.paddingTop + durY + lineBottom = lineTop + textPaint.textHeight + lineBase = lineBottom - textPaint.fontMetrics.descent + } + fun isTouch(x: Float, y: Float, relativeOffset: Float): Boolean { return y > lineTop + relativeOffset && y < lineBottom + relativeOffset diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt index 254deee54..b5ee422ca 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt @@ -19,7 +19,7 @@ data class TextPage( var index: Int = 0, var text: String = appCtx.getString(R.string.data_loading), var title: String = "", - val textLines: ArrayList = arrayListOf(), + private val textLines: ArrayList = arrayListOf(), var pageSize: Int = 0, var chapterSize: Int = 0, var chapterIndex: Int = 0, @@ -27,10 +27,15 @@ data class TextPage( var leftLineSize: Int = 0 ) { - val lineSize get() = textLines.size - val charSize get() = text.length + val lines: List get() = textLines + val lineSize: Int get() = textLines.size + val charSize: Int get() = text.length var isMsgPage: Boolean = false + fun addLine(line: TextLine) { + textLines.add(line) + } + fun getLine(index: Int): TextLine { return textLines.getOrElse(index) { textLines.last() @@ -84,7 +89,7 @@ data class TextPage( } /** - * 计算文字位置 + * 计算文字位置,只用作单页面内容 */ @Suppress("DEPRECATION") fun format(): TextPage { @@ -113,12 +118,11 @@ data class TextPage( val char = textLine.text[i].toString() val cw = StaticLayout.getDesiredWidth(char, ChapterProvider.contentPaint) val x1 = x + cw - textLine.textColumns.add( + textLine.addColumn( TextColumn( char, start = x, - end = x1, - style = if (textLine.text.length - 1 == index && char == "\uD83D\uDCAC") 2 else 0 + end = x1 ) ) x = x1 diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt index 873ad925a..8c518ea44 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt @@ -26,7 +26,10 @@ import java.util.* */ @Suppress("DEPRECATION") object ChapterProvider { + //用于图片字的替换 private const val srcReplaceChar = "▩" + + //用于评论按钮的替换 private const val reviewChar = "\uD83D\uDCAC" @JvmStatic @@ -264,10 +267,10 @@ object ChapterProvider { } else { Pair(0f, width.toFloat()) } - textLine.textColumns.add( + textLine.addColumn( TextColumn(charData = src, start = x + start, end = x + end, style = 1) ) - textPages.last().textLines.add(textLine) + textPages.last().addLine(textLine) } return durY + paragraphSpacing / 10f } @@ -306,7 +309,7 @@ object ChapterProvider { if (fistLine.lineTop < textLayoutHeight + titleTopSpacing) { textLayoutHeight = fistLine.lineTop - titleTopSpacing } - textPage.textLines.forEach { + textPage.lines.forEach { it.lineTop = it.lineTop - textLayoutHeight it.lineBase = it.lineBase - textLayoutHeight it.lineBottom = it.lineBottom - textLayoutHeight @@ -314,7 +317,7 @@ object ChapterProvider { y - textLayoutHeight } } - isTitle && textPages.size == 1 && textPages.last().textLines.isEmpty() -> + isTitle && textPages.size == 1 && textPages.last().lines.isEmpty() -> y + titleTopSpacing else -> y } @@ -382,7 +385,7 @@ object ChapterProvider { if (textLine.isParagraphEnd) { stringBuilder.append("\n") } - textPages.last().textLines.add(textLine) + textPages.last().addLine(textLine) textLine.upTopBottom(durY, textPaint) durY += textPaint.textHeight * lineSpacingExtra textPages.last().height = durY @@ -412,7 +415,7 @@ object ChapterProvider { val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length for (char in bodyIndent.toStringArray()) { val x1 = x + icw - textLine.textColumns.add( + textLine.addColumn( TextColumn( charData = char, start = absStartX + x, @@ -496,7 +499,7 @@ object ChapterProvider { if (srcList != null && char == srcReplaceChar) { val src = srcList.removeFirst() ImageProvider.cacheImage(book, src, ReadBook.bookSource) - textLine.textColumns.add( + textLine.addColumn( TextColumn( charData = src, start = absStartX + xStart, @@ -505,7 +508,7 @@ object ChapterProvider { ) ) } else { - textLine.textColumns.add( + textLine.addColumn( TextColumn( charData = char, start = absStartX + xStart, @@ -521,11 +524,11 @@ object ChapterProvider { */ private fun exceed(absStartX: Int, textLine: TextLine, words: Array) { val visibleEnd = absStartX + visibleWidth - val endX = textLine.textColumns.lastOrNull()?.end ?: return + val endX = textLine.columns.lastOrNull()?.end ?: return if (endX > visibleEnd) { val cc = (endX - visibleEnd) / words.size for (i in 0..words.lastIndex) { - textLine.getTextColumnReverseAt(i).let { + textLine.getColumnReverseAt(i).let { val py = cc * (words.size - i) it.start = it.start - py it.end = it.end - py