正文规则添加字体

pull/475/head
gedoor 4 years ago
parent b272de377c
commit 4c5d030d61
  1. 5
      app/src/main/java/io/legado/app/data/entities/BookChapter.kt
  2. 40
      app/src/main/java/io/legado/app/help/BookHelp.kt
  3. 42
      app/src/main/java/io/legado/app/model/webBook/BookContent.kt
  4. 13
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  5. 6
      app/src/main/java/io/legado/app/service/CacheBookService.kt
  6. 7
      app/src/main/java/io/legado/app/service/help/CacheBook.kt
  7. 2
      app/src/main/java/io/legado/app/ui/book/cache/CacheActivity.kt
  8. 26
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  9. 10
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  10. 8
      app/src/main/java/io/legado/app/ui/book/read/page/PageFactory.kt
  11. 12
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  12. 52
      app/src/main/java/io/legado/app/ui/book/read/page/TextPageFactory.kt
  13. 6
      app/src/main/java/io/legado/app/ui/book/read/page/entities/PageData.kt
  14. 5
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChapter.kt
  15. 91
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ChapterProvider.kt
  16. 4
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentActivity.kt
  17. 4
      app/src/main/java/io/legado/app/ui/book/toc/ChapterListAdapter.kt
  18. 2
      app/src/main/java/io/legado/app/ui/book/toc/ChapterListFragment.kt

@ -6,6 +6,7 @@ import androidx.room.ForeignKey
import androidx.room.Ignore import androidx.room.Ignore
import androidx.room.Index import androidx.room.Index
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.MD5Utils
import io.legado.app.utils.NetworkUtils import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.IgnoredOnParcel
@ -62,5 +63,9 @@ data class BookChapter(
fun getAbsoluteURL(): String { fun getAbsoluteURL(): String {
return NetworkUtils.getAbsoluteURL(baseUrl, url)!! return NetworkUtils.getAbsoluteURL(baseUrl, url)!!
} }
fun getFileName(): String = String.format("%05d-%s.nb", index, MD5Utils.md5Encode16(title))
fun getFontName(): String = String.format("%05d-%s.ttf", index, MD5Utils.md5Encode16(title))
} }

@ -31,14 +31,6 @@ object BookHelp {
private val downloadDir: File = App.INSTANCE.externalFilesDir private val downloadDir: File = App.INSTANCE.externalFilesDir
private val downloadImages = CopyOnWriteArraySet<String>() private val downloadImages = CopyOnWriteArraySet<String>()
fun formatChapterName(bookChapter: BookChapter): String {
return String.format(
"%05d-%s.nb",
bookChapter.index,
MD5Utils.md5Encode16(bookChapter.title)
)
}
fun clearCache() { fun clearCache() {
FileUtils.deleteFile( FileUtils.deleteFile(
FileUtils.getPath(downloadDir, cacheFolderName) FileUtils.getPath(downloadDir, cacheFolderName)
@ -75,7 +67,7 @@ object BookHelp {
downloadDir, downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
formatChapterName(bookChapter), bookChapter.getFileName(),
).writeText(content) ).writeText(content)
//保存图片 //保存图片
content.split("\n").forEach { content.split("\n").forEach {
@ -91,6 +83,30 @@ object BookHelp {
postEvent(EventBus.SAVE_CONTENT, bookChapter) postEvent(EventBus.SAVE_CONTENT, bookChapter)
} }
suspend fun saveFont(book: Book, bookChapter: BookChapter, font: ByteArray) {
FileUtils.createFileIfNotExist(
downloadDir,
cacheFolderName,
book.getFolderName(),
"font",
bookChapter.getFontName()
).writeBytes(font)
}
suspend fun getFont(book: Book, bookChapter: BookChapter): File? {
val fontFile = FileUtils.getFile(
downloadDir,
cacheFolderName,
book.getFolderName(),
"font",
bookChapter.getFontName()
)
if (fontFile.exists()) {
return fontFile
}
return null
}
suspend fun saveImage(book: Book, src: String) { suspend fun saveImage(book: Book, src: String) {
while (downloadImages.contains(src)) { while (downloadImages.contains(src)) {
delay(100) delay(100)
@ -158,7 +174,7 @@ object BookHelp {
downloadDir, downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
formatChapterName(bookChapter) bookChapter.getFileName()
) )
} }
} }
@ -171,7 +187,7 @@ object BookHelp {
downloadDir, downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
formatChapterName(bookChapter) bookChapter.getFileName()
) )
if (file.exists()) { if (file.exists()) {
return file.readText() return file.readText()
@ -188,7 +204,7 @@ object BookHelp {
downloadDir, downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
formatChapterName(bookChapter) bookChapter.getFileName()
).delete() ).delete()
} }
} }

