段评相关

感谢@Luoyacheng,https://github.com/Luoyacheng/legado
This commit is contained in:
HapeLee committed 2025-09-24 19:24:06 +08:00
1 parent 53a1a6c89a
commit 891ec2a6ec
7 files changed
+1980 -65

No files matched your search

@@ -46,10 +46,10 @@ import java.util.Locale
@Suppress("DEPRECATION", "ConstPropertyName")
object ChapterProvider {
//用于图片字的替换
const val srcReplaceChar = "▩"
const val srcReplaceChar = "⼁"//▩ 丨
//用于评论按钮的替换
const val reviewChar = "▨"
const val reviewChar = "꧁"
const val indentChar = " "
@@ -4,8 +4,11 @@ import android.graphics.Paint
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import android.util.Size
import io.legato.kazusa.constant.AppLog
import io.legato.kazusa.constant.AppPattern
import io.legato.kazusa.constant.AppPattern.noWordCountRegex
import io.legato.kazusa.data.appDb
import io.legato.kazusa.data.entities.Book
import io.legato.kazusa.data.entities.BookChapter
import io.legato.kazusa.help.book.BookContent
@@ -21,6 +24,7 @@ import io.legato.kazusa.ui.book.read.page.entities.TextLine
import io.legato.kazusa.ui.book.read.page.entities.TextPage
import io.legato.kazusa.ui.book.read.page.entities.column.ImageColumn
import io.legato.kazusa.ui.book.read.page.entities.column.TextColumn
import io.legato.kazusa.utils.StringUtils
import io.legato.kazusa.utils.dpToPx
import io.legato.kazusa.utils.fastSum
import io.legato.kazusa.utils.getTextWidthsCompat
@@ -202,13 +206,25 @@ class TextChapterLayout(
if (titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
//标题非隐藏
displayTitle.splitNotBlank("\n").forEach { text ->
val srcList = LinkedList<String>()
val reviewImg = bookChapter.reviewImg
var reviewTxt = ""
if (reviewImg != null) {
srcList.add(reviewImg)
reviewTxt = if (reviewImg.contains("TEXT")) {
ChapterProvider.reviewChar
} else {
ChapterProvider.srcReplaceChar
}
}
setTypeText(
book,
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
text + reviewTxt,
titlePaint,
titlePaintTextHeight,
titlePaintFontMetrics,
imageStyle,
srcList = srcList.ifEmpty { null },
isTitle = true,
emptyContent = contents.isEmpty(),
isVolumeTitle = bookChapter.isVolume
@@ -226,11 +242,12 @@ class TextChapterLayout(
val sb = StringBuffer()
var isSetTypedImage = false
var wordCount = 0
contents.forEach { content ->
coroutineContext.ensureActive()
if (isTextImageStyle) {
//图片样式为文字嵌入类型
var text = content.replace(ChapterProvider.srcReplaceChar, "▣")
var text = content.replace(ChapterProvider.srcReplaceChar, "丨") //▣
val srcList = LinkedList<String>()
sb.setLength(0)
val matcher = AppPattern.imgPattern.matcher(text)
@@ -242,6 +259,7 @@ class TextChapterLayout(
}
matcher.appendTail(sb)
text = sb.toString()
wordCount += text.replace(noWordCountRegex,"").length
setTypeText(
book,
text,
@@ -257,29 +275,80 @@ class TextChapterLayout(
prepareNextPageIfNeed()
}
var start = 0
val srcList = LinkedList<String>()
sb.setLength(0)
var isFirstLine = true
if (content.contains("<img")) {
val matcher = AppPattern.imgPattern.matcher(content)
val text = content.replace(ChapterProvider.srcReplaceChar, "丨")
val matcher = AppPattern.imgPattern.matcher(text)
while (matcher.find()) {
coroutineContext.ensureActive()
val text = content.substring(start, matcher.start())
if (text.isNotBlank()) {
setTypeText(
val imgSrc = matcher.group(1)!!
var iStyle = imageStyle
var isSmallImage = true
val matchResult = AppPattern.imgStyRegex.find(imgSrc)
var imgSize: Size? = null
if (matchResult != null) {
val styleValue = matchResult.groupValues[1].trim()
if (styleValue == "TEXT" && matcher.end() == text.length) {
iStyle = "TEXT"
wordCount--
}
else if (styleValue.equals("text", true)) {
iStyle = "text"
}
else {
imgSize = ImageProvider.getImageSize(book, imgSrc, ReadBook.bookSource)
iStyle = styleValue
isSmallImage = false
}
}
else {
imgSize = ImageProvider.getImageSize(book, imgSrc, ReadBook.bookSource)
if (imgSize.width < 80 && imgSize.height < 80) {
iStyle = "text"
}
else {
isSmallImage = false
}
}
if (start < matcher.start()) {
sb.append(text.substring(start, matcher.start()))
}
if (isSmallImage) {
sb.append(
if (iStyle == "TEXT")
ChapterProvider.reviewChar
else
ChapterProvider.srcReplaceChar
)
srcList.add(imgSrc)
} else {
val textBefore = sb.toString()
if (textBefore.isNotBlank()) {
wordCount += textBefore.replace(noWordCountRegex,"").length
setTypeText(
book,
sb.toString(),
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
"TEXT",
isFirstLine = isFirstLine,
srcList = srcList
)
sb.setLength(0)
isFirstLine=false
}
setTypeImage(
book,
text,
contentPaint,
imgSrc,
contentPaintTextHeight,
contentPaintFontMetrics,
imageStyle,
isFirstLine = start == 0
iStyle,
imgSize!!
)
isSetTypedImage = true
}
setTypeImage(
book,
matcher.group(1)!!,
contentPaintTextHeight,
imageStyle
)
isSetTypedImage = true
start = matcher.end()
}
}
@@ -288,23 +357,30 @@ class TextChapterLayout(
isSetTypedImage = false
prepareNextPageIfNeed()
}
val text = content.substring(start, content.length)
if (text.isNotBlank()) {
setTypeText(
book,
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
imageStyle,
isFirstLine = start == 0
)
}
val textAfter = content.substring(start, content.length)
sb.append(textAfter)
}
val text = sb.toString()
if (text.isNotBlank()) {
wordCount += text.replace(noWordCountRegex,"").length
setTypeText(
book,
if (AppConfig.enableReview) text + ChapterProvider.reviewChar else text,
contentPaint,
contentPaintTextHeight,
contentPaintFontMetrics,
"TEXT",
isFirstLine = start == 0,
srcList = srcList.ifEmpty { null }
)
}
}
pendingTextPage.lines.last().isParagraphEnd = true
stringBuilder.append("\n")
}
val chapterWordCount = StringUtils.wordCountFormat(wordCount.toString())
bookChapter.wordCount = chapterWordCount
appDb.bookChapterDao.upWordCount(bookChapter.bookUrl, bookChapter.url, chapterWordCount)
val textPage = pendingTextPage
val endPadding = 20.dpToPx()
val durYPadding = durY + endPadding
@@ -327,8 +403,8 @@ class TextChapterLayout(
src: String,
textHeight: Float,
imageStyle: String?,
size: Size
) {
val size = ImageProvider.getImageSize(book, src, ReadBook.bookSource)
if (size.width > 0 && size.height > 0) {
prepareNextPageIfNeed(durY)
var height = size.height
@@ -375,13 +451,19 @@ class TextChapterLayout(
durY += height
textLine.lineBottom = durY + paddingTop
val (start, end) = if (visibleWidth > width) {
val adjustWidth = (visibleWidth - width) / 2f
Pair(adjustWidth, adjustWidth + width)
when (imageStyle?.uppercase()) {
"RIGHT" -> Pair(visibleWidth - width, visibleWidth)
"LEFT" -> Pair(0f, width)
else -> {
val adjustWidth = (visibleWidth - width) / 2f
Pair(adjustWidth, adjustWidth + width)
}
}
} else {
Pair(0f, width.toFloat())
Pair(0f, width)
}
textLine.addColumn(
ImageColumn(start = absStartX + start, end = absStartX + end, src = src)
ImageColumn(start = absStartX + start.toFloat(), end = absStartX + end.toFloat(), src = src)
)
calcTextLinePosition(textPages, textLine, stringBuilder.length)
stringBuilder.append(" ") // 确保翻页时索引计算正确
@@ -697,7 +779,7 @@ class TextChapterLayout(
srcList: LinkedList<String>?
) {
val column = when {
srcList != null && char == ChapterProvider.srcReplaceChar -> {
!srcList.isNullOrEmpty() && (char == ChapterProvider.srcReplaceChar || char == ChapterProvider.reviewChar && isLineEnd) -> {
val src = srcList.removeFirst()
ImageProvider.cacheImage(book, src, ReadBook.bookSource)
ImageColumn(
@@ -706,14 +788,13 @@ class TextChapterLayout(
src = src
)
}
// isLineEnd && char == ChapterProvider.reviewChar -> {
// ReviewColumn(
// start = absStartX + xStart,
// end = absStartX + xEnd,
// count = 100
// )
// }
/*isLineEnd && char == ChapterProvider.reviewChar -> {
ReviewColumn(
start = absStartX + xStart,
end = absStartX + xEnd,
count = 10
)
}*/
else -> {
TextColumn(
@@ -820,4 +901,4 @@ class TextChapterLayout(
return code == 8203 || code == 8204 || code == 8205 || code == 8288
}
}
}