This commit is contained in:
Horis
2024-02-08 23:01:19 +08:00
parent 4537f1325a
commit 1111e36c41
8 changed files with 207 additions and 43 deletions
@@ -537,20 +537,33 @@ object ReadBookConfig {
var footerMode: Int = 0 var footerMode: Int = 0
) { ) {
private var textColorIntEInk = Color.parseColor(textColorEInk)
private var textColorIntNight = Color.parseColor(textColorNight)
private var textColorInt = Color.parseColor(textColor)
fun setCurTextColor(color: Int) { fun setCurTextColor(color: Int) {
when { when {
AppConfig.isEInkMode -> textColorEInk = "#${color.hexString}" AppConfig.isEInkMode -> {
AppConfig.isNightTheme -> textColorNight = "#${color.hexString}" textColorEInk = "#${color.hexString}"
else -> textColor = "#${color.hexString}" textColorIntEInk = color
}
AppConfig.isNightTheme -> {
textColorNight = "#${color.hexString}"
textColorIntNight = color
}
else -> {
textColor = "#${color.hexString}"
textColorInt = color
}
} }
ChapterProvider.upStyle() ChapterProvider.upStyle()
} }
fun curTextColor(): Int { fun curTextColor(): Int {
return when { return when {
AppConfig.isEInkMode -> Color.parseColor(textColorEInk) AppConfig.isEInkMode -> textColorIntEInk
AppConfig.isNightTheme -> Color.parseColor(textColorNight) AppConfig.isNightTheme -> textColorIntNight
else -> Color.parseColor(textColor) else -> textColorInt
} }
} }
@@ -15,13 +15,11 @@ 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.CacheBookService import io.legado.app.service.CacheBookService
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.startService import io.legado.app.utils.startService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@@ -3,11 +3,15 @@ package io.legado.app.ui.book.read.page
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Picture
import android.graphics.RectF import android.graphics.RectF
import android.os.Build
import android.util.AttributeSet import android.util.AttributeSet
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.core.graphics.record
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.PageAnim
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.Bookmark import io.legado.app.data.entities.Bookmark
import io.legado.app.help.book.isImage import io.legado.app.help.book.isImage
@@ -61,6 +65,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
//滚动参数 //滚动参数
private val pageFactory: TextPageFactory get() = callBack.pageFactory private val pageFactory: TextPageFactory get() = callBack.pageFactory
private var pageOffset = 0 private var pageOffset = 0
private lateinit var picture: Picture
private var pictureIsDirty = true
private val atLeastApi23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
private val isNoAnim get() = ReadBook.pageAnim() == PageAnim.noAnim
//绘制图片的paint //绘制图片的paint
private val imagePaint by lazy { private val imagePaint by lazy {
@@ -71,6 +79,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
init { init {
callBack = activity as CallBack callBack = activity as CallBack
if (atLeastApi23) {
picture = Picture()
}
} }
/** /**
@@ -108,7 +119,17 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
canvas.translate(0f, scrollY.toFloat()) canvas.translate(0f, scrollY.toFloat())
} }
canvas.clipRect(visibleRect) canvas.clipRect(visibleRect)
drawPage(canvas) if (atLeastApi23 && !callBack.isScroll && !isNoAnim) {
if (pictureIsDirty) {
pictureIsDirty = false
picture.record(width, height) {
drawPage(this)
}
}
canvas.drawPicture(picture)
} else {
drawPage(canvas)
}
} }
/** /**
@@ -288,6 +309,15 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
invalidate() invalidate()
} }
override fun invalidate() {
super.invalidate()
invalidatePicture()
}
private fun invalidatePicture() {
pictureIsDirty = true
}
/** /**
* 重置滚动位置 * 重置滚动位置
*/ */
@@ -104,7 +104,6 @@ class ReadView(context: Context, attrs: AttributeSet) :
addView(nextPage) addView(nextPage)
addView(curPage) addView(curPage)
addView(prevPage) addView(prevPage)
nextPage.invisible()
prevPage.invisible() prevPage.invisible()
curPage.markAsMainView() curPage.markAsMainView()
if (!isInEditMode) { if (!isInEditMode) {
@@ -516,6 +515,12 @@ class ReadView(context: Context, attrs: AttributeSet) :
} }
} }
(pageDelegate as? ScrollPageDelegate)?.noAnim = AppConfig.noAnimScrollPage (pageDelegate as? ScrollPageDelegate)?.noAnim = AppConfig.noAnimScrollPage
pageDelegate?.setViewSize(width, height)
if (pageDelegate is NoAnimPageDelegate) {
nextPage.invisible()
} else {
nextPage.visible()
}
} }
/** /**
@@ -2,7 +2,11 @@ package io.legado.app.ui.book.read.page.delegate
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.Picture
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.os.Build
import androidx.core.graphics.withClip
import androidx.core.graphics.withTranslation
import io.legado.app.ui.book.read.page.ReadView import io.legado.app.ui.book.read.page.ReadView
import io.legado.app.ui.book.read.page.entities.PageDirection import io.legado.app.ui.book.read.page.entities.PageDirection
import io.legado.app.utils.screenshot import io.legado.app.utils.screenshot
@@ -11,12 +15,23 @@ class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
private val bitmapMatrix = Matrix() private val bitmapMatrix = Matrix()
private val shadowDrawableR: GradientDrawable private val shadowDrawableR: GradientDrawable
private lateinit var curPicture: Picture
private lateinit var prevPicture: Picture
private lateinit var nextPicture: Picture
private val atLeastApi23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
init { init {
val shadowColors = intArrayOf(0x66111111, 0x00000000) val shadowColors = intArrayOf(0x66111111, 0x00000000)
shadowDrawableR = GradientDrawable( shadowDrawableR = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, shadowColors GradientDrawable.Orientation.LEFT_RIGHT, shadowColors
) )
shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT
if (atLeastApi23) {
curPicture = Picture()
prevPicture = Picture()
nextPicture = Picture()
}
} }
override fun onDraw(canvas: Canvas) { override fun onDraw(canvas: Canvas) {
@@ -32,52 +47,84 @@ class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth
if (mDirection == PageDirection.PREV) { if (mDirection == PageDirection.PREV) {
if (offsetX <= viewWidth) { if (offsetX <= viewWidth) {
bitmapMatrix.setTranslate(distanceX, 0.toFloat()) if (!atLeastApi23) {
prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } bitmapMatrix.setTranslate(distanceX, 0.toFloat())
addShadow(distanceX.toInt(), canvas) prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
} else {
canvas.withTranslation(distanceX) {
drawPicture(prevPicture)
}
}
addShadow(distanceX, canvas)
} else { } else {
prevBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) } if (!atLeastApi23) {
} prevBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
} else if (mDirection == PageDirection.NEXT) { } else {
bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat()) canvas.drawPicture(prevPicture)
nextBitmap?.let {
canvas.apply {
save()
val width = it.width.toFloat()
val height = it.height.toFloat()
clipRect(width + offsetX, 0f, width, height)
drawBitmap(it, 0f, 0f, null)
restore()
} }
} }
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } } else if (mDirection == PageDirection.NEXT) {
addShadow(distanceX.toInt(), canvas) if (!atLeastApi23) {
bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat())
nextBitmap?.let {
val width = it.width.toFloat()
val height = it.height.toFloat()
canvas.withClip(width + offsetX, 0f, width, height) {
drawBitmap(it, 0f, 0f, null)
}
}
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
} else {
val width = nextPicture.width.toFloat()
val height = nextPicture.height.toFloat()
canvas.withClip(width + offsetX, 0f, width, height) {
drawPicture(nextPicture)
}
canvas.withTranslation(distanceX - viewWidth) {
drawPicture(curPicture)
}
}
addShadow(distanceX, canvas)
} }
} }
override fun setBitmap() { override fun setBitmap() {
when (mDirection) { when (mDirection) {
PageDirection.PREV -> { PageDirection.PREV -> if (!atLeastApi23) {
prevBitmap = prevPage.screenshot(prevBitmap, canvas) prevBitmap = prevPage.screenshot(prevBitmap, canvas)
} else {
prevPage.screenshot(prevPicture)
} }
PageDirection.NEXT -> {
PageDirection.NEXT -> if (!atLeastApi23) {
nextBitmap = nextPage.screenshot(nextBitmap, canvas) nextBitmap = nextPage.screenshot(nextBitmap, canvas)
curBitmap = curPage.screenshot(curBitmap, canvas) curBitmap = curPage.screenshot(curBitmap, canvas)
} else {
nextPage.screenshot(nextPicture)
curPage.screenshot(curPicture)
} }
else -> Unit else -> Unit
} }
} }
private fun addShadow(left: Int, canvas: Canvas) { private fun addShadow(left: Float, canvas: Canvas) {
if (left < 0) { if (left == 0f) return
shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) val dx = if (left < 0) {
shadowDrawableR.draw(canvas) left + viewWidth
} else if (left > 0) { } else {
shadowDrawableR.setBounds(left, 0, left + 30, viewHeight) left
}
canvas.withTranslation(dx) {
shadowDrawableR.draw(canvas) shadowDrawableR.draw(canvas)
} }
} }
override fun setViewSize(width: Int, height: Int) {
super.setViewSize(width, height)
shadowDrawableR.setBounds(0, 0, 30, viewHeight)
}
override fun onAnimStop() { override fun onAnimStop() {
if (!isCancel) { if (!isCancel) {
readView.fillPage(mDirection) readView.fillPage(mDirection)
@@ -97,6 +144,7 @@ class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
} else { } else {
-(touchX + (viewWidth - startX)) -(touchX + (viewWidth - startX))
} }
else -> distanceX = else -> distanceX =
if (isCancel) { if (isCancel) {
-(touchX - startX) -(touchX - startX)
@@ -90,6 +90,7 @@ abstract class PageDelegate(protected val readView: ReadView) {
} }
} }
@CallSuper
open fun setViewSize(width: Int, height: Int) { open fun setViewSize(width: Int, height: Int) {
viewWidth = width viewWidth = width
viewHeight = height viewHeight = height
@@ -2,13 +2,50 @@ package io.legado.app.ui.book.read.page.delegate
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.Picture
import android.os.Build
import androidx.core.graphics.withTranslation
import io.legado.app.ui.book.read.page.ReadView import io.legado.app.ui.book.read.page.ReadView
import io.legado.app.ui.book.read.page.entities.PageDirection import io.legado.app.ui.book.read.page.entities.PageDirection
import io.legado.app.utils.screenshot
class SlidePageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) { class SlidePageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
private val bitmapMatrix = Matrix() private val bitmapMatrix = Matrix()
private lateinit var curPicture: Picture
private lateinit var prevPicture: Picture
private lateinit var nextPicture: Picture
private val atLeastApi23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
init {
if (atLeastApi23) {
curPicture = Picture()
prevPicture = Picture()
nextPicture = Picture()
}
}
override fun setBitmap() {
if (!atLeastApi23) {
return super.setBitmap()
}
when (mDirection) {
PageDirection.PREV -> {
prevPage.screenshot(prevPicture)
curPage.screenshot(curPicture)
}
PageDirection.NEXT -> {
nextPage.screenshot(nextPicture)
curPage.screenshot(curPicture)
}
else -> Unit
}
}
override fun onAnimStart(animationSpeed: Int) { override fun onAnimStart(animationSpeed: Int) {
val distanceX: Float val distanceX: Float
when (mDirection) { when (mDirection) {
@@ -22,6 +59,7 @@ class SlidePageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
} else { } else {
-(touchX + (viewWidth - startX)) -(touchX + (viewWidth - startX))
} }
else -> distanceX = else -> distanceX =
if (isCancel) { if (isCancel) {
-(touchX - startX) -(touchX - startX)
@@ -41,15 +79,33 @@ class SlidePageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth
if (!isRunning) return if (!isRunning) return
if (mDirection == PageDirection.PREV) { if (mDirection == PageDirection.PREV) {
bitmapMatrix.setTranslate(distanceX + viewWidth, 0.toFloat()) if (!atLeastApi23) {
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } bitmapMatrix.setTranslate(distanceX + viewWidth, 0.toFloat())
bitmapMatrix.setTranslate(distanceX, 0.toFloat()) curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } bitmapMatrix.setTranslate(distanceX, 0.toFloat())
prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
} else {
canvas.withTranslation(distanceX + viewWidth) {
drawPicture(curPicture)
}
canvas.withTranslation(distanceX) {
drawPicture(prevPicture)
}
}
} else if (mDirection == PageDirection.NEXT) { } else if (mDirection == PageDirection.NEXT) {
bitmapMatrix.setTranslate(distanceX, 0.toFloat()) if (!atLeastApi23) {
nextBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } bitmapMatrix.setTranslate(distanceX, 0.toFloat())
bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat()) nextBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) } bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat())
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
} else {
canvas.withTranslation(distanceX) {
drawPicture(nextPicture)
}
canvas.withTranslation(distanceX - viewWidth) {
drawPicture(curPicture)
}
}
} }
} }
@@ -7,6 +7,7 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.Picture
import android.os.Build import android.os.Build
import android.text.Html import android.text.Html
import android.view.MotionEvent import android.view.MotionEvent
@@ -25,6 +26,8 @@ import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.menu.MenuPopupHelper import androidx.appcompat.view.menu.MenuPopupHelper
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.record
import androidx.core.graphics.withTranslation
import androidx.core.view.get import androidx.core.view.get
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
@@ -163,6 +166,16 @@ fun View.screenshot(bitmap: Bitmap? = null, canvas: Canvas? = null): Bitmap? {
} }
} }
fun View.screenshot(picture: Picture) {
if (width > 0 && height > 0) {
picture.record(width, height) {
withTranslation(-scrollX.toFloat(), -scrollY.toFloat()) {
draw(this)
}
}
}
}
fun View.setPaddingBottom(bottom: Int) { fun View.setPaddingBottom(bottom: Int) {
setPadding(paddingLeft, paddingTop, paddingRight, bottom) setPadding(paddingLeft, paddingTop, paddingRight, bottom)
} }