feat: 优化代码

pull/106/head
kunfei 5 years ago
parent 38911b6d93
commit db33516ac5
  1. 15
      app/src/main/assets/readConfig.json
  2. 3
      app/src/main/java/io/legado/app/App.kt
  3. 1
      app/src/main/java/io/legado/app/constant/PreferKey.kt
  4. 5
      app/src/main/java/io/legado/app/help/BookHelp.kt
  5. 14
      app/src/main/java/io/legado/app/help/ReadBookConfig.kt
  6. 2
      app/src/main/java/io/legado/app/ui/book/read/Help.kt
  7. 7
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  8. 10
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  9. 4
      app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt
  10. 17
      app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt
  11. 286
      app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt
  12. 55
      app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt
  13. 50
      app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt
  14. 4
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt
  15. 4
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  16. 7
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt
  17. 3
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextChar.kt
  18. 7
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextLine.kt
  19. 21
      app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt
  20. 12
      app/src/main/res/layout/dialog_read_book_style.xml

@ -9,8 +9,7 @@
"darkStatusIcon": true,
"textSize": 24,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2
"lineSpacingExtra": 10
},
{
"bgStr": "#DDC090",
@ -22,8 +21,7 @@
"darkStatusIcon": true,
"textSize": 24,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2
"lineSpacingExtra": 10
},
{
"bgStr": "#C2D8AA",
@ -35,8 +33,7 @@
"darkStatusIcon": false,
"textSize": 24,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2
"lineSpacingExtra": 10
},
{
"bgStr": "#DBB8E2",
@ -48,8 +45,7 @@
"darkStatusIcon": false,
"textSize": 24,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2
"lineSpacingExtra": 10
},
{
"bgStr": "#ABCEE0",
@ -61,7 +57,6 @@
"darkStatusIcon": false,
"textSize": 24,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"lineSpacingMultiplier": 1.2
"lineSpacingExtra": 10
}
]