@ -6,6 +6,7 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.ContentRule import io.legado.app.data.entities.rule.ContentRule
import io.legado.app.help.BookHelp
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeRule
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
@ -38,7 +39,7 @@ object BookContent {
val analyzeRule = AnalyzeRule(book) val analyzeRule = AnalyzeRule(book)
analyzeRule.setContent(body).setBaseUrl(baseUrl) analyzeRule.setContent(body).setBaseUrl(baseUrl)
analyzeRule.getByteArray(it)?.let { font -> analyzeRule.getByteArray(it)?.let { font ->
BookHelp.saveFont(book, bookChapter, font)
} }
} }
var contentData = analyzeContent( var contentData = analyzeContent(
@ -62,16 +63,14 @@ object BookContent {
ruleUrl = nextUrl, ruleUrl = nextUrl,
book = book, book = book,
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
).getResponseAwait(bookSource.bookSourceUrl) ).getResponseAwait(bookSource.bookSourceUrl).body?.let { nextBody ->
.body?.let { nextBody -> contentData = analyzeContent(
contentData = book, nextUrl, nextBody, contentRule, bookChapter, bookSource, false
analyzeContent( )
book, nextUrl, nextBody, contentRule, bookChapter, bookSource, false nextUrl =
) if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else ""
nextUrl = content.append(contentData.content).append("\n")
if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" }
content.append(contentData.content).append("\n")
}
} }
Debug.log(bookSource.bookSourceUrl, "◇本章总页数:${nextUrlList.size}") Debug.log(bookSource.bookSourceUrl, "◇本章总页数:${nextUrlList.size}")
} else if (contentData.nextUrl.size > 1) { } else if (contentData.nextUrl.size > 1) {
@ -86,20 +85,12 @@ object BookContent {
ruleUrl = item.nextUrl, ruleUrl = item.nextUrl,
book = book, book = book,
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
).getResponseAwait(bookSource.bookSourceUrl) ).getResponseAwait(bookSource.bookSourceUrl).body?.let {
.body?.let { contentData = analyzeContent(
contentData = book, item.nextUrl, it, contentRule, bookChapter, bookSource, false
analyzeContent( )
book, item.content = contentData.content
item.nextUrl, }
it,
contentRule,
bookChapter,
bookSource,
false
)
item.content = contentData.content
}
} }
} }
for (item in contentDataList) { for (item in contentDataList) {
@ -119,6 +110,7 @@ object BookContent {
Debug.log(bookSource.bookSourceUrl, "${bookChapter.title}") Debug.log(bookSource.bookSourceUrl, "${bookChapter.title}")
Debug.log(bookSource.bookSourceUrl, "┌获取正文内容") Debug.log(bookSource.bookSourceUrl, "┌获取正文内容")
Debug.log(bookSource.bookSourceUrl, "\n$contentStr") Debug.log(bookSource.bookSourceUrl, "\n$contentStr")
BookHelp.saveContent(book, bookChapter, contentStr)
return contentStr return contentStr
} }

@ -24,7 +24,6 @@ import io.legado.app.constant.EventBus
import io.legado.app.constant.IntentAction import io.legado.app.constant.IntentAction
import io.legado.app.constant.Status import io.legado.app.constant.Status
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp
import io.legado.app.help.IntentHelp import io.legado.app.help.IntentHelp
import io.legado.app.help.MediaHelp import io.legado.app.help.MediaHelp
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
@ -283,19 +282,17 @@ class AudioPlayService : BaseService(),
} }
} }
private fun loadContent(chapter: BookChapter) { private fun loadContent(chapter: BookChapter) = AudioPlay.apply {
AudioPlay.book?.let { book -> book?.let { book ->
AudioPlay.webBook?.getContent(book, chapter, scope = this) webBook?.getContent(book, chapter, scope = this@AudioPlayService)
?.onSuccess(IO) { content -> ?.onSuccess { content ->
removeLoading(chapter.index)
if (content.isEmpty()) { if (content.isEmpty()) {
withContext(Main) { withContext(Main) {
toast("未获取到资源链接") toast("未获取到资源链接")
} }
removeLoading(chapter.index)
} else { } else {
BookHelp.saveContent(book, chapter, content)
contentLoadFinish(chapter, content) contentLoadFinish(chapter, content)
removeLoading(chapter.index)
} }
}?.onError { }?.onError {
contentLoadFinish(chapter, it.localizedMessage ?: toString()) contentLoadFinish(chapter, it.localizedMessage ?: toString())

@ -20,7 +20,6 @@ import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.help.CacheBook import io.legado.app.service.help.CacheBook
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -197,8 +196,7 @@ class CacheBookService : BaseService() {
CacheBook.addLog("getContentError${it.localizedMessage}") CacheBook.addLog("getContentError${it.localizedMessage}")
updateNotification("getContentError${it.localizedMessage}") updateNotification("getContentError${it.localizedMessage}")
} }
.onSuccess(IO) { content -> .onSuccess {
BookHelp.saveContent(book, bookChapter, content)
synchronized(this@CacheBookService) { synchronized(this@CacheBookService) {
downloadCount[book.bookUrl]?.increaseSuccess() downloadCount[book.bookUrl]?.increaseSuccess()
downloadCount[book.bookUrl]?.increaseFinished() downloadCount[book.bookUrl]?.increaseFinished()
@ -221,7 +219,7 @@ class CacheBookService : BaseService() {
downloadCount.remove(book.bookUrl) downloadCount.remove(book.bookUrl)
} }
} }
}.onFinally(IO) { }.onFinally {
postDownloading(true) postDownloading(true)
} }
} else { } else {

@ -7,11 +7,9 @@ import io.legado.app.R
import io.legado.app.constant.IntentAction import io.legado.app.constant.IntentAction
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.CacheBookService import io.legado.app.service.CacheBookService
import io.legado.app.utils.msg import io.legado.app.utils.msg
import kotlinx.coroutines.Dispatchers.IO
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
@ -76,10 +74,7 @@ object CacheBook {
} }
downloadMap[book.bookUrl]?.add(chapter.index) downloadMap[book.bookUrl]?.add(chapter.index)
webBook.getContent(book, chapter) webBook.getContent(book, chapter)
.onSuccess(IO) { content -> .onSuccess { content ->
if (content.isNotBlank()) {
BookHelp.saveContent(book, chapter, content)
}
if (ReadBook.book?.bookUrl == book.bookUrl) { if (ReadBook.book?.bookUrl == book.bookUrl) {
ReadBook.contentLoadFinish( ReadBook.contentLoadFinish(
book, book,

@ -151,7 +151,7 @@ class CacheActivity : VMBaseActivity<CacheViewModel>(R.layout.activity_download)
val chapterCaches = hashSetOf<String>() val chapterCaches = hashSetOf<String>()
val cacheNames = BookHelp.getChapterFiles(book) val cacheNames = BookHelp.getChapterFiles(book)
App.db.bookChapterDao().getChapterList(book.bookUrl).forEach { chapter -> App.db.bookChapterDao().getChapterList(book.bookUrl).forEach { chapter ->
if (cacheNames.contains(BookHelp.formatChapterName(chapter))) { if (cacheNames.contains(chapter.getFileName())) {
chapterCaches.add(chapter.url) chapterCaches.add(chapter.url)
} }
} }

@ -12,9 +12,7 @@ import io.legado.app.constant.PreferKey
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.service.help.ReadBook import io.legado.app.service.help.ReadBook
import io.legado.app.ui.book.read.page.entities.TextChar import io.legado.app.ui.book.read.page.entities.*
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.provider.ChapterProvider 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.ImageProvider
import io.legado.app.ui.widget.dialog.PhotoDialog import io.legado.app.ui.widget.dialog.PhotoDialog
@ -40,6 +38,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
private val visibleRect = RectF() private val visibleRect = RectF()
private val selectStart = arrayOf(0, 0, 0) private val selectStart = arrayOf(0, 0, 0)
private val selectEnd = arrayOf(0, 0, 0) private val selectEnd = arrayOf(0, 0, 0)
private var textChapter: TextChapter? = null
private var textPage: TextPage = TextPage() private var textPage: TextPage = TextPage()
//滚动参数 //滚动参数
@ -51,8 +50,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
contentDescription = textPage.text contentDescription = textPage.text
} }
fun setContent(textPage: TextPage) { fun setContent(pageData: PageData) {
this.textPage = textPage this.textChapter = pageData.textChapter
this.textPage = pageData.textPage
contentDescription = textPage.text contentDescription = textPage.text
invalidate() invalidate()
} }
@ -139,7 +139,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
isTitle: Boolean, isTitle: Boolean,
isReadAloud: Boolean, isReadAloud: Boolean,
) { ) {
val textPaint = if (isTitle) ChapterProvider.titlePaint else ChapterProvider.contentPaint val textPaint = if (isTitle) {
textChapter?.titlePaint ?: ChapterProvider.titlePaint
} else {
textChapter?.contentPaint ?: ChapterProvider.contentPaint
}
textPaint.color = textPaint.color =
if (isReadAloud) context.accentColor else ReadBookConfig.textColor if (isReadAloud) context.accentColor else ReadBookConfig.textColor
textChars.forEach { textChars.forEach {
@ -186,13 +190,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
pageOffset = min(0, offset) pageOffset = min(0, offset)
} else if (pageOffset > 0) { } else if (pageOffset > 0) {
pageFactory.moveToPrev(false) pageFactory.moveToPrev(false)
textPage = pageFactory.currentPage textPage = pageFactory.curData.textPage
pageOffset -= textPage.height.toInt() pageOffset -= textPage.height.toInt()
upView?.invoke(textPage) upView?.invoke(textPage)
} else if (pageOffset < -textPage.height) { } else if (pageOffset < -textPage.height) {
pageOffset += textPage.height.toInt() pageOffset += textPage.height.toInt()
pageFactory.moveToNext(false) pageFactory.moveToNext(false)
textPage = pageFactory.currentPage textPage = pageFactory.curData.textPage
upView?.invoke(textPage) upView?.invoke(textPage)
} }
invalidate() invalidate()
@ -482,15 +486,15 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
return when (relativePos) { return when (relativePos) {
0 -> pageOffset.toFloat() 0 -> pageOffset.toFloat()
1 -> pageOffset + textPage.height 1 -> pageOffset + textPage.height
else -> pageOffset + textPage.height + pageFactory.nextPage.height else -> pageOffset + textPage.height + pageFactory.nextData.textPage.height
} }
} }
private fun relativePage(relativePos: Int): TextPage { private fun relativePage(relativePos: Int): TextPage {
return when (relativePos) { return when (relativePos) {
0 -> textPage 0 -> textPage
1 -> pageFactory.nextPage 1 -> pageFactory.nextData.textPage
else -> pageFactory.nextPagePlus else -> pageFactory.nextPlusData.textPage
} }
} }

@ -12,6 +12,7 @@ import io.legado.app.constant.AppConst.timeFormat
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.help.ReadTipConfig import io.legado.app.help.ReadTipConfig
import io.legado.app.service.help.ReadBook import io.legado.app.service.help.ReadBook
import io.legado.app.ui.book.read.page.entities.PageData
import io.legado.app.ui.book.read.page.entities.TextPage 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.widget.BatteryView import io.legado.app.ui.widget.BatteryView
@ -217,11 +218,12 @@ class ContentView(context: Context) : FrameLayout(context) {
tvBattery?.setBattery(battery) tvBattery?.setBattery(battery)
} }
fun setContent(textPage: TextPage, resetPageOffset: Boolean = true) { fun setContent(pageData: PageData, resetPageOffset: Boolean = true) {
setProgress(textPage) setProgress(pageData.textPage)
if (resetPageOffset) if (resetPageOffset) {
resetPageOffset() resetPageOffset()
content_text_view.setContent(textPage) }
content_text_view.setContent(pageData)
} }
fun resetPageOffset() { fun resetPageOffset() {

@ -10,13 +10,13 @@ abstract class PageFactory<DATA>(protected val dataSource: DataSource) {
abstract fun moveToPrev(upContent: Boolean): Boolean abstract fun moveToPrev(upContent: Boolean): Boolean
abstract val nextPage: DATA abstract val nextData: DATA
abstract val prevPage: DATA abstract val prevData: DATA
abstract val currentPage: DATA abstract val curData: DATA
abstract val nextPagePlus: DATA abstract val nextPlusData: DATA
abstract fun hasNext(): Boolean abstract fun hasNext(): Boolean

@ -376,16 +376,16 @@ class PageView(context: Context, attrs: AttributeSet) :
override fun upContent(relativePosition: Int, resetPageOffset: Boolean) { override fun upContent(relativePosition: Int, resetPageOffset: Boolean) {
if (isScroll && !callBack.isAutoPage) { if (isScroll && !callBack.isAutoPage) {
curPage.setContent(pageFactory.currentPage, resetPageOffset) curPage.setContent(pageFactory.curData, resetPageOffset)
} else { } else {
curPage.resetPageOffset() curPage.resetPageOffset()
when (relativePosition) { when (relativePosition) {
-1 -> prevPage.setContent(pageFactory.prevPage) -1 -> prevPage.setContent(pageFactory.prevData)
1 -> nextPage.setContent(pageFactory.nextPage) 1 -> nextPage.setContent(pageFactory.nextData)
else -> { else -> {
curPage.setContent(pageFactory.currentPage) curPage.setContent(pageFactory.curData)
nextPage.setContent(pageFactory.nextPage) nextPage.setContent(pageFactory.nextData)
prevPage.setContent(pageFactory.prevPage) prevPage.setContent(pageFactory.prevData)
} }
} }
} }

@ -1,9 +1,10 @@
package io.legado.app.ui.book.read.page package io.legado.app.ui.book.read.page
import io.legado.app.service.help.ReadBook import io.legado.app.service.help.ReadBook
import io.legado.app.ui.book.read.page.entities.PageData
import io.legado.app.ui.book.read.page.entities.TextPage import io.legado.app.ui.book.read.page.entities.TextPage
class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource) { class TextPageFactory(dataSource: DataSource) : PageFactory<PageData>(dataSource) {
override fun hasPrev(): Boolean = with(dataSource) { override fun hasPrev(): Boolean = with(dataSource) {
return hasPrevChapter() || pageIndex > 0 return hasPrevChapter() || pageIndex > 0
@ -57,74 +58,81 @@ class TextPageFactory(dataSource: DataSource) : PageFactory<TextPage>(dataSource
false false
} }
override val currentPage: TextPage override val curData: PageData
get() = with(dataSource) { get() = with(dataSource) {
ReadBook.msg?.let { ReadBook.msg?.let {
return@with TextPage(text = it).format() return@with PageData(TextPage(text = it).format())
} }
currentChapter?.let { currentChapter?.let {
return@with it.page(pageIndex) val page = it.page(pageIndex) ?: TextPage(title = it.title).format()
?: TextPage(title = it.title).format() return@with PageData(page, it)
} }
return TextPage().format() return PageData(TextPage().format())
} }
override val nextPage: TextPage override val nextData: PageData
get() = with(dataSource) { get() = with(dataSource) {
ReadBook.msg?.let { ReadBook.msg?.let {
return@with TextPage(text = it).format() return@with PageData(TextPage(text = it).format())
} }
currentChapter?.let { currentChapter?.let {
if (pageIndex < it.pageSize - 1) { if (pageIndex < it.pageSize - 1) {
return@with it.page(pageIndex + 1)?.removePageAloudSpan() val page = it.page(pageIndex + 1)?.removePageAloudSpan()
?: TextPage(title = it.title).format() ?: TextPage(title = it.title).format()
return@with PageData(page, it)
} }
} }
if (!hasNextChapter()) { if (!hasNextChapter()) {
return@with TextPage(text = "") return@with PageData(TextPage(text = ""))
} }
nextChapter?.let { nextChapter?.let {
return@with it.page(0)?.removePageAloudSpan() val page = it.page(0)?.removePageAloudSpan()
?: TextPage(title = it.title).format() ?: TextPage(title = it.title).format()
return@with PageData(page, it)
} }
return TextPage().format() return PageData(TextPage().format())
} }
override val prevPage: TextPage override val prevData: PageData
get() = with(dataSource) { get() = with(dataSource) {
ReadBook.msg?.let { ReadBook.msg?.let {
return@with TextPage(text = it).format() return@with PageData(TextPage(text = it).format())
} }
if (pageIndex > 0) { if (pageIndex > 0) {
currentChapter?.let { currentChapter?.let {
return@with it.page(pageIndex - 1)?.removePageAloudSpan() val page = it.page(pageIndex - 1)?.removePageAloudSpan()
?: TextPage(title = it.title).format() ?: TextPage(title = it.title).format()
return@with PageData(page, it)
} }
} }
prevChapter?.let { prevChapter?.let {
return@with it.lastPage?.removePageAloudSpan() val page = it.lastPage?.removePageAloudSpan()
?: TextPage(title = it.title).format() ?: TextPage(title = it.title).format()
return@with PageData(page, it)
} }
return TextPage().format() return PageData(TextPage().format())
} }
override val nextPagePlus: TextPage override val nextPlusData: PageData
get() = with(dataSource) { get() = with(dataSource) {
currentChapter?.let { currentChapter?.let {
if (pageIndex < it.pageSize - 2) { if (pageIndex < it.pageSize - 2) {
return@with it.page(pageIndex + 2)?.removePageAloudSpan() val page = it.page(pageIndex + 2)?.removePageAloudSpan()
?: TextPage(title = it.title).format() ?: TextPage(title = it.title).format()
return@with PageData(page, it)
} }
nextChapter?.let { nc -> nextChapter?.let { nc ->
if (pageIndex < it.pageSize - 1) { if (pageIndex < it.pageSize - 1) {
return@with nc.page(0)?.removePageAloudSpan() val page = nc.page(0)?.removePageAloudSpan()
?: TextPage(title = nc.title).format() ?: TextPage(title = nc.title).format()
return@with PageData(page, nc)
} }
return@with nc.page(1)?.removePageAloudSpan() val page = nc.page(1)?.removePageAloudSpan()
?: TextPage(title = nc.title).format() ?: TextPage(title = nc.title).format()
return@with PageData(page, nc)
} }
} }
return TextPage().format() return PageData(TextPage().format())
} }
} }

@ -0,0 +1,6 @@
package io.legado.app.ui.book.read.page.entities
data class PageData(
val textPage: TextPage,
val textChapter: TextChapter? = null
)

@ -1,5 +1,6 @@
package io.legado.app.ui.book.read.page.entities package io.legado.app.ui.book.read.page.entities
import android.text.TextPaint
import kotlin.math.min import kotlin.math.min
data class TextChapter( data class TextChapter(
@ -9,7 +10,9 @@ data class TextChapter(
val pages: List<TextPage>, val pages: List<TextPage>,
val pageLines: List<Int>, val pageLines: List<Int>,
val pageLengths: List<Int>, val pageLengths: List<Int>,
val chaptersSize: Int val chaptersSize: Int,
var titlePaint: TextPaint? = null,
var contentPaint: TextPaint? = null
) { ) {
fun page(index: Int): TextPage? { fun page(index: Int): TextPage? {
return pages.getOrNull(index) return pages.getOrNull(index)

@ -66,19 +66,18 @@ object ChapterProvider {
src = NetworkUtils.getAbsoluteURL(bookChapter.url, src) src = NetworkUtils.getAbsoluteURL(bookChapter.url, src)
} }
src?.let { src?.let {
durY = durY = setTypeImage(
setTypeImage( book, bookChapter, src, durY, textPages, imageStyle
book, bookChapter, src, durY, textPages, imageStyle )
)
} }
} else { } else {
val isTitle = index == 0 val isTitle = index == 0
val textPaint = if (isTitle) titlePaint else contentPaint
if (!(isTitle && ReadBookConfig.titleMode == 2)) { if (!(isTitle && ReadBookConfig.titleMode == 2)) {
durY = durY = setTypeText(
setTypeText( text, durY, textPages, pageLines,
text, durY, textPages, pageLines, pageLengths, stringBuilder, isTitle, textPaint
pageLengths, stringBuilder, isTitle )
)
} }
} }
} }
@ -185,9 +184,9 @@ object ChapterProvider {
pageLengths: ArrayList<Int>, pageLengths: ArrayList<Int>,
stringBuilder: StringBuilder, stringBuilder: StringBuilder,
isTitle: Boolean, isTitle: Boolean,
textPaint: TextPaint
): Float { ): Float {
var durY = if (isTitle) y + titleTopSpacing else y var durY = if (isTitle) y + titleTopSpacing else y
val textPaint = if (isTitle) titlePaint else contentPaint
val layout = StaticLayout( val layout = StaticLayout(
text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true
) )
@ -200,12 +199,7 @@ object ChapterProvider {
if (lineIndex == 0 && layout.lineCount > 1 && !isTitle) { if (lineIndex == 0 && layout.lineCount > 1 && !isTitle) {
//第一行 //第一行
textLine.text = words textLine.text = words
addCharsToLineFirst( addCharsToLineFirst(textLine, words.toStringArray(), textPaint, desiredWidth)
textLine,
words.toStringArray(),
textPaint,
desiredWidth
)
} else if (lineIndex == layout.lineCount - 1) { } else if (lineIndex == layout.lineCount - 1) {
//最后一行 //最后一行
textLine.text = "$words\n" textLine.text = "$words\n"
@ -213,22 +207,11 @@ object ChapterProvider {
val x = if (isTitle && ReadBookConfig.titleMode == 1) val x = if (isTitle && ReadBookConfig.titleMode == 1)
(visibleWidth - layout.getLineWidth(lineIndex)) / 2 (visibleWidth - layout.getLineWidth(lineIndex)) / 2
else 0f else 0f
addCharsToLineLast( addCharsToLineLast(textLine, words.toStringArray(), textPaint, x)
textLine,
words.toStringArray(),
textPaint,
x
)
} else { } else {
//中间行 //中间行
textLine.text = words textLine.text = words
addCharsToLineMiddle( addCharsToLineMiddle(textLine, words.toStringArray(), textPaint, desiredWidth, 0f)
textLine,
words.toStringArray(),
textPaint,
desiredWidth,
0f
)
} }
if (durY + textPaint.textHeight > visibleHeight) { if (durY + textPaint.textHeight > visibleHeight) {
//当前页面结束,设置各种值 //当前页面结束,设置各种值
@ -264,33 +247,18 @@ object ChapterProvider {
) { ) {
var x = 0f var x = 0f
if (!ReadBookConfig.textFullJustify) { if (!ReadBookConfig.textFullJustify) {
addCharsToLineLast( addCharsToLineLast(textLine, words, textPaint, x)
textLine,
words,
textPaint,
x
)
return return
} }
val bodyIndent = ReadBookConfig.paragraphIndent val bodyIndent = ReadBookConfig.paragraphIndent
val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length
bodyIndent.toStringArray().forEach { bodyIndent.toStringArray().forEach {
val x1 = x + icw val x1 = x + icw
textLine.addTextChar( textLine.addTextChar(charData = it, start = paddingLeft + x, end = paddingLeft + x1)
charData = it,
start = paddingLeft + x,
end = paddingLeft + x1
)
x = x1 x = x1
} }
val words1 = words.copyOfRange(bodyIndent.length, words.size) val words1 = words.copyOfRange(bodyIndent.length, words.size)
addCharsToLineMiddle( addCharsToLineMiddle(textLine, words1, textPaint, desiredWidth, x)
textLine,
words1,
textPaint,
desiredWidth,
x
)
} }
/** /**
@ -304,12 +272,7 @@ object ChapterProvider {
startX: Float, startX: Float,
) { ) {
if (!ReadBookConfig.textFullJustify) { if (!ReadBookConfig.textFullJustify) {
addCharsToLineLast( addCharsToLineLast(textLine, words, textPaint, startX)
textLine,
words,
textPaint,
startX
)
return return
} }
val gapCount: Int = words.lastIndex val gapCount: Int = words.lastIndex
@ -318,17 +281,10 @@ object ChapterProvider {
words.forEachIndexed { index, s -> words.forEachIndexed { index, s ->
val cw = StaticLayout.getDesiredWidth(s, textPaint) val cw = StaticLayout.getDesiredWidth(s, textPaint)
val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw) val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw)
textLine.addTextChar( textLine.addTextChar(charData = s, start = paddingLeft + x, end = paddingLeft + x1)
charData = s,
start = paddingLeft + x,
end = paddingLeft + x1
)
x = x1 x = x1
} }
exceed( exceed(textLine, words)
textLine,
words
)
} }
/** /**
@ -344,17 +300,10 @@ object ChapterProvider {
words.forEach { words.forEach {
val cw = StaticLayout.getDesiredWidth(it, textPaint) val cw = StaticLayout.getDesiredWidth(it, textPaint)
val x1 = x + cw val x1 = x + cw
textLine.addTextChar( textLine.addTextChar(charData = it, start = paddingLeft + x, end = paddingLeft + x1)
charData = it,
start = paddingLeft + x,
end = paddingLeft + x1
)
x = x1 x = x1
} }
exceed( exceed(textLine, words)
textLine,
words
)
} }
/** /**

@ -122,7 +122,7 @@ class SearchContentActivity :
observeEvent<BookChapter>(EventBus.SAVE_CONTENT) { chapter -> observeEvent<BookChapter>(EventBus.SAVE_CONTENT) { chapter ->
viewModel.book?.bookUrl?.let { bookUrl -> viewModel.book?.bookUrl?.let { bookUrl ->
if (chapter.bookUrl == bookUrl) { if (chapter.bookUrl == bookUrl) {
adapter.cacheFileNames.add(BookHelp.formatChapterName(chapter)) adapter.cacheFileNames.add(chapter.getFileName())
adapter.notifyItemChanged(chapter.index, true) adapter.notifyItemChanged(chapter.index, true)
} }
} }
@ -143,7 +143,7 @@ class SearchContentActivity :
App.db.bookChapterDao().getChapterList(viewModel.bookUrl).map { chapter -> App.db.bookChapterDao().getChapterList(viewModel.bookUrl).map { chapter ->
val job = async(Dispatchers.IO) { val job = async(Dispatchers.IO) {
if (isLocalBook if (isLocalBook
|| adapter.cacheFileNames.contains(BookHelp.formatChapterName(chapter)) || adapter.cacheFileNames.contains(chapter.getFileName())
) { ) {
searchResults = searchChapter(newText, chapter) searchResults = searchChapter(newText, chapter)
} }

@ -6,7 +6,6 @@ import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.base.adapter.SimpleRecyclerAdapter
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.utils.getCompatColor import io.legado.app.utils.getCompatColor
import io.legado.app.utils.visible import io.legado.app.utils.visible
@ -22,8 +21,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList<Any>) { override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList<Any>) {
with(holder.itemView) { with(holder.itemView) {
val isDur = callback.durChapterIndex() == item.index val isDur = callback.durChapterIndex() == item.index
val cached = callback.isLocalBook val cached = callback.isLocalBook || cacheFileNames.contains(item.getFileName())
|| cacheFileNames.contains(BookHelp.formatChapterName(item))
if (payloads.isEmpty()) { if (payloads.isEmpty()) {
if (isDur) { if (isDur) {
tv_chapter_name.setTextColor(context.accentColor) tv_chapter_name.setTextColor(context.accentColor)

@ -110,7 +110,7 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
observeEvent<BookChapter>(EventBus.SAVE_CONTENT) { chapter -> observeEvent<BookChapter>(EventBus.SAVE_CONTENT) { chapter ->
viewModel.book?.bookUrl?.let { bookUrl -> viewModel.book?.bookUrl?.let { bookUrl ->
if (chapter.bookUrl == bookUrl) { if (chapter.bookUrl == bookUrl) {
adapter.cacheFileNames.add(BookHelp.formatChapterName(chapter)) adapter.cacheFileNames.add(chapter.getFileName())
adapter.notifyItemChanged(chapter.index, true) adapter.notifyItemChanged(chapter.index, true)
} }
} }

Loading…
Cancel
Save