@ -19,7 +19,6 @@ import io.legado.app.help.AppConfig
import io.legado.app.help.CrashHandler
import io.legado.app.help.ReadBookConfig
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.ui.book.read.page.ChapterProvider
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getPrefInt
@ -92,7 +91,7 @@ class App : Application() {
)
.apply()
}
ChapterProvider.upReadAloudSpan()
// ChapterProvider.upReadAloudSpan()
}
fun applyDayNight() {

@ -35,4 +35,5 @@ object PreferKey {
const val launcherIcon = "launcherIcon"
const val selectText = "selectText"
const val lastBackup = "lastBackup"
const val bodyIndent = "textIndent"
}

@ -237,6 +237,8 @@ object BookHelp {
private var bookName: String? = null
private var bookOrigin: String? = null
private var replaceRules: List<ReplaceRule> = arrayListOf()
val bodyIndent
get() = " ".repeat(App.INSTANCE.getPrefInt(PreferKey.bodyIndent, 2))
fun disposeContent(
title: String,
@ -273,7 +275,6 @@ object BookHelp {
1 -> c = ZhConvertBootstrap.newInstance().toSimple(c)
2 -> c = ZhConvertBootstrap.newInstance().toTraditional(c)
}
val indent = App.INSTANCE.getPrefInt("textIndent", 2)
return c.replace("\\s*\\n+\\s*".toRegex(), "\n" + " ".repeat(indent))
return c.replace("\\s*\\n+\\s*".toRegex(), "\n$bodyIndent")
}
}

@ -7,6 +7,7 @@ import android.graphics.drawable.Drawable
import io.legado.app.App
import io.legado.app.R
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.ui.book.read.page.ChapterProvider
import io.legado.app.utils.*
import java.io.File
@ -22,6 +23,8 @@ object ReadBookConfig {
val json = String(App.INSTANCE.assets.open(readConfigFileName).readBytes())
GSON.fromJsonArray<Config>(json)!!
}
val durConfig
get() = getConfig(styleSelect)
var styleSelect
get() = App.INSTANCE.getPrefInt("readStyleSelect")
@ -33,7 +36,7 @@ object ReadBookConfig {
}
@Synchronized
fun getConfig(index: Int = styleSelect): Config {
fun getConfig(index: Int): Config {
if (configList.size < 5) {
resetAll()
}
@ -64,7 +67,7 @@ object ReadBookConfig {
val dm = resources.displayMetrics
val width = dm.widthPixels
val height = dm.heightPixels
bg = getConfig().bgDrawable(width, height)
bg = durConfig.bgDrawable(width, height)
}
fun save() {
@ -76,8 +79,8 @@ object ReadBookConfig {
fun resetDur() {
defaultConfigs[styleSelect].let {
getConfig().setBg(it.bgType(), it.bgStr())
getConfig().setTextColor(it.textColor())
durConfig.setBg(it.bgType(), it.bgStr())
durConfig.setTextColor(it.textColor())
upBg()
save()
}
@ -104,7 +107,7 @@ object ReadBookConfig {
var textSize: Int = 15,//文字大小
var letterSpacing: Float = 1f,//字间距
var lineSpacingExtra: Int = 12,//行间距
var lineSpacingMultiplier: Float = 1.2f,//行倍距
var paragraphSpacing: Int = 12,
var paddingBottom: Int = 6,
var paddingLeft: Int = 16,
var paddingRight: Int = 16,
@ -134,6 +137,7 @@ object ReadBookConfig {
} else {
textColor = "#${color.hexString}"
}
ChapterProvider.upStyle(this)
}
fun setStatusIconDark(isDark: Boolean) {

@ -56,7 +56,7 @@ object Help {
}
activity.window.decorView.systemUiVisibility = flag
if (toolBarHide) {
ATH.setLightStatusBar(activity, ReadBookConfig.getConfig().statusIconDark())
ATH.setLightStatusBar(activity, ReadBookConfig.durConfig.statusIconDark())
} else {
ATH.setLightStatusBarAuto(
activity,

@ -44,7 +44,6 @@ import io.legado.app.ui.replacerule.edit.ReplaceEditDialog
import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.utils.*
import kotlinx.android.synthetic.main.activity_book_read.*
import kotlinx.android.synthetic.main.view_book_page.*
import kotlinx.android.synthetic.main.view_read_menu.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
@ -117,7 +116,6 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
* 初始化View
*/
private fun initView() {
ChapterProvider.textView = content_text_view
tv_chapter_name.onClick {
ReadBook.webBook?.let {
startActivityForResult<BookSourceEditActivity>(
@ -446,7 +444,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
/**
* colorSelectDialog
*/
override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.getConfig()) {
override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.durConfig) {
when (dialogId) {
TEXT_COLOR -> {
setTextColor(color)
@ -507,7 +505,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
ReadBook.curTextChapter?.let { textChapter ->
val page = textChapter.page(ReadBook.durPageIndex)
if (page != null && page.text is SpannableStringBuilder) {
page.text.removeSpan(ChapterProvider.readAloudSpan)
page.removePageAloudSpan()
page_view.upContent()
}
}
@ -531,6 +529,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
content_view.upStyle()
page_view.upBg()
page_view.upStyle()
ChapterProvider.upStyle(ReadBookConfig.durConfig)
if (it) {
ReadBook.loadContent()
} else {

@ -81,7 +81,7 @@ class BgTextConfigDialog : DialogFragment() {
}
@SuppressLint("InflateParams")
private fun initData() = with(ReadBookConfig.getConfig()) {
private fun initData() = with(ReadBookConfig.durConfig) {
sw_dark_status_icon.isChecked = statusIconDark()
adapter = BgAdapter(requireContext())
recycler_view.layoutManager =
@ -99,7 +99,7 @@ class BgTextConfigDialog : DialogFragment() {
}
}
private fun initView() = with(ReadBookConfig.getConfig()) {
private fun initView() = with(ReadBookConfig.durConfig) {
sw_dark_status_icon.onCheckedChange { buttonView, isChecked ->
if (buttonView?.isPressed == true) {
setStatusIconDark(isChecked)
@ -156,7 +156,7 @@ class BgTextConfigDialog : DialogFragment() {
holder.itemView.apply {
this.onClick {
getItem(holder.layoutPosition)?.let {
ReadBookConfig.getConfig().setBg(1, it)
ReadBookConfig.durConfig.setBg(1, it)
ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false)
}
@ -180,7 +180,7 @@ class BgTextConfigDialog : DialogFragment() {
FileUtils.createFileIfNotExist(file.absolutePath + File.separator + "bg" + File.separator + doc.name)
DocumentUtils.readBytes(requireContext(), uri)?.let {
file.writeBytes(it)
ReadBookConfig.getConfig().setBg(2, file.absolutePath)
ReadBookConfig.durConfig.setBg(2, file.absolutePath)
ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false)
}
@ -194,7 +194,7 @@ class BgTextConfigDialog : DialogFragment() {
.rationale(R.string.bg_image_per)
.onGranted {
RealPathUtil.getPath(requireContext(), uri)?.let { path ->
ReadBookConfig.getConfig().setBg(2, path)
ReadBookConfig.durConfig.setBg(2, path)
ReadBookConfig.upBg()
postEvent(EventBus.UP_CONFIG, false)
}

@ -49,7 +49,7 @@ class PaddingConfigDialog : DialogFragment() {
ReadBookConfig.save()
}
private fun initData() = with(ReadBookConfig.getConfig()) {
private fun initData() = with(ReadBookConfig.durConfig) {
//正文
dsb_padding_top.progress = paddingTop
dsb_padding_bottom.progress = paddingBottom
@ -67,7 +67,7 @@ class PaddingConfigDialog : DialogFragment() {
dsb_footer_padding_right.progress = footerPaddingRight
}
private fun initView() = with(ReadBookConfig.getConfig()) {
private fun initView() = with(ReadBookConfig.durConfig) {
//正文
dsb_padding_top.onChanged = {
paddingTop = it

@ -91,7 +91,7 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack {
postEvent(EventBus.UP_CONFIG, true)
}
tv_text_bold.onClick {
with(ReadBookConfig.getConfig()) {
with(ReadBookConfig.durConfig) {
textBold = !textBold
tv_text_bold.isSelected = textBold
}
@ -105,7 +105,7 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack {
title = getString(R.string.text_indent),
items = resources.getStringArray(R.array.indent).toList()
) { _, index ->
putPrefInt("textIndent", index)
putPrefInt(PreferKey.bodyIndent, index)
postEvent(EventBus.UP_CONFIG, true)
}
}
@ -117,15 +117,19 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack {
}
}
dsb_text_size.onChanged = {
ReadBookConfig.getConfig().textSize = it + 5
ReadBookConfig.durConfig.textSize = it + 5
postEvent(EventBus.UP_CONFIG, true)
}
dsb_text_letter_spacing.onChanged = {
ReadBookConfig.getConfig().letterSpacing = (it - 5) / 10f
ReadBookConfig.durConfig.letterSpacing = (it - 5) / 10f
postEvent(EventBus.UP_CONFIG, true)
}
dsb_line_size.onChanged = {
ReadBookConfig.getConfig().lineSpacingExtra = it
ReadBookConfig.durConfig.lineSpacingExtra = it
postEvent(EventBus.UP_CONFIG, true)
}
dsb_paragraph_spacing.onChanged = {
ReadBookConfig.durConfig.paragraphSpacing = it
postEvent(EventBus.UP_CONFIG, true)
}
rg_page_anim.onCheckedChange { _, checkedId ->
@ -173,11 +177,12 @@ class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack {
}
private fun upStyle() {
ReadBookConfig.getConfig().let {
ReadBookConfig.durConfig.let {
tv_text_bold.isSelected = it.textBold
dsb_text_size.progress = it.textSize - 5
dsb_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5
dsb_line_size.progress = it.lineSpacingExtra
dsb_paragraph_spacing.progress = it.paragraphSpacing
}
}

@ -1,83 +1,261 @@
package io.legado.app.ui.book.read.page
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import androidx.core.text.HtmlCompat
import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT
import io.legado.app.App
import android.graphics.Point
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import io.legado.app.data.entities.BookChapter
import io.legado.app.lib.theme.accentColor
import io.legado.app.help.BookHelp
import io.legado.app.help.ReadBookConfig
import io.legado.app.ui.book.read.page.entities.TextChapter
import io.legado.app.ui.book.read.page.entities.TextChar
import io.legado.app.ui.book.read.page.entities.TextLine
import io.legado.app.ui.book.read.page.entities.TextPage
import io.legado.app.utils.dp
object ChapterProvider {
var readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor)
private val titleSpan = RelativeSizeSpan(1.2f)
var viewWidth = 0
var viewHeight = 0
private var visibleWidth = 0
private var visibleHeight = 0
private var paddingLeft = 0
private var paddingTop = 0
private var lineSpacingExtra = 0
private var paragraphSpacing = 0
var titlePaint = TextPaint()
var contentPaint = TextPaint()
var textView: ContentTextView? = null
init {
upStyle(ReadBookConfig.durConfig)
}
fun upStyle(config: ReadBookConfig.Config) {
titlePaint.color = config.textColor()
titlePaint.letterSpacing = config.letterSpacing
contentPaint.color = config.textColor()
contentPaint.letterSpacing = config.letterSpacing
lineSpacingExtra = config.lineSpacingExtra
paragraphSpacing = config.paragraphSpacing
titlePaint.textSize = (config.textSize + 2).dp.toFloat()
contentPaint.textSize = config.textSize.dp.toFloat()
upSize(config)
}
fun upSize(config: ReadBookConfig.Config) {
paddingLeft = config.paddingLeft.dp
paddingTop = config.paddingTop.dp
visibleWidth = viewWidth - paddingLeft - config.paddingRight.dp
visibleHeight = viewHeight - paddingTop - config.paddingBottom.dp
}
@Suppress("DEPRECATION")
fun getTextChapter(
bookChapter: BookChapter,
content: String,
chapterSize: Int,
isHtml: Boolean = false
): TextChapter {
textView?.let {
val bodyIndent = BookHelp.bodyIndent
val textPages = arrayListOf<TextPage>()
val pageLines = arrayListOf<Int>()
val pageLengths = arrayListOf<Int>()
var surplusText = content
var pageIndex = 0
var durY = 0
textPages.add(TextPage())
while (surplusText.isNotEmpty()) {
val spannableStringBuilder =
if (isHtml) {
HtmlCompat.fromHtml(
surplusText,
FROM_HTML_MODE_COMPACT
) as SpannableStringBuilder
if (textPages.first().textLines.isEmpty()) {
//title
val end = surplusText.indexOf("\n")
if (end > 0) {
val title = surplusText.substring(0, end)
surplusText = surplusText.substring(end + 1)
val layout = StaticLayout(
title, titlePaint, visibleWidth,
Layout.Alignment.ALIGN_NORMAL, 1f, lineSpacingExtra.toFloat(), false
)
for (lineIndex in 0 until layout.lineCount) {
durY = durY + layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex)
val textLine = TextLine(isTitle = true)
if (durY < visibleHeight) {
textPages.last().textLines.add(textLine)
} else {
durY = 0
textPages.add(TextPage())
textPages.last().textLines.add(textLine)
}
textLine.lineBottom = layout.getLineBottom(lineIndex)
textLine.lineTop = layout.getLineTop(lineIndex)
val words = title.substring(
layout.getLineStart(lineIndex),
layout.getLineEnd(lineIndex)
)
val desiredWidth = layout.getLineMax(lineIndex)
if (lineIndex != layout.lineCount - 1) {
val gapCount: Int = words.length - 1
val d = (visibleWidth - desiredWidth) / gapCount
var x = 0
for (i in words.indices) {
val char = words[i].toString()
val cw = StaticLayout.getDesiredWidth(char, titlePaint)
val x1 = if (i != words.lastIndex) {
(x + cw + d).toInt()
} else {
(x + cw).toInt()
}
val textChar = TextChar(
charData = char,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
textLine.textChars.add(textChar)
x = x1
}
} else {
SpannableStringBuilder(surplusText)
//最后一行
var x = 0
for (i in words.indices) {
val char = words[i].toString()
val cw = StaticLayout.getDesiredWidth(char, titlePaint)
val x1 = (x + cw).toInt()
val textChar = TextChar(
charData = char,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
textLine.textChars.add(textChar)
x = x1
}
if (pageIndex == 0) {
}
}
durY += paragraphSpacing
}
} else {
//正文
val end = surplusText.indexOf("\n")
if (end > 0) {
spannableStringBuilder.setSpan(
titleSpan,
0,
end,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
val text: String
if (end >= 0) {
text = surplusText.substring(0, end)
surplusText = surplusText.substring(end + 1)
} else {
text = surplusText
surplusText = ""
}
val layout = StaticLayout(
text, contentPaint, visibleWidth,
Layout.Alignment.ALIGN_NORMAL, 1f, lineSpacingExtra.toFloat(), false
)
for (lineIndex in 0 until layout.lineCount) {
val textLine = TextLine(isTitle = false)
durY = durY + layout.getLineBottom(lineIndex) - layout.getLineTop(lineIndex)
if (durY < visibleHeight) {
textPages.last().textLines.add(textLine)
} else {
durY = 0
textPages.add(TextPage())
textPages.last().textLines.add(textLine)
}
textLine.lineBottom = layout.getLineBottom(lineIndex)
textLine.lineTop = layout.getLineTop(lineIndex)
var words =
text.substring(layout.getLineStart(lineIndex), layout.getLineEnd(lineIndex))
val desiredWidth = layout.getLineMax(lineIndex)
if (lineIndex == 0 && layout.lineCount > 1) {
//第一行
var x = 0
val icw = StaticLayout.getDesiredWidth(bodyIndent, contentPaint)
var x1 = (x + icw).toInt()
val textChar = TextChar(
charData = bodyIndent,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
textLine.textChars.add(textChar)
x = x1
words = words.replaceFirst(bodyIndent, "")
val gapCount: Int = words.length - 1
val d = (visibleWidth - desiredWidth) / gapCount
for (i in words.indices) {
val char = words[i].toString()
val cw = StaticLayout.getDesiredWidth(char, contentPaint)
x1 = if (i != words.lastIndex) {
(x + cw + d).toInt()
} else {
(x + cw).toInt()
}
val textChar1 = TextChar(
charData = char,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
textLine.textChars.add(textChar1)
x = x1
}
} else if (lineIndex == layout.lineCount - 1) {
//最后一行
var x = 0
for (i in words.indices) {
val char = words[i].toString()
val cw = StaticLayout.getDesiredWidth(char, contentPaint)
val x1 = (x + cw).toInt()
val textChar = TextChar(
charData = char,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
textLine.textChars.add(textChar)
x = x1
}
it.text = spannableStringBuilder
val lastLine = it.getLineNum()
val lastCharNum = it.getCharNum(lastLine)
if (lastCharNum == 0) {
break
} else {
pageLines.add(lastLine)
pageLengths.add(lastCharNum)
textPages.add(
TextPage(
index = pageIndex,
text = spannableStringBuilder.delete(
lastCharNum,
spannableStringBuilder.length
),
title = bookChapter.title,
chapterSize = chapterSize,
chapterIndex = bookChapter.index
//中间行
val gapCount: Int = words.length - 1
val d = (visibleWidth - desiredWidth) / gapCount
var x = 0
for (i in words.indices) {
val char = words[i].toString()
val cw = StaticLayout.getDesiredWidth(char, contentPaint)
val x1 = if (i != words.lastIndex) {
(x + cw + d).toInt()
} else {
(x + cw).toInt()
}
val textChar = TextChar(
charData = char,
leftBottomPosition = Point(paddingLeft + x, paddingTop + durY),
rightTopPosition = Point(
paddingLeft + x1,
paddingTop + durY - (textLine.lineBottom - textLine.lineTop)
)
)
surplusText = surplusText.substring(lastCharNum)
pageIndex++
textLine.textChars.add(textChar)
x = x1
}
}
}
durY += paragraphSpacing
}
for (item in textPages) {
}
for ((index, item) in textPages.withIndex()) {
item.index = index
item.pageSize = textPages.size
item.chapterIndex = bookChapter.index
item.chapterSize = chapterSize
item.title = bookChapter.title
}
return TextChapter(
bookChapter.index,
@ -88,19 +266,5 @@ object ChapterProvider {
pageLengths,
chapterSize
)
} ?: return TextChapter(
bookChapter.index,
bookChapter.title,
bookChapter.url,
arrayListOf(),
arrayListOf(),
arrayListOf(),
chapterSize
)
}
fun upReadAloudSpan() {
readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor)
}
}

@ -1,11 +1,14 @@
package io.legado.app.ui.book.read.page
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import io.legado.app.ui.widget.text.InertiaScrollTextView
import android.view.View
import io.legado.app.help.ReadBookConfig
import io.legado.app.ui.book.read.page.entities.TextPage
class ContentTextView : InertiaScrollTextView {
class ContentTextView : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
@ -13,19 +16,45 @@ class ContentTextView : InertiaScrollTextView {
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int)
: super(context, attrs, defStyleAttr)
/**
* 获取当前页总字数
*/
fun getCharNum(lineNum: Int = getLineNum()): Int {
return layout?.getLineEnd(lineNum) ?: 0
var textPage: TextPage? = null
fun setContent(textPage: TextPage?) {
this.textPage = textPage
invalidate()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
ReadBookConfig.durConfig.let {
ChapterProvider.viewWidth = w
ChapterProvider.viewHeight = h
ChapterProvider.upSize(ReadBookConfig.durConfig)
}
}
/**
* 获取当前页总行数
*/
fun getLineNum(): Int {
val topOfLastLine = height - paddingTop - paddingBottom - lineHeight
return layout?.getLineForVertical(topOfLastLine) ?: 0
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
textPage?.let { textPage ->
textPage.textLines.forEach { textLine ->
textLine.textChars.forEach {
if (textLine.isTitle) {
canvas.drawText(
it.charData,
it.leftBottomPosition.x.toFloat(),
it.leftBottomPosition.y.toFloat(),
ChapterProvider.titlePaint
)
} else {
canvas.drawText(
it.charData,
it.leftBottomPosition.x.toFloat(),
it.leftBottomPosition.y.toFloat(),
ChapterProvider.contentPaint
)
}
}
}
}
}
}

@ -2,10 +2,8 @@ package io.legado.app.ui.book.read.page
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.Gravity
import android.widget.FrameLayout
import io.legado.app.R
import io.legado.app.constant.AppConst.TIME_FORMAT
@ -14,8 +12,6 @@ import io.legado.app.help.ReadBookConfig
import io.legado.app.ui.book.read.page.entities.TextPage
import io.legado.app.utils.*
import kotlinx.android.synthetic.main.view_book_page.view.*
import org.jetbrains.anko.sdk27.listeners.onScrollChange
import java.io.File
import java.util.*
@ -39,20 +35,10 @@ class ContentView : FrameLayout {
inflate(context, R.layout.view_book_page, this)
upStyle()
upTime()
content_text_view.customSelectionActionModeCallback =
ContentSelectActionCallback(content_text_view)
content_text_view.onScrollChange { _, _, scrollY, _, _ ->
content_text_view.layout?.getLineForVertical(scrollY)?.let { line ->
callBack?.scrollToLine(line)
}
if (content_text_view.atBottom()) {
callBack?.scrollToLast()
}
}
}
fun upStyle() {
ReadBookConfig.getConfig().apply {
ReadBookConfig.durConfig.apply {
val rootPaddingTop = if (context.getPrefBoolean(PreferKey.hideStatusBar, false)) {
//显示状态栏时隐藏header
ll_header.visible()
@ -82,30 +68,13 @@ class ContentView : FrameLayout {
footerPaddingRight.dp,
footerPaddingBottom.dp
)
content_text_view.textSize = textSize.toFloat()
content_text_view.setLineSpacing(lineSpacingExtra.toFloat(), lineSpacingMultiplier)
content_text_view.letterSpacing = letterSpacing
content_text_view.paint.isFakeBoldText = textBold
textColor().let {
content_text_view.setTextColor(it)
tv_top_left.setTextColor(it)
tv_top_right.setTextColor(it)
tv_bottom_left.setTextColor(it)
tv_bottom_right.setTextColor(it)
}
}
context.getPrefString(PreferKey.readBookFont)?.let {
if (it.isNotEmpty()) {
val file = File(it)
if (file.exists()) {
content_text_view.typeface = Typeface.createFromFile(it)
return@let
} else {
context.putPrefString(PreferKey.readBookFont, "")
}
}
content_text_view.typeface = Typeface.DEFAULT
}
}
fun setBg(bg: Drawable?) {
@ -121,15 +90,11 @@ class ContentView : FrameLayout {
}
fun setContent(textPage: TextPage?) {
content_text_view.setContent(textPage)
if (textPage != null) {
content_text_view.gravity = Gravity.START
content_text_view.text = textPage.text
tv_bottom_left.text = textPage.title
pageSize = textPage.pageSize
setPageIndex(textPage.index)
} else {
content_text_view.gravity = Gravity.CENTER
content_text_view.setText(R.string.data_loading)
}
}
@ -141,7 +106,7 @@ class ContentView : FrameLayout {
}
fun isTextSelected(): Boolean {
return content_text_view.selectionEnd - content_text_view.selectionStart != 0
return false
}
fun contentTextView(): ContentTextView? {
@ -151,19 +116,14 @@ class ContentView : FrameLayout {
fun scrollTo(pos: Int?) {
if (pos != null) {
content_text_view.post {
if (content_text_view.layout.lineCount >= pos) {
content_text_view.scrollTo(0, content_text_view.layout.getLineTop(pos))
}
}
}
}
fun scrollToBottom() {
content_text_view.post {
content_text_view.scrollTo(
0,
content_text_view.layout.getLineTop(content_text_view.lineCount)
)
}
}

@ -51,9 +51,9 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie
override fun upSelectAble() {
pageView.curPage.contentTextView()?.apply {
if (context.getPrefBoolean(PreferKey.selectText)) {
setTextIsSelectable(true)
// setTextIsSelectable(true)
} else {
setTextIsSelectable(false)
// setTextIsSelectable(false)
}
}
}

@ -192,8 +192,8 @@ abstract class PageDelegate(protected val pageView: PageView) {
if (event.action == MotionEvent.ACTION_DOWN) {
curPage.let {
it.contentTextView()?.let { contentTextView ->
atTop = contentTextView.atTop()
atBottom = contentTextView.atBottom()
// atTop = contentTextView.atTop()
// atBottom = contentTextView.atBottom()
}
it.dispatchTouchEvent(event)
}

@ -2,7 +2,6 @@ package io.legado.app.ui.book.read.page.delegate
import android.graphics.Canvas
import android.graphics.Matrix
import android.text.method.ScrollingMovementMethod
import android.view.MotionEvent
import io.legado.app.constant.PreferKey
import io.legado.app.ui.book.read.page.PageView
@ -122,10 +121,10 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) {
override fun upSelectAble() {
pageView.curPage.contentTextView()?.apply {
if (context.getPrefBoolean(PreferKey.selectText)) {
setTextIsSelectable(true)
// setTextIsSelectable(true)
} else {
setTextIsSelectable(false)
movementMethod = ScrollingMovementMethod.getInstance()
// setTextIsSelectable(false)
// movementMethod = ScrollingMovementMethod.getInstance()
}
}
}

@ -3,9 +3,8 @@ package io.legado.app.ui.book.read.page.entities
import android.graphics.Point
data class TextChar(
val charData: Char,
val charData: String,
var selected: Boolean = false,
var isReadAloud: Boolean = false,
val leftBottomPosition: Point,
val rightTopPosition: Point
)

@ -1,6 +1,9 @@
package io.legado.app.ui.book.read.page.entities
data class TextLine(
val textChars: List<TextChar>,
val lineBottom: Int
val textChars: ArrayList<TextChar> = arrayListOf(),
var lineTop: Int = 0,
var lineBottom: Int = 0,
val isTitle: Boolean = false,
var isReadAloud: Boolean = false
)

@ -1,40 +1,33 @@
package io.legado.app.ui.book.read.page.entities
import android.text.Spannable
import android.text.SpannableStringBuilder
import io.legado.app.App
import io.legado.app.R
import io.legado.app.ui.book.read.page.ChapterProvider
data class TextPage(
val index: Int,
val text: CharSequence = App.INSTANCE.getString(R.string.data_loading),
val title: String,
var index: Int = 0,
var text: CharSequence = App.INSTANCE.getString(R.string.data_loading),
var title: String = "",
val textLines: ArrayList<TextLine> = arrayListOf(),
var pageSize: Int = 0,
var chapterSize: Int = 0,
var chapterIndex: Int = 0
) {
fun removePageAloudSpan(): TextPage {
if (text is SpannableStringBuilder) {
text.removeSpan(ChapterProvider.readAloudSpan)
textLines.forEach { textLine ->
textLine.isReadAloud = false
}
return this
}
fun upPageAloudSpan(pageStart: Int) {
if (text is SpannableStringBuilder) {
text.removeSpan(ChapterProvider.readAloudSpan)
removePageAloudSpan()
var end = text.indexOf("\n", pageStart)
if (end == -1) end = text.length
var start = text.lastIndexOf("\n", pageStart)
if (start == -1) start = 0
text.setSpan(
ChapterProvider.readAloudSpan,
start,
end,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
}
}
}

@ -112,12 +112,22 @@
app:title="@string/line_size"
app:layout_constraintTop_toBottomOf="@+id/dsb_text_letter_spacing" />
<io.legado.app.ui.widget.DetailSeekBar
android:id="@+id/dsb_paragraph_spacing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
app:max="50"
app:title="@string/paragraph_size"
app:layout_constraintTop_toBottomOf="@+id/dsb_line_size" />
<View
android:id="@+id/vw_bg_fg"
android:layout_width="match_parent"
android:layout_height="0.8dp"
android:background="@color/btn_bg_press"
app:layout_constraintTop_toBottomOf="@+id/dsb_line_size" />
app:layout_constraintTop_toBottomOf="@+id/dsb_paragraph_spacing" />
<TextView
android:id="@+id/tv_page_anim"

Loading…
Cancel
Save