优化
This commit is contained in:
@@ -567,7 +567,6 @@ object ReadBookConfig {
|
|||||||
textColorInt = color
|
textColorInt = color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChapterProvider.upStyle()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun curTextColor(): Int {
|
fun curTextColor(): Int {
|
||||||
|
|||||||
@@ -274,10 +274,10 @@ object ReadBook : CoroutineScope by MainScope() {
|
|||||||
if (textChapter != null) {
|
if (textChapter != null) {
|
||||||
val pageIndex = durPageIndex
|
val pageIndex = durPageIndex
|
||||||
if (index > pageIndex) {
|
if (index > pageIndex) {
|
||||||
textChapter.getPage(index - 2)?.recyclePictures()
|
textChapter.getPage(index - 2)?.recycleRecorders()
|
||||||
}
|
}
|
||||||
if (index < pageIndex) {
|
if (index < pageIndex) {
|
||||||
textChapter.getPage(index + 3)?.recyclePictures()
|
textChapter.getPage(index + 3)?.recycleRecorders()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
durChapterPos = curTextChapter?.getReadLength(index) ?: index
|
durChapterPos = curTextChapter?.getReadLength(index) ?: index
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Intent
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Looper
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.InputDevice
|
import android.view.InputDevice
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
@@ -76,6 +77,7 @@ import io.legado.app.ui.book.read.config.TipConfigDialog.Companion.TIP_DIVIDER_C
|
|||||||
import io.legado.app.ui.book.read.page.ContentTextView
|
import io.legado.app.ui.book.read.page.ContentTextView
|
||||||
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.ui.book.read.page.provider.ChapterProvider
|
||||||
import io.legado.app.ui.book.searchContent.SearchContentActivity
|
import io.legado.app.ui.book.searchContent.SearchContentActivity
|
||||||
import io.legado.app.ui.book.searchContent.SearchResult
|
import io.legado.app.ui.book.searchContent.SearchResult
|
||||||
import io.legado.app.ui.book.source.edit.BookSourceEditActivity
|
import io.legado.app.ui.book.source.edit.BookSourceEditActivity
|
||||||
@@ -116,7 +118,6 @@ import io.legado.app.utils.toastOnUi
|
|||||||
import io.legado.app.utils.visible
|
import io.legado.app.utils.visible
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.asExecutor
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -217,7 +218,6 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
private val prevPageDebounce by lazy { Debounce { keyPage(PageDirection.PREV) } }
|
private val prevPageDebounce by lazy { Debounce { keyPage(PageDirection.PREV) } }
|
||||||
private var bookChanged = false
|
private var bookChanged = false
|
||||||
private var pageChanged = false
|
private var pageChanged = false
|
||||||
private var reloadContent = false
|
|
||||||
private val handler by lazy { buildMainHandler() }
|
private val handler by lazy { buildMainHandler() }
|
||||||
private val screenOffRunnable by lazy { Runnable { keepScreenOn(false) } }
|
private val screenOffRunnable by lazy { Runnable { keepScreenOn(false) } }
|
||||||
private val executor = ReadBook.executor
|
private val executor = ReadBook.executor
|
||||||
@@ -264,23 +264,9 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
|
|
||||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
override fun onPostCreate(savedInstanceState: Bundle?) {
|
||||||
super.onPostCreate(savedInstanceState)
|
super.onPostCreate(savedInstanceState)
|
||||||
viewModel.initData(intent) {
|
Looper.myQueue().addIdleHandler {
|
||||||
initDataSuccess()
|
viewModel.initData(intent) { upMenu() }
|
||||||
}
|
false
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
viewModel.initData(intent ?: return) {
|
|
||||||
initDataSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initDataSuccess() {
|
|
||||||
upMenu()
|
|
||||||
if (reloadContent) {
|
|
||||||
reloadContent = false
|
|
||||||
ReadBook.loadContent(resetPageOffset = false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1312,24 +1298,24 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
when (dialogId) {
|
when (dialogId) {
|
||||||
TEXT_COLOR -> {
|
TEXT_COLOR -> {
|
||||||
setCurTextColor(color)
|
setCurTextColor(color)
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2, 6))
|
||||||
}
|
}
|
||||||
|
|
||||||
BG_COLOR -> {
|
BG_COLOR -> {
|
||||||
setCurBg(0, "#${color.hexString}")
|
setCurBg(0, "#${color.hexString}")
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
TIP_COLOR -> {
|
TIP_COLOR -> {
|
||||||
ReadTipConfig.tipColor = color
|
ReadTipConfig.tipColor = color
|
||||||
postEvent(EventBus.TIP_COLOR, "")
|
postEvent(EventBus.TIP_COLOR, "")
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
TIP_DIVIDER_COLOR -> {
|
TIP_DIVIDER_COLOR -> {
|
||||||
ReadTipConfig.tipDividerColor = color
|
ReadTipConfig.tipDividerColor = color
|
||||||
postEvent(EventBus.TIP_COLOR, "")
|
postEvent(EventBus.TIP_COLOR, "")
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1493,22 +1479,21 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
ReadBook.readAloud(!BaseReadAloudService.pause)
|
ReadBook.readAloud(!BaseReadAloudService.pause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
observeEvent<Boolean>(EventBus.UP_CONFIG) {
|
observeEvent<Array<Int>>(EventBus.UP_CONFIG) {
|
||||||
upSystemUiVisibility()
|
it.forEach { value ->
|
||||||
readView.upPageSlopSquare()
|
when (value) {
|
||||||
readView.upBg()
|
0 -> upSystemUiVisibility()
|
||||||
readView.upStyle()
|
1 -> readView.upBg()
|
||||||
readView.upBgAlpha()
|
2 -> readView.upStyle()
|
||||||
if (it) { // 更新内容排版布局
|
3 -> readView.upBgAlpha()
|
||||||
if (isInitFinish) {
|
4 -> readView.upPageSlopSquare()
|
||||||
ReadBook.loadContent(resetPageOffset = false)
|
5 -> if (isInitFinish) ReadBook.loadContent(resetPageOffset = false)
|
||||||
} else {
|
6 -> readView.upContent(resetPageOffset = false)
|
||||||
reloadContent = true
|
8 -> ChapterProvider.upStyle()
|
||||||
|
9 -> binding.readView.invalidateTextPage()
|
||||||
|
10 -> ChapterProvider.upLayout()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
readView.upContent(resetPageOffset = false)
|
|
||||||
}
|
}
|
||||||
binding.readMenu.reset()
|
|
||||||
}
|
}
|
||||||
observeEvent<Int>(EventBus.ALOUD_STATE) {
|
observeEvent<Int>(EventBus.ALOUD_STATE) {
|
||||||
if (it == Status.STOP || it == Status.PAUSE) {
|
if (it == Status.STOP || it == Status.PAUSE) {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class BgAdapter(context: Context, val textColor: Int) :
|
|||||||
this.setOnClickListener {
|
this.setOnClickListener {
|
||||||
getItemByLayoutPosition(holder.layoutPosition)?.let {
|
getItemByLayoutPosition(holder.layoutPosition)?.let {
|
||||||
ReadBookConfig.durConfig.setCurBg(1, it)
|
ReadBookConfig.durConfig.setCurBg(1, it)
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,11 +33,32 @@ import io.legado.app.lib.theme.getSecondaryTextColor
|
|||||||
import io.legado.app.ui.book.read.ReadBookActivity
|
import io.legado.app.ui.book.read.ReadBookActivity
|
||||||
import io.legado.app.ui.file.HandleFileContract
|
import io.legado.app.ui.file.HandleFileContract
|
||||||
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
|
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.ColorUtils
|
||||||
|
import io.legado.app.utils.FileUtils
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
|
import io.legado.app.utils.MD5Utils
|
||||||
|
import io.legado.app.utils.SelectImageContract
|
||||||
import io.legado.app.utils.compress.ZipUtils
|
import io.legado.app.utils.compress.ZipUtils
|
||||||
|
import io.legado.app.utils.createFileReplace
|
||||||
|
import io.legado.app.utils.createFolderReplace
|
||||||
|
import io.legado.app.utils.externalCache
|
||||||
|
import io.legado.app.utils.externalFiles
|
||||||
|
import io.legado.app.utils.getFile
|
||||||
|
import io.legado.app.utils.inputStream
|
||||||
|
import io.legado.app.utils.isContentScheme
|
||||||
|
import io.legado.app.utils.launch
|
||||||
|
import io.legado.app.utils.longToast
|
||||||
|
import io.legado.app.utils.openOutputStream
|
||||||
|
import io.legado.app.utils.outputStream
|
||||||
|
import io.legado.app.utils.parseToUri
|
||||||
|
import io.legado.app.utils.postEvent
|
||||||
|
import io.legado.app.utils.printOnDebug
|
||||||
|
import io.legado.app.utils.readBytes
|
||||||
|
import io.legado.app.utils.readUri
|
||||||
|
import io.legado.app.utils.stackTraceStr
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
@@ -168,7 +189,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
ReadBookConfig.durConfig = defaultConfigs[i].copy()
|
ReadBookConfig.durConfig = defaultConfigs[i].copy()
|
||||||
initData()
|
initData()
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1, 2, 5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +199,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
}
|
}
|
||||||
binding.swUnderline.setOnCheckedChangeListener { _, isChecked ->
|
binding.swUnderline.setOnCheckedChangeListener { _, isChecked ->
|
||||||
underline = isChecked
|
underline = isChecked
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(9))
|
||||||
}
|
}
|
||||||
binding.tvTextColor.setOnClickListener {
|
binding.tvTextColor.setOnClickListener {
|
||||||
ColorPickerDialog.newBuilder()
|
ColorPickerDialog.newBuilder()
|
||||||
@@ -214,7 +235,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
}
|
}
|
||||||
binding.ivDelete.setOnClickListener {
|
binding.ivDelete.setOnClickListener {
|
||||||
if (ReadBookConfig.deleteDur()) {
|
if (ReadBookConfig.deleteDur()) {
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1, 2, 5))
|
||||||
dismissAllowingStateLoss()
|
dismissAllowingStateLoss()
|
||||||
} else {
|
} else {
|
||||||
toastOnUi("数量已是最少,不能删除.")
|
toastOnUi("数量已是最少,不能删除.")
|
||||||
@@ -223,11 +244,11 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
binding.sbBgAlpha.setOnSeekBarChangeListener(object : SeekBarChangeListener {
|
binding.sbBgAlpha.setOnSeekBarChangeListener(object : SeekBarChangeListener {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||||
ReadBookConfig.bgAlpha = progress
|
ReadBookConfig.bgAlpha = progress
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(3))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
override fun onStopTrackingTouch(seekBar: SeekBar) {
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(3))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -357,7 +378,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
ReadBookConfig.import(byteArray).getOrThrow()
|
ReadBookConfig.import(byteArray).getOrThrow()
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
ReadBookConfig.durConfig = it
|
ReadBookConfig.durConfig = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1, 2, 5))
|
||||||
toastOnUi("导入成功")
|
toastOnUi("导入成功")
|
||||||
}.onError {
|
}.onError {
|
||||||
it.printOnDebug()
|
it.printOnDebug()
|
||||||
@@ -378,7 +399,7 @@ class BgTextConfigDialog : BaseDialogFragment(R.layout.dialog_read_bg_text) {
|
|||||||
inputStream.copyTo(outputStream)
|
inputStream.copyTo(outputStream)
|
||||||
}
|
}
|
||||||
ReadBookConfig.durConfig.setCurBg(2, fileName)
|
ReadBookConfig.durConfig.setCurBg(2, fileName)
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1))
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
appCtx.toastOnUi(it.localizedMessage)
|
appCtx.toastOnUi(it.localizedMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,39 +107,48 @@ class MoreConfigDialog : DialogFragment() {
|
|||||||
PreferKey.readBodyToLh -> activity?.recreate()
|
PreferKey.readBodyToLh -> activity?.recreate()
|
||||||
PreferKey.hideStatusBar -> {
|
PreferKey.hideStatusBar -> {
|
||||||
ReadBookConfig.hideStatusBar = getPrefBoolean(PreferKey.hideStatusBar)
|
ReadBookConfig.hideStatusBar = getPrefBoolean(PreferKey.hideStatusBar)
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.hideNavigationBar -> {
|
PreferKey.hideNavigationBar -> {
|
||||||
ReadBookConfig.hideNavigationBar = getPrefBoolean(PreferKey.hideNavigationBar)
|
ReadBookConfig.hideNavigationBar = getPrefBoolean(PreferKey.hideNavigationBar)
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.keepLight -> postEvent(key, true)
|
PreferKey.keepLight -> postEvent(key, true)
|
||||||
PreferKey.textSelectAble -> postEvent(key, getPrefBoolean(key))
|
PreferKey.textSelectAble -> postEvent(key, getPrefBoolean(key))
|
||||||
PreferKey.screenOrientation -> {
|
PreferKey.screenOrientation -> {
|
||||||
(activity as? ReadBookActivity)?.setOrientation()
|
(activity as? ReadBookActivity)?.setOrientation()
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.textFullJustify,
|
PreferKey.textFullJustify,
|
||||||
PreferKey.textBottomJustify,
|
PreferKey.textBottomJustify,
|
||||||
PreferKey.useZhLayout -> {
|
PreferKey.useZhLayout -> {
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(5))
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.showBrightnessView -> {
|
PreferKey.showBrightnessView -> {
|
||||||
postEvent(PreferKey.showBrightnessView, "")
|
postEvent(PreferKey.showBrightnessView, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.expandTextMenu -> {
|
PreferKey.expandTextMenu -> {
|
||||||
(activity as? ReadBookActivity)?.textActionMenu?.upMenu()
|
(activity as? ReadBookActivity)?.textActionMenu?.upMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.doublePageHorizontal -> {
|
PreferKey.doublePageHorizontal -> {
|
||||||
ChapterProvider.upLayout()
|
ChapterProvider.upLayout()
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.showReadTitleAddition,
|
PreferKey.showReadTitleAddition,
|
||||||
PreferKey.readBarStyleFollowPage -> {
|
PreferKey.readBarStyleFollowPage -> {
|
||||||
postEvent(EventBus.UPDATE_READ_ACTION_BAR, true)
|
postEvent(EventBus.UPDATE_READ_ACTION_BAR, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.progressBarBehavior -> {
|
PreferKey.progressBarBehavior -> {
|
||||||
postEvent(EventBus.UP_SEEK_BAR, true)
|
postEvent(EventBus.UP_SEEK_BAR, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.noAnimScrollPage -> {
|
PreferKey.noAnimScrollPage -> {
|
||||||
ReadBook.callBack?.upPageAnim()
|
ReadBook.callBack?.upPageAnim()
|
||||||
}
|
}
|
||||||
@@ -152,6 +161,7 @@ class MoreConfigDialog : DialogFragment() {
|
|||||||
"clickRegionalConfig" -> {
|
"clickRegionalConfig" -> {
|
||||||
(activity as? ReadBookActivity)?.showClickRegionalConfig()
|
(activity as? ReadBookActivity)?.showClickRegionalConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferKey.pageTouchSlop -> {
|
PreferKey.pageTouchSlop -> {
|
||||||
NumberPickerDialog(requireContext())
|
NumberPickerDialog(requireContext())
|
||||||
.setTitle(getString(R.string.page_touch_slop_dialog_title))
|
.setTitle(getString(R.string.page_touch_slop_dialog_title))
|
||||||
@@ -160,7 +170,7 @@ class MoreConfigDialog : DialogFragment() {
|
|||||||
.setValue(AppConfig.pageTouchSlop)
|
.setValue(AppConfig.pageTouchSlop)
|
||||||
.show {
|
.show {
|
||||||
AppConfig.pageTouchSlop = it
|
AppConfig.pageTouchSlop = it
|
||||||
postEvent(EventBus.UP_CONFIG, false)
|
postEvent(EventBus.UP_CONFIG, arrayOf(4))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,61 +63,61 @@ class PaddingConfigDialog : BaseDialogFragment(R.layout.dialog_read_padding) {
|
|||||||
//正文
|
//正文
|
||||||
dsbPaddingTop.onChanged = {
|
dsbPaddingTop.onChanged = {
|
||||||
ReadBookConfig.paddingTop = it
|
ReadBookConfig.paddingTop = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(10, 5))
|
||||||
}
|
}
|
||||||
dsbPaddingBottom.onChanged = {
|
dsbPaddingBottom.onChanged = {
|
||||||
ReadBookConfig.paddingBottom = it
|
ReadBookConfig.paddingBottom = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(10, 5))
|
||||||
}
|
}
|
||||||
dsbPaddingLeft.onChanged = {
|
dsbPaddingLeft.onChanged = {
|
||||||
ReadBookConfig.paddingLeft = it
|
ReadBookConfig.paddingLeft = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(10, 5))
|
||||||
}
|
}
|
||||||
dsbPaddingRight.onChanged = {
|
dsbPaddingRight.onChanged = {
|
||||||
ReadBookConfig.paddingRight = it
|
ReadBookConfig.paddingRight = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(10, 5))
|
||||||
}
|
}
|
||||||
//页眉
|
//页眉
|
||||||
dsbHeaderPaddingTop.onChanged = {
|
dsbHeaderPaddingTop.onChanged = {
|
||||||
ReadBookConfig.headerPaddingTop = it
|
ReadBookConfig.headerPaddingTop = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbHeaderPaddingBottom.onChanged = {
|
dsbHeaderPaddingBottom.onChanged = {
|
||||||
ReadBookConfig.headerPaddingBottom = it
|
ReadBookConfig.headerPaddingBottom = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbHeaderPaddingLeft.onChanged = {
|
dsbHeaderPaddingLeft.onChanged = {
|
||||||
ReadBookConfig.headerPaddingLeft = it
|
ReadBookConfig.headerPaddingLeft = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbHeaderPaddingRight.onChanged = {
|
dsbHeaderPaddingRight.onChanged = {
|
||||||
ReadBookConfig.headerPaddingRight = it
|
ReadBookConfig.headerPaddingRight = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
//页脚
|
//页脚
|
||||||
dsbFooterPaddingTop.onChanged = {
|
dsbFooterPaddingTop.onChanged = {
|
||||||
ReadBookConfig.footerPaddingTop = it
|
ReadBookConfig.footerPaddingTop = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbFooterPaddingBottom.onChanged = {
|
dsbFooterPaddingBottom.onChanged = {
|
||||||
ReadBookConfig.footerPaddingBottom = it
|
ReadBookConfig.footerPaddingBottom = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbFooterPaddingLeft.onChanged = {
|
dsbFooterPaddingLeft.onChanged = {
|
||||||
ReadBookConfig.footerPaddingLeft = it
|
ReadBookConfig.footerPaddingLeft = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
dsbFooterPaddingRight.onChanged = {
|
dsbFooterPaddingRight.onChanged = {
|
||||||
ReadBookConfig.footerPaddingRight = it
|
ReadBookConfig.footerPaddingRight = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
cbShowTopLine.onCheckedChangeListener = { _, isChecked ->
|
cbShowTopLine.onCheckedChangeListener = { _, isChecked ->
|
||||||
ReadBookConfig.showHeaderLine = isChecked
|
ReadBookConfig.showHeaderLine = isChecked
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
cbShowBottomLine.onCheckedChangeListener = { _, isChecked ->
|
cbShowBottomLine.onCheckedChangeListener = { _, isChecked ->
|
||||||
ReadBookConfig.showFooterLine = isChecked
|
ReadBookConfig.showFooterLine = isChecked
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,10 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
|
|||||||
private fun initViewEvent() = binding.run {
|
private fun initViewEvent() = binding.run {
|
||||||
chineseConverter.onChanged {
|
chineseConverter.onChanged {
|
||||||
ChineseUtils.unLoad(*TransType.entries.toTypedArray())
|
ChineseUtils.unLoad(*TransType.entries.toTypedArray())
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(5))
|
||||||
}
|
}
|
||||||
textFontWeightConverter.onChanged {
|
textFontWeightConverter.onChanged {
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8))
|
||||||
}
|
}
|
||||||
tvTextFont.setOnClickListener {
|
tvTextFont.setOnClickListener {
|
||||||
showDialogFragment<FontSelectDialog>()
|
showDialogFragment<FontSelectDialog>()
|
||||||
@@ -122,7 +122,7 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
|
|||||||
items = resources.getStringArray(R.array.indent).toList()
|
items = resources.getStringArray(R.array.indent).toList()
|
||||||
) { _, index ->
|
) { _, index ->
|
||||||
ReadBookConfig.paragraphIndent = " ".repeat(index)
|
ReadBookConfig.paragraphIndent = " ".repeat(index)
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tvPadding.setOnClickListener {
|
tvPadding.setOnClickListener {
|
||||||
@@ -141,40 +141,40 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
|
|||||||
cbShareLayout.onCheckedChangeListener = { _, isChecked ->
|
cbShareLayout.onCheckedChangeListener = { _, isChecked ->
|
||||||
ReadBookConfig.shareLayout = isChecked
|
ReadBookConfig.shareLayout = isChecked
|
||||||
upView()
|
upView()
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1, 2, 5))
|
||||||
}
|
}
|
||||||
dsbTextSize.onChanged = {
|
dsbTextSize.onChanged = {
|
||||||
ReadBookConfig.textSize = it + 5
|
ReadBookConfig.textSize = it + 5
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
dsbTextLetterSpacing.onChanged = {
|
dsbTextLetterSpacing.onChanged = {
|
||||||
ReadBookConfig.letterSpacing = (it - 50) / 100f
|
ReadBookConfig.letterSpacing = (it - 50) / 100f
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
dsbLineSize.onChanged = {
|
dsbLineSize.onChanged = {
|
||||||
ReadBookConfig.lineSpacingExtra = it
|
ReadBookConfig.lineSpacingExtra = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
dsbParagraphSpacing.onChanged = {
|
dsbParagraphSpacing.onChanged = {
|
||||||
ReadBookConfig.paragraphSpacing = it
|
ReadBookConfig.paragraphSpacing = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeBg(index: Int) {
|
private fun changeBgTextConfig(index: Int) {
|
||||||
val oldIndex = ReadBookConfig.styleSelect
|
val oldIndex = ReadBookConfig.styleSelect
|
||||||
if (index != oldIndex) {
|
if (index != oldIndex) {
|
||||||
ReadBookConfig.styleSelect = index
|
ReadBookConfig.styleSelect = index
|
||||||
upView()
|
upView()
|
||||||
styleAdapter.notifyItemChanged(oldIndex)
|
styleAdapter.notifyItemChanged(oldIndex)
|
||||||
styleAdapter.notifyItemChanged(index)
|
styleAdapter.notifyItemChanged(index)
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(1, 2, 5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showBgTextConfig(index: Int): Boolean {
|
private fun showBgTextConfig(index: Int): Boolean {
|
||||||
dismissAllowingStateLoss()
|
dismissAllowingStateLoss()
|
||||||
changeBg(index)
|
changeBgTextConfig(index)
|
||||||
callBack?.showBgTextConfig()
|
callBack?.showBgTextConfig()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
|
|||||||
override fun selectFont(path: String) {
|
override fun selectFont(path: String) {
|
||||||
if (path != ReadBookConfig.textFont) {
|
if (path != ReadBookConfig.textFont) {
|
||||||
ReadBookConfig.textFont = path
|
ReadBookConfig.textFont = path
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
|
|||||||
binding.apply {
|
binding.apply {
|
||||||
ivStyle.setOnClickListener {
|
ivStyle.setOnClickListener {
|
||||||
if (ivStyle.isInView) {
|
if (ivStyle.isInView) {
|
||||||
changeBg(holder.layoutPosition)
|
changeBgTextConfig(holder.layoutPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ivStyle.onLongClick(ivStyle.isInView) {
|
ivStyle.onLongClick(ivStyle.isInView) {
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ import io.legado.app.databinding.DialogTipConfigBinding
|
|||||||
import io.legado.app.help.config.ReadBookConfig
|
import io.legado.app.help.config.ReadBookConfig
|
||||||
import io.legado.app.help.config.ReadTipConfig
|
import io.legado.app.help.config.ReadTipConfig
|
||||||
import io.legado.app.lib.dialogs.selector
|
import io.legado.app.lib.dialogs.selector
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.checkByIndex
|
||||||
|
import io.legado.app.utils.getIndexById
|
||||||
|
import io.legado.app.utils.hexString
|
||||||
|
import io.legado.app.utils.observeEvent
|
||||||
|
import io.legado.app.utils.postEvent
|
||||||
|
import io.legado.app.utils.setLayout
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
|
|
||||||
|
|
||||||
@@ -89,26 +94,26 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
private fun initEvent() = binding.run {
|
private fun initEvent() = binding.run {
|
||||||
rgTitleMode.setOnCheckedChangeListener { _, checkedId ->
|
rgTitleMode.setOnCheckedChangeListener { _, checkedId ->
|
||||||
ReadBookConfig.titleMode = rgTitleMode.getIndexById(checkedId)
|
ReadBookConfig.titleMode = rgTitleMode.getIndexById(checkedId)
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(5))
|
||||||
}
|
}
|
||||||
dsbTitleSize.onChanged = {
|
dsbTitleSize.onChanged = {
|
||||||
ReadBookConfig.titleSize = it
|
ReadBookConfig.titleSize = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
dsbTitleTop.onChanged = {
|
dsbTitleTop.onChanged = {
|
||||||
ReadBookConfig.titleTopSpacing = it
|
ReadBookConfig.titleTopSpacing = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
dsbTitleBottom.onChanged = {
|
dsbTitleBottom.onChanged = {
|
||||||
ReadBookConfig.titleBottomSpacing = it
|
ReadBookConfig.titleBottomSpacing = it
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(8, 5))
|
||||||
}
|
}
|
||||||
llHeaderShow.setOnClickListener {
|
llHeaderShow.setOnClickListener {
|
||||||
val headerModes = ReadTipConfig.getHeaderModes(requireContext())
|
val headerModes = ReadTipConfig.getHeaderModes(requireContext())
|
||||||
context?.selector(items = headerModes.values.toList()) { _, i ->
|
context?.selector(items = headerModes.values.toList()) { _, i ->
|
||||||
ReadTipConfig.headerMode = headerModes.keys.toList()[i]
|
ReadTipConfig.headerMode = headerModes.keys.toList()[i]
|
||||||
tvHeaderShow.text = headerModes[ReadTipConfig.headerMode]
|
tvHeaderShow.text = headerModes[ReadTipConfig.headerMode]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llFooterShow.setOnClickListener {
|
llFooterShow.setOnClickListener {
|
||||||
@@ -116,7 +121,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
context?.selector(items = footerModes.values.toList()) { _, i ->
|
context?.selector(items = footerModes.values.toList()) { _, i ->
|
||||||
ReadTipConfig.footerMode = footerModes.keys.toList()[i]
|
ReadTipConfig.footerMode = footerModes.keys.toList()[i]
|
||||||
tvFooterShow.text = footerModes[ReadTipConfig.footerMode]
|
tvFooterShow.text = footerModes[ReadTipConfig.footerMode]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llHeaderLeft.setOnClickListener {
|
llHeaderLeft.setOnClickListener {
|
||||||
@@ -125,7 +130,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipHeaderLeft = tipValue
|
ReadTipConfig.tipHeaderLeft = tipValue
|
||||||
tvHeaderLeft.text = ReadTipConfig.tipNames[i]
|
tvHeaderLeft.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llHeaderMiddle.setOnClickListener {
|
llHeaderMiddle.setOnClickListener {
|
||||||
@@ -134,7 +139,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipHeaderMiddle = tipValue
|
ReadTipConfig.tipHeaderMiddle = tipValue
|
||||||
tvHeaderMiddle.text = ReadTipConfig.tipNames[i]
|
tvHeaderMiddle.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llHeaderRight.setOnClickListener {
|
llHeaderRight.setOnClickListener {
|
||||||
@@ -143,7 +148,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipHeaderRight = tipValue
|
ReadTipConfig.tipHeaderRight = tipValue
|
||||||
tvHeaderRight.text = ReadTipConfig.tipNames[i]
|
tvHeaderRight.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llFooterLeft.setOnClickListener {
|
llFooterLeft.setOnClickListener {
|
||||||
@@ -152,7 +157,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipFooterLeft = tipValue
|
ReadTipConfig.tipFooterLeft = tipValue
|
||||||
tvFooterLeft.text = ReadTipConfig.tipNames[i]
|
tvFooterLeft.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llFooterMiddle.setOnClickListener {
|
llFooterMiddle.setOnClickListener {
|
||||||
@@ -161,7 +166,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipFooterMiddle = tipValue
|
ReadTipConfig.tipFooterMiddle = tipValue
|
||||||
tvFooterMiddle.text = ReadTipConfig.tipNames[i]
|
tvFooterMiddle.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llFooterRight.setOnClickListener {
|
llFooterRight.setOnClickListener {
|
||||||
@@ -170,7 +175,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
clearRepeat(tipValue)
|
clearRepeat(tipValue)
|
||||||
ReadTipConfig.tipFooterRight = tipValue
|
ReadTipConfig.tipFooterRight = tipValue
|
||||||
tvFooterRight.text = ReadTipConfig.tipNames[i]
|
tvFooterRight.text = ReadTipConfig.tipNames[i]
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llTipColor.setOnClickListener {
|
llTipColor.setOnClickListener {
|
||||||
@@ -179,7 +184,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
0 -> {
|
0 -> {
|
||||||
ReadTipConfig.tipColor = 0
|
ReadTipConfig.tipColor = 0
|
||||||
upTvTipColor()
|
upTvTipColor()
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
1 -> ColorPickerDialog.newBuilder()
|
1 -> ColorPickerDialog.newBuilder()
|
||||||
.setShowAlphaSlider(false)
|
.setShowAlphaSlider(false)
|
||||||
@@ -195,7 +200,7 @@ class TipConfigDialog : BaseDialogFragment(R.layout.dialog_tip_config) {
|
|||||||
0, 1 -> {
|
0, 1 -> {
|
||||||
ReadTipConfig.tipDividerColor = i - 1
|
ReadTipConfig.tipDividerColor = i - 1
|
||||||
upTvTipDividerColor()
|
upTvTipDividerColor()
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
2 -> ColorPickerDialog.newBuilder()
|
2 -> ColorPickerDialog.newBuilder()
|
||||||
.setShowAlphaSlider(false)
|
.setShowAlphaSlider(false)
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ class AutoPager(private val readView: ReadView) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (readView.isScroll) {
|
if (readView.isScroll) {
|
||||||
computeOffset()
|
|
||||||
if (!isPausing) readView.curPage.scroll(-scrollOffset)
|
if (!isPausing) readView.curPage.scroll(-scrollOffset)
|
||||||
} else {
|
} else {
|
||||||
val bottom = progress
|
val bottom = progress
|
||||||
@@ -112,13 +111,15 @@ class AutoPager(private val readView: ReadView) {
|
|||||||
bottom.toFloat(),
|
bottom.toFloat(),
|
||||||
paint
|
paint
|
||||||
)
|
)
|
||||||
if (!isPausing) readView.invalidate()
|
if (!isPausing) readView.postInvalidate()
|
||||||
computeOffset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeOffset() {
|
fun computeOffset() {
|
||||||
|
if (!isRunning) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val currentTime = SystemClock.uptimeMillis()
|
val currentTime = SystemClock.uptimeMillis()
|
||||||
val elapsedTime = currentTime - lastTimeMillis
|
val elapsedTime = currentTime - lastTimeMillis
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
|||||||
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.TextPageFactory
|
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
||||||
import io.legado.app.ui.widget.dialog.PhotoDialog
|
import io.legado.app.ui.widget.dialog.PhotoDialog
|
||||||
import io.legado.app.utils.PictureMirror
|
|
||||||
import io.legado.app.utils.activity
|
import io.legado.app.utils.activity
|
||||||
import io.legado.app.utils.getCompatColor
|
import io.legado.app.utils.getCompatColor
|
||||||
import io.legado.app.utils.showDialogFragment
|
import io.legado.app.utils.showDialogFragment
|
||||||
@@ -57,6 +56,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
private val pageDelegate get() = callBack.pageDelegate
|
private val pageDelegate get() = callBack.pageDelegate
|
||||||
private var pageOffset = 0
|
private var pageOffset = 0
|
||||||
private var autoPager: AutoPager? = null
|
private var autoPager: AutoPager? = null
|
||||||
|
private var isScroll = false
|
||||||
private val renderRunnable by lazy { Runnable { preRenderPage() } }
|
private val renderRunnable by lazy { Runnable { preRenderPage() } }
|
||||||
|
|
||||||
//绘制图片的paint
|
//绘制图片的paint
|
||||||
@@ -75,14 +75,17 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
*/
|
*/
|
||||||
fun setContent(textPage: TextPage) {
|
fun setContent(textPage: TextPage) {
|
||||||
this.textPage = textPage
|
this.textPage = textPage
|
||||||
imagePaint.isAntiAlias = AppConfig.useAntiAlias
|
// 非滑动翻页动画需要同步重绘,不然翻页可能会出现闪烁
|
||||||
invalidate()
|
if (isScroll) {
|
||||||
|
postInvalidate()
|
||||||
|
} else {
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh)
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
if (!isMainView) return
|
ChapterProvider.upViewSize(w, h, isMainView)
|
||||||
ChapterProvider.upViewSize(w, h)
|
|
||||||
textPage.format()
|
textPage.format()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,16 +110,21 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
//滚动翻页
|
//滚动翻页
|
||||||
if (!pageFactory.hasNext()) return
|
if (!pageFactory.hasNext()) return
|
||||||
val textPage1 = relativePage(1)
|
val textPage1 = relativePage(1)
|
||||||
relativeOffset = relativeOffset(1)
|
relativeOffset += textPage.height
|
||||||
textPage1.draw(this, canvas, relativeOffset)
|
textPage1.draw(this, canvas, relativeOffset)
|
||||||
if (!pageFactory.hasNextPlus()) return
|
if (!pageFactory.hasNextPlus()) return
|
||||||
relativeOffset = relativeOffset(2)
|
relativeOffset += textPage1.height
|
||||||
if (relativeOffset < ChapterProvider.visibleHeight) {
|
if (relativeOffset < ChapterProvider.visibleHeight) {
|
||||||
val textPage2 = relativePage(2)
|
val textPage2 = relativePage(2)
|
||||||
textPage2.draw(this, canvas, relativeOffset)
|
textPage2.draw(this, canvas, relativeOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun computeScroll() {
|
||||||
|
pageDelegate?.computeScroll()
|
||||||
|
autoPager?.computeOffset()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 滚动事件
|
* 滚动事件
|
||||||
* pageOffset 向上滚动 减小 向下滚动 增大
|
* pageOffset 向上滚动 减小 向下滚动 增大
|
||||||
@@ -125,7 +133,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
* pageOffset + textPage.height 为 textPage 下方的高度
|
* pageOffset + textPage.height 为 textPage 下方的高度
|
||||||
*/
|
*/
|
||||||
fun scroll(mOffset: Int) {
|
fun scroll(mOffset: Int) {
|
||||||
if (mOffset == 0) return
|
|
||||||
pageOffset += mOffset
|
pageOffset += mOffset
|
||||||
if (longScreenshot) {
|
if (longScreenshot) {
|
||||||
scrollY += -mOffset
|
scrollY += -mOffset
|
||||||
@@ -156,33 +163,34 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
pageDelegate?.abortAnim()
|
pageDelegate?.abortAnim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidate()
|
postInvalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun submitPreRenderTask() {
|
fun submitRenderTask() {
|
||||||
if (PictureMirror.atLeastApi23) {
|
renderThread.submit(renderRunnable)
|
||||||
renderThread.submit(renderRunnable)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun preRenderPage() {
|
private fun preRenderPage() {
|
||||||
val view = this
|
val view = this
|
||||||
var invalidate = false
|
var invalidate = false
|
||||||
pageFactory.run {
|
pageFactory.run {
|
||||||
hasPrev() && prevPage.preRender(view)
|
if (hasPrev() && prevPage.render(view)) {
|
||||||
if (curPage.preRender(view)) {
|
|
||||||
invalidate = true
|
invalidate = true
|
||||||
}
|
}
|
||||||
if (hasNext() && nextPage.preRender(view) && callBack.isScroll) {
|
if (curPage.render(view)) {
|
||||||
invalidate = true
|
invalidate = true
|
||||||
}
|
}
|
||||||
if (hasNextPlus() && nextPlusPage.preRender(view) && callBack.isScroll
|
if (hasNext() && nextPage.render(view) && callBack.isScroll) {
|
||||||
|
invalidate = true
|
||||||
|
}
|
||||||
|
if (hasNextPlus() && nextPlusPage.render(view) && callBack.isScroll
|
||||||
&& relativeOffset(2) < ChapterProvider.visibleHeight
|
&& relativeOffset(2) < ChapterProvider.visibleHeight
|
||||||
) {
|
) {
|
||||||
invalidate = true
|
invalidate = true
|
||||||
}
|
}
|
||||||
if (invalidate) {
|
if (invalidate) {
|
||||||
postInvalidate()
|
postInvalidate()
|
||||||
|
pageDelegate?.postInvalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +262,6 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
touchRough(x, y) { _, textPos, _, _, column ->
|
touchRough(x, y) { _, textPos, _, _, column ->
|
||||||
if (column is TextColumn) {
|
if (column is TextColumn) {
|
||||||
column.selected = true
|
column.selected = true
|
||||||
invalidate()
|
|
||||||
select(textPos)
|
select(textPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -557,7 +564,8 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidate()
|
// 由后台线程完成渲染后通知视图重绘
|
||||||
|
submitRenderTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun upSelectedStart(x: Float, y: Float, top: Float) {
|
private fun upSelectedStart(x: Float, y: Float, top: Float) {
|
||||||
@@ -681,6 +689,10 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
this.autoPager = autoPager
|
this.autoPager = autoPager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setIsScroll(value: Boolean) {
|
||||||
|
isScroll = value
|
||||||
|
}
|
||||||
|
|
||||||
override fun canScrollVertically(direction: Int): Boolean {
|
override fun canScrollVertically(direction: Int): Boolean {
|
||||||
return callBack.isScroll && pageFactory.hasNext()
|
return callBack.isScroll && pageFactory.hasNext()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,7 +321,12 @@ class PageView(context: Context) : FrameLayout(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun submitPreRenderTask() {
|
fun submitPreRenderTask() {
|
||||||
binding.contentTextView.submitPreRenderTask()
|
binding.contentTextView.submitRenderTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setIsScroll(value: Boolean) {
|
||||||
|
isScroll = value
|
||||||
|
binding.contentTextView.setIsScroll(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
|||||||
|
|
||||||
override fun computeScroll() {
|
override fun computeScroll() {
|
||||||
pageDelegate?.computeScroll()
|
pageDelegate?.computeScroll()
|
||||||
|
autoPager.computeOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
@@ -510,7 +511,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
|||||||
} else {
|
} else {
|
||||||
curPage.setAutoPager(null)
|
curPage.setAutoPager(null)
|
||||||
}
|
}
|
||||||
curPage.isScroll = isScroll
|
curPage.setIsScroll(isScroll)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -634,6 +635,7 @@ class ReadView(context: Context, attrs: AttributeSet) :
|
|||||||
nextPage.invalidateAll()
|
nextPage.invalidateAll()
|
||||||
nextPlusPage.invalidateAll()
|
nextPlusPage.invalidateAll()
|
||||||
}
|
}
|
||||||
|
upContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onScrollAnimStart() {
|
fun onScrollAnimStart() {
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package io.legado.app.ui.book.read.page.delegate
|
package io.legado.app.ui.book.read.page.delegate
|
||||||
|
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
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.withClip
|
||||||
import androidx.core.graphics.withTranslation
|
import androidx.core.graphics.withTranslation
|
||||||
import io.legado.app.ui.book.read.page.ReadView
|
import io.legado.app.ui.book.read.page.ReadView
|
||||||
@@ -12,26 +9,14 @@ import io.legado.app.ui.book.read.page.entities.PageDirection
|
|||||||
import io.legado.app.utils.screenshot
|
import io.legado.app.utils.screenshot
|
||||||
|
|
||||||
class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
|
class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
|
||||||
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) {
|
||||||
@@ -47,42 +32,21 @@ 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) {
|
||||||
if (!atLeastApi23) {
|
canvas.withTranslation(distanceX) {
|
||||||
bitmapMatrix.setTranslate(distanceX, 0.toFloat())
|
prevRecorder.draw(canvas)
|
||||||
prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
|
|
||||||
} else {
|
|
||||||
canvas.withTranslation(distanceX) {
|
|
||||||
drawPicture(prevPicture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addShadow(distanceX, canvas)
|
addShadow(distanceX, canvas)
|
||||||
} else {
|
} else {
|
||||||
if (!atLeastApi23) {
|
prevRecorder.draw(canvas)
|
||||||
prevBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
|
|
||||||
} else {
|
|
||||||
canvas.drawPicture(prevPicture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (mDirection == PageDirection.NEXT) {
|
} else if (mDirection == PageDirection.NEXT) {
|
||||||
if (!atLeastApi23) {
|
val width = nextRecorder.width.toFloat()
|
||||||
bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat())
|
val height = nextRecorder.height.toFloat()
|
||||||
nextBitmap?.let {
|
canvas.withClip(width + offsetX, 0f, width, height) {
|
||||||
val width = it.width.toFloat()
|
nextRecorder.draw(this)
|
||||||
val height = it.height.toFloat()
|
}
|
||||||
canvas.withClip(width + offsetX, 0f, width, height) {
|
canvas.withTranslation(distanceX - viewWidth) {
|
||||||
drawBitmap(it, 0f, 0f, null)
|
curRecorder.draw(this)
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
addShadow(distanceX, canvas)
|
||||||
}
|
}
|
||||||
@@ -90,18 +54,13 @@ class CoverPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
|
|||||||
|
|
||||||
override fun setBitmap() {
|
override fun setBitmap() {
|
||||||
when (mDirection) {
|
when (mDirection) {
|
||||||
PageDirection.PREV -> if (!atLeastApi23) {
|
PageDirection.PREV -> {
|
||||||
prevBitmap = prevPage.screenshot(prevBitmap, canvas)
|
prevPage.screenshot(prevRecorder)
|
||||||
} else {
|
|
||||||
prevPage.screenshot(prevPicture)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirection.NEXT -> if (!atLeastApi23) {
|
PageDirection.NEXT -> {
|
||||||
nextBitmap = nextPage.screenshot(nextBitmap, canvas)
|
nextPage.screenshot(nextRecorder)
|
||||||
curBitmap = curPage.screenshot(curBitmap, canvas)
|
curPage.screenshot(curRecorder)
|
||||||
} else {
|
|
||||||
nextPage.screenshot(nextPicture)
|
|
||||||
curPage.screenshot(curPicture)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
|
|||||||
+11
-16
@@ -1,18 +1,16 @@
|
|||||||
package io.legado.app.ui.book.read.page.delegate
|
package io.legado.app.ui.book.read.page.delegate
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
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.canvasrecorder.CanvasRecorderFactory
|
||||||
import io.legado.app.utils.screenshot
|
import io.legado.app.utils.screenshot
|
||||||
|
|
||||||
abstract class HorizontalPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
abstract class HorizontalPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
||||||
|
|
||||||
protected var curBitmap: Bitmap? = null
|
protected val curRecorder = CanvasRecorderFactory.create()
|
||||||
protected var prevBitmap: Bitmap? = null
|
protected val prevRecorder = CanvasRecorderFactory.create()
|
||||||
protected var nextBitmap: Bitmap? = null
|
protected val nextRecorder = CanvasRecorderFactory.create()
|
||||||
protected var canvas: Canvas = Canvas()
|
|
||||||
private val slopSquare get() = readView.pageSlopSquare2
|
private val slopSquare get() = readView.pageSlopSquare2
|
||||||
|
|
||||||
override fun setDirection(direction: PageDirection) {
|
override fun setDirection(direction: PageDirection) {
|
||||||
@@ -23,13 +21,13 @@ abstract class HorizontalPageDelegate(readView: ReadView) : PageDelegate(readVie
|
|||||||
open fun setBitmap() {
|
open fun setBitmap() {
|
||||||
when (mDirection) {
|
when (mDirection) {
|
||||||
PageDirection.PREV -> {
|
PageDirection.PREV -> {
|
||||||
prevBitmap = prevPage.screenshot(prevBitmap, canvas)
|
prevPage.screenshot(prevRecorder)
|
||||||
curBitmap = curPage.screenshot(curBitmap, canvas)
|
curPage.screenshot(curRecorder)
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirection.NEXT -> {
|
PageDirection.NEXT -> {
|
||||||
nextBitmap = nextPage.screenshot(nextBitmap, canvas)
|
nextPage.screenshot(nextRecorder)
|
||||||
curBitmap = curPage.screenshot(curBitmap, canvas)
|
curPage.screenshot(curRecorder)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
@@ -140,12 +138,9 @@ abstract class HorizontalPageDelegate(readView: ReadView) : PageDelegate(readVie
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
prevBitmap?.recycle()
|
prevRecorder.recycle()
|
||||||
prevBitmap = null
|
curRecorder.recycle()
|
||||||
curBitmap?.recycle()
|
nextRecorder.recycle()
|
||||||
curBitmap = null
|
|
||||||
nextBitmap?.recycle()
|
|
||||||
nextBitmap = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ abstract class PageDelegate(protected val readView: ReadView) {
|
|||||||
viewHeight = height
|
viewHeight = height
|
||||||
}
|
}
|
||||||
|
|
||||||
fun computeScroll() {
|
open fun computeScroll() {
|
||||||
if (scroller.computeScrollOffset()) {
|
if (scroller.computeScrollOffset()) {
|
||||||
readView.setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat())
|
readView.setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat())
|
||||||
} else if (isStarted) {
|
} else if (isStarted) {
|
||||||
@@ -190,6 +190,15 @@ abstract class PageDelegate(protected val readView: ReadView) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun postInvalidate() {
|
||||||
|
if (isRunning && this is HorizontalPageDelegate) {
|
||||||
|
readView.post {
|
||||||
|
setBitmap()
|
||||||
|
readView.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun onDestroy() {
|
open fun onDestroy() {
|
||||||
// run on destroy
|
// run on destroy
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
|||||||
val pointX = event.getX(event.pointerCount - 1)
|
val pointX = event.getX(event.pointerCount - 1)
|
||||||
val pointY = event.getY(event.pointerCount - 1)
|
val pointY = event.getY(event.pointerCount - 1)
|
||||||
if (isMoved) {
|
if (isMoved) {
|
||||||
readView.setTouchPoint(pointX, pointY)
|
readView.setTouchPoint(pointX, pointY, false)
|
||||||
}
|
}
|
||||||
if (!isMoved) {
|
if (!isMoved) {
|
||||||
val deltaX = (pointX - startX).toInt()
|
val deltaX = (pointX - startX).toInt()
|
||||||
@@ -95,12 +95,22 @@ class ScrollPageDelegate(readView: ReadView) : PageDelegate(readView) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun computeScroll() {
|
||||||
|
if (scroller.computeScrollOffset()) {
|
||||||
|
readView.setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat(), false)
|
||||||
|
} else if (isStarted) {
|
||||||
|
onAnimStop()
|
||||||
|
stopScroll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
mVelocity.recycle()
|
mVelocity.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun abortAnim() {
|
override fun abortAnim() {
|
||||||
|
readView.onScrollAnimStop()
|
||||||
isStarted = false
|
isStarted = false
|
||||||
isMoved = false
|
isMoved = false
|
||||||
isRunning = false
|
isRunning = false
|
||||||
|
|||||||
+42
-2
@@ -1,13 +1,27 @@
|
|||||||
package io.legado.app.ui.book.read.page.delegate
|
package io.legado.app.ui.book.read.page.delegate
|
||||||
|
|
||||||
import android.graphics.*
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.ColorMatrix
|
||||||
|
import android.graphics.ColorMatrixColorFilter
|
||||||
|
import android.graphics.Matrix
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.Path
|
||||||
|
import android.graphics.PointF
|
||||||
|
import android.graphics.Region
|
||||||
import android.graphics.drawable.GradientDrawable
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import io.legado.app.help.config.ReadBookConfig
|
import io.legado.app.help.config.ReadBookConfig
|
||||||
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 kotlin.math.*
|
import io.legado.app.utils.screenshot
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.atan2
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.hypot
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
|
class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readView) {
|
||||||
@@ -86,6 +100,11 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
|
|
||||||
private val mPaint: Paint = Paint().apply { style = Paint.Style.FILL }
|
private val mPaint: Paint = Paint().apply { style = Paint.Style.FILL }
|
||||||
|
|
||||||
|
private var curBitmap: Bitmap? = null
|
||||||
|
private var prevBitmap: Bitmap? = null
|
||||||
|
private var nextBitmap: Bitmap? = null
|
||||||
|
private var canvas: Canvas = Canvas()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
//设置颜色数组
|
//设置颜色数组
|
||||||
val color = intArrayOf(0x333333, -0x4fcccccd)
|
val color = intArrayOf(0x333333, -0x4fcccccd)
|
||||||
@@ -122,6 +141,22 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
mFrontShadowDrawableHBT.gradientType = GradientDrawable.LINEAR_GRADIENT
|
mFrontShadowDrawableHBT.gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setBitmap() {
|
||||||
|
when (mDirection) {
|
||||||
|
PageDirection.PREV -> {
|
||||||
|
prevBitmap = prevPage.screenshot(prevBitmap, canvas)
|
||||||
|
curBitmap = curPage.screenshot(curBitmap, canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
PageDirection.NEXT -> {
|
||||||
|
nextBitmap = nextPage.screenshot(nextBitmap, canvas)
|
||||||
|
curBitmap = curPage.screenshot(curBitmap, canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun setViewSize(width: Int, height: Int) {
|
override fun setViewSize(width: Int, height: Int) {
|
||||||
super.setViewSize(width, height)
|
super.setViewSize(width, height)
|
||||||
mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat()
|
mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat()
|
||||||
@@ -133,6 +168,7 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
calcCornerXY(event.x, event.y)
|
calcCornerXY(event.x, event.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
if ((startY > viewHeight / 3 && startY < viewHeight * 2 / 3)
|
if ((startY > viewHeight / 3 && startY < viewHeight * 2 / 3)
|
||||||
|| mDirection == PageDirection.PREV
|
|| mDirection == PageDirection.PREV
|
||||||
@@ -159,10 +195,12 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
} else {
|
} else {
|
||||||
calcCornerXY(viewWidth - startX, viewHeight.toFloat())
|
calcCornerXY(viewWidth - startX, viewHeight.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirection.NEXT ->
|
PageDirection.NEXT ->
|
||||||
if (viewWidth / 2 > startX) {
|
if (viewWidth / 2 > startX) {
|
||||||
calcCornerXY(viewWidth - startX, startY)
|
calcCornerXY(viewWidth - startX, startY)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,6 +254,7 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
drawCurrentPageShadow(canvas)
|
drawCurrentPageShadow(canvas)
|
||||||
drawCurrentBackArea(canvas, curBitmap)
|
drawCurrentBackArea(canvas, curBitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
PageDirection.PREV -> {
|
PageDirection.PREV -> {
|
||||||
calcPoints()
|
calcPoints()
|
||||||
drawCurrentPageArea(canvas, prevBitmap)
|
drawCurrentPageArea(canvas, prevBitmap)
|
||||||
@@ -223,6 +262,7 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
|
|||||||
drawCurrentPageShadow(canvas)
|
drawCurrentPageShadow(canvas)
|
||||||
drawCurrentBackArea(canvas, prevBitmap)
|
drawCurrentBackArea(canvas, prevBitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,12 @@
|
|||||||
package io.legado.app.ui.book.read.page.delegate
|
package io.legado.app.ui.book.read.page.delegate
|
||||||
|
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Matrix
|
|
||||||
import android.graphics.Picture
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.core.graphics.withTranslation
|
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 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) {
|
||||||
@@ -79,32 +40,18 @@ 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) {
|
||||||
if (!atLeastApi23) {
|
canvas.withTranslation(distanceX + viewWidth) {
|
||||||
bitmapMatrix.setTranslate(distanceX + viewWidth, 0.toFloat())
|
curRecorder.draw(this)
|
||||||
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
|
}
|
||||||
bitmapMatrix.setTranslate(distanceX, 0.toFloat())
|
canvas.withTranslation(distanceX) {
|
||||||
prevBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
|
prevRecorder.draw(this)
|
||||||
} else {
|
|
||||||
canvas.withTranslation(distanceX + viewWidth) {
|
|
||||||
drawPicture(curPicture)
|
|
||||||
}
|
|
||||||
canvas.withTranslation(distanceX) {
|
|
||||||
drawPicture(prevPicture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (mDirection == PageDirection.NEXT) {
|
} else if (mDirection == PageDirection.NEXT) {
|
||||||
if (!atLeastApi23) {
|
canvas.withTranslation(distanceX) {
|
||||||
bitmapMatrix.setTranslate(distanceX, 0.toFloat())
|
nextRecorder.draw(this)
|
||||||
nextBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
|
}
|
||||||
bitmapMatrix.setTranslate(distanceX - viewWidth, 0.toFloat())
|
canvas.withTranslation(distanceX - viewWidth) {
|
||||||
curBitmap?.let { canvas.drawBitmap(it, bitmapMatrix, null) }
|
curRecorder.draw(this)
|
||||||
} else {
|
|
||||||
canvas.withTranslation(distanceX) {
|
|
||||||
drawPicture(nextPicture)
|
|
||||||
}
|
|
||||||
canvas.withTranslation(distanceX - viewWidth) {
|
|
||||||
drawPicture(curPicture)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import io.legado.app.ui.book.read.page.ContentTextView
|
|||||||
import io.legado.app.ui.book.read.page.entities.TextPage.Companion.emptyTextPage
|
import io.legado.app.ui.book.read.page.entities.TextPage.Companion.emptyTextPage
|
||||||
import io.legado.app.ui.book.read.page.entities.column.BaseColumn
|
import io.legado.app.ui.book.read.page.entities.column.BaseColumn
|
||||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||||
import io.legado.app.utils.PictureMirror
|
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
|
||||||
|
import io.legado.app.utils.canvasrecorder.recordIfNeededThenDraw
|
||||||
import io.legado.app.utils.dpToPx
|
import io.legado.app.utils.dpToPx
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +40,7 @@ data class TextLine(
|
|||||||
val lineEnd: Float get() = textColumns.lastOrNull()?.end ?: 0f
|
val lineEnd: Float get() = textColumns.lastOrNull()?.end ?: 0f
|
||||||
val chapterIndices: IntRange get() = chapterPosition..chapterPosition + charSize
|
val chapterIndices: IntRange get() = chapterPosition..chapterPosition + charSize
|
||||||
val height: Float inline get() = lineBottom - lineTop
|
val height: Float inline get() = lineBottom - lineTop
|
||||||
val pictureMirror: PictureMirror = PictureMirror()
|
val canvasRecorder = CanvasRecorderFactory.create()
|
||||||
var isReadAloud: Boolean = false
|
var isReadAloud: Boolean = false
|
||||||
set(value) {
|
set(value) {
|
||||||
if (field != value) {
|
if (field != value) {
|
||||||
@@ -122,7 +123,7 @@ data class TextLine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun draw(view: ContentTextView, canvas: Canvas) {
|
fun draw(view: ContentTextView, canvas: Canvas) {
|
||||||
pictureMirror.draw(canvas, view.width, height.toInt()) {
|
canvasRecorder.recordIfNeededThenDraw(canvas, view.width, height.toInt()) {
|
||||||
drawTextLine(view, this)
|
drawTextLine(view, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,11 +157,11 @@ data class TextLine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun invalidateSelf() {
|
fun invalidateSelf() {
|
||||||
pictureMirror.invalidate()
|
canvasRecorder.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun recyclePicture() {
|
fun recycleRecorder() {
|
||||||
pictureMirror.recycle()
|
canvasRecorder.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import io.legado.app.model.ReadBook
|
|||||||
import io.legado.app.ui.book.read.page.ContentTextView
|
import io.legado.app.ui.book.read.page.ContentTextView
|
||||||
import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
import io.legado.app.ui.book.read.page.entities.column.TextColumn
|
||||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||||
import io.legado.app.utils.PictureMirror
|
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
|
||||||
|
import io.legado.app.utils.canvasrecorder.recordIfNeeded
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -43,7 +44,7 @@ data class TextPage(
|
|||||||
val charSize: Int get() = text.length.coerceAtLeast(1)
|
val charSize: Int get() = text.length.coerceAtLeast(1)
|
||||||
val searchResult = hashSetOf<TextColumn>()
|
val searchResult = hashSetOf<TextColumn>()
|
||||||
var isMsgPage: Boolean = false
|
var isMsgPage: Boolean = false
|
||||||
var pictureMirror: PictureMirror = PictureMirror()
|
var canvasRecorder = CanvasRecorderFactory.create(true)
|
||||||
var doublePage = false
|
var doublePage = false
|
||||||
var paddingTop = 0
|
var paddingTop = 0
|
||||||
|
|
||||||
@@ -267,11 +268,9 @@ data class TextPage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun draw(view: ContentTextView, canvas: Canvas, relativeOffset: Float) {
|
fun draw(view: ContentTextView, canvas: Canvas, relativeOffset: Float) {
|
||||||
val height = height.toInt()
|
render(view)
|
||||||
canvas.withTranslation(0f, relativeOffset + paddingTop) {
|
canvas.withTranslation(0f, relativeOffset + paddingTop) {
|
||||||
pictureMirror.drawLocked(canvas, view.width, height) {
|
canvasRecorder.draw(this)
|
||||||
drawPage(view, this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,20 +283,14 @@ data class TextPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun preRender(view: ContentTextView): Boolean {
|
fun render(view: ContentTextView): Boolean {
|
||||||
if (!pictureMirror.isDirty) return false
|
return canvasRecorder.recordIfNeeded(view.width, height.toInt()) {
|
||||||
pictureMirror.drawLocked(null, view.width, height.toInt()) {
|
|
||||||
drawPage(view, this)
|
drawPage(view, this)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isDirty(): Boolean {
|
|
||||||
return pictureMirror.isDirty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidate() {
|
fun invalidate() {
|
||||||
pictureMirror.invalidate()
|
canvasRecorder.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidateAll() {
|
fun invalidateAll() {
|
||||||
@@ -307,10 +300,10 @@ data class TextPage(
|
|||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun recyclePictures() {
|
fun recycleRecorders() {
|
||||||
pictureMirror.recycle()
|
canvasRecorder.recycle()
|
||||||
for (i in lines.indices) {
|
for (i in lines.indices) {
|
||||||
lines[i].recyclePicture()
|
lines[i].recycleRecorder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,15 +42,15 @@ data class TextColumn(
|
|||||||
} else {
|
} else {
|
||||||
ChapterProvider.contentPaint
|
ChapterProvider.contentPaint
|
||||||
}
|
}
|
||||||
val textColor = if (textLine.isReadAloud || isSearchResult) {
|
if (textLine.isReadAloud || isSearchResult) {
|
||||||
ThemeStore.accentColor
|
synchronized(textPaint) {
|
||||||
|
textPaint.color = ThemeStore.accentColor
|
||||||
|
canvas.drawText(charData, start, textLine.lineBase - textLine.lineTop, textPaint)
|
||||||
|
textPaint.color = ReadBookConfig.textColor
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ReadBookConfig.textColor
|
canvas.drawText(charData, start, textLine.lineBase - textLine.lineTop, textPaint)
|
||||||
}
|
}
|
||||||
if (textPaint.color != textColor) {
|
|
||||||
textPaint.color = textColor
|
|
||||||
}
|
|
||||||
canvas.drawText(charData, start, textLine.lineBase - textLine.lineTop, textPaint)
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
canvas.drawRect(start, 0f, end, textLine.height, view.selectedPaint)
|
canvas.drawRect(start, 0f, end, textLine.height, view.selectedPaint)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -690,39 +690,6 @@ object ChapterProvider {
|
|||||||
exceed(absStartX, textLine, words)
|
exceed(absStartX, textLine, words)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStringArrayAndTextWidths(
|
|
||||||
text: String,
|
|
||||||
textWidths: List<Float>,
|
|
||||||
textPaint: TextPaint
|
|
||||||
): Pair<List<String>, List<Float>> {
|
|
||||||
val charArray = text.toCharArray()
|
|
||||||
val strList = ArrayList<String>(text.length)
|
|
||||||
val textWidthList = ArrayList<Float>(text.length)
|
|
||||||
val lastIndex = charArray.lastIndex
|
|
||||||
var ca: CharArray? = null
|
|
||||||
for (i in textWidths.indices) {
|
|
||||||
if (charArray[i].isLowSurrogate()) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val char = if (i + 1 <= lastIndex && charArray[i + 1].isLowSurrogate()) {
|
|
||||||
if (ca == null) ca = CharArray(2)
|
|
||||||
System.arraycopy(charArray, i, ca, 0, 2)
|
|
||||||
String(ca)
|
|
||||||
} else {
|
|
||||||
charArray[i].toString()
|
|
||||||
}
|
|
||||||
val w = textWidths[i]
|
|
||||||
if (w == 0f && textWidthList.size > 0) {
|
|
||||||
textWidthList[textWidthList.lastIndex] = textPaint.measureText(strList.last())
|
|
||||||
textWidthList.add(textPaint.measureText(char))
|
|
||||||
} else {
|
|
||||||
textWidthList.add(w)
|
|
||||||
}
|
|
||||||
strList.add(char)
|
|
||||||
}
|
|
||||||
return strList to textWidthList
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加字符
|
* 添加字符
|
||||||
*/
|
*/
|
||||||
@@ -883,12 +850,12 @@ object ChapterProvider {
|
|||||||
/**
|
/**
|
||||||
* 更新View尺寸
|
* 更新View尺寸
|
||||||
*/
|
*/
|
||||||
fun upViewSize(width: Int, height: Int) {
|
fun upViewSize(width: Int, height: Int, postEvent: Boolean) {
|
||||||
if (width > 0 && height > 0 && (width != viewWidth || height != viewHeight)) {
|
if (width > 0 && height > 0 && (width != viewWidth || height != viewHeight)) {
|
||||||
viewWidth = width
|
viewWidth = width
|
||||||
viewHeight = height
|
viewHeight = height
|
||||||
upLayout()
|
upLayout()
|
||||||
postEvent(EventBus.UP_CONFIG, true)
|
if (postEvent) postEvent(EventBus.UP_CONFIG, arrayOf(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ package io.legado.app.ui.book.read.page.provider
|
|||||||
import android.text.TextPaint
|
import android.text.TextPaint
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import androidx.core.util.getOrDefault
|
import androidx.core.util.getOrDefault
|
||||||
import java.util.BitSet
|
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class TextMeasure(private var paint: TextPaint) {
|
class TextMeasure(private var paint: TextPaint) {
|
||||||
|
|
||||||
private var chineseCommonWidth = paint.measureText("一")
|
private var chineseCommonWidth = paint.measureText("一")
|
||||||
private val chineseCommonWidthBitSet = BitSet()
|
|
||||||
private val asciiWidths = FloatArray(128) { -1f }
|
private val asciiWidths = FloatArray(128) { -1f }
|
||||||
private val codePointWidths = SparseArray<Float>()
|
private val codePointWidths = SparseArray<Float>()
|
||||||
|
|
||||||
@@ -17,7 +15,8 @@ class TextMeasure(private var paint: TextPaint) {
|
|||||||
if (codePoint < 128) {
|
if (codePoint < 128) {
|
||||||
return asciiWidths[codePoint]
|
return asciiWidths[codePoint]
|
||||||
}
|
}
|
||||||
if (chineseCommonWidthBitSet[codePoint]) {
|
// 中文 Unicode 范围 U+4E00 - U+9FA5
|
||||||
|
if (codePoint in 19968 .. 40869) {
|
||||||
return chineseCommonWidth
|
return chineseCommonWidth
|
||||||
}
|
}
|
||||||
return codePointWidths.getOrDefault(codePoint, -1f)
|
return codePointWidths.getOrDefault(codePoint, -1f)
|
||||||
@@ -33,7 +32,8 @@ class TextMeasure(private var paint: TextPaint) {
|
|||||||
if (charArray[i].isLowSurrogate()) continue
|
if (charArray[i].isLowSurrogate()) continue
|
||||||
val width = ceil(widths[i])
|
val width = ceil(widths[i])
|
||||||
widthsList.add(width)
|
widthsList.add(width)
|
||||||
if (width == 0f && widthsList.size > 0) {
|
// 可能需要检查是否不可见字符
|
||||||
|
if (width == 0f && widthsList.size > 1) {
|
||||||
val lastIndex = widthsList.lastIndex
|
val lastIndex = widthsList.lastIndex
|
||||||
buf[0] = codePoints[lastIndex - 1]
|
buf[0] = codePoints[lastIndex - 1]
|
||||||
widthsList[lastIndex - 1] = paint.measureText(String(buf, 0, 1))
|
widthsList[lastIndex - 1] = paint.measureText(String(buf, 0, 1))
|
||||||
@@ -46,8 +46,6 @@ class TextMeasure(private var paint: TextPaint) {
|
|||||||
val width = widthsList[i]
|
val width = widthsList[i]
|
||||||
if (codePoint < 128) {
|
if (codePoint < 128) {
|
||||||
asciiWidths[codePoint] = width
|
asciiWidths[codePoint] = width
|
||||||
} else if (width == chineseCommonWidth) {
|
|
||||||
chineseCommonWidthBitSet.set(codePoint)
|
|
||||||
} else {
|
} else {
|
||||||
codePointWidths[codePoint] = width
|
codePointWidths[codePoint] = width
|
||||||
}
|
}
|
||||||
@@ -138,7 +136,6 @@ class TextMeasure(private var paint: TextPaint) {
|
|||||||
|
|
||||||
private fun invalidate() {
|
private fun invalidate() {
|
||||||
chineseCommonWidth = paint.measureText("一")
|
chineseCommonWidth = paint.measureText("一")
|
||||||
chineseCommonWidthBitSet.clear()
|
|
||||||
codePointWidths.clear()
|
codePointWidths.clear()
|
||||||
asciiWidths.fill(-1f)
|
asciiWidths.fill(-1f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import android.text.StaticLayout
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
|
import io.legado.app.utils.canvasrecorder.CanvasRecorderFactory
|
||||||
|
import io.legado.app.utils.canvasrecorder.recordIfNeededThenDraw
|
||||||
import io.legado.app.utils.dpToPx
|
import io.legado.app.utils.dpToPx
|
||||||
|
|
||||||
class BatteryView @JvmOverloads constructor(
|
class BatteryView @JvmOverloads constructor(
|
||||||
@@ -22,6 +24,7 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
private val batteryPaint = Paint()
|
private val batteryPaint = Paint()
|
||||||
private val outFrame = Rect()
|
private val outFrame = Rect()
|
||||||
private val polar = Rect()
|
private val polar = Rect()
|
||||||
|
private val canvasRecorder = CanvasRecorderFactory.create()
|
||||||
var isBattery = false
|
var isBattery = false
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
@@ -62,31 +65,40 @@ class BatteryView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDraw(canvas: Canvas) {
|
override fun onDraw(canvas: Canvas) {
|
||||||
super.onDraw(canvas)
|
canvasRecorder.recordIfNeededThenDraw(canvas, width, height) {
|
||||||
if (!isBattery) return
|
super.onDraw(this)
|
||||||
layout.getLineBounds(0, outFrame)
|
if (!isBattery) return@recordIfNeededThenDraw
|
||||||
val batteryStart = layout
|
layout.getLineBounds(0, outFrame)
|
||||||
.getPrimaryHorizontal(text.length - battery.toString().length)
|
val batteryStart = layout
|
||||||
.toInt() + 2.dpToPx()
|
.getPrimaryHorizontal(text.length - battery.toString().length)
|
||||||
val batteryEnd = batteryStart +
|
.toInt() + 2.dpToPx()
|
||||||
StaticLayout.getDesiredWidth(battery.toString(), paint).toInt() + 4.dpToPx()
|
val batteryEnd = batteryStart +
|
||||||
outFrame.set(
|
StaticLayout.getDesiredWidth(battery.toString(), paint).toInt() + 4.dpToPx()
|
||||||
batteryStart,
|
outFrame.set(
|
||||||
2.dpToPx(),
|
batteryStart,
|
||||||
batteryEnd,
|
2.dpToPx(),
|
||||||
height - 2.dpToPx()
|
batteryEnd,
|
||||||
)
|
height - 2.dpToPx()
|
||||||
val dj = (outFrame.bottom - outFrame.top) / 3
|
)
|
||||||
polar.set(
|
val dj = (outFrame.bottom - outFrame.top) / 3
|
||||||
batteryEnd,
|
polar.set(
|
||||||
outFrame.top + dj,
|
batteryEnd,
|
||||||
batteryEnd + 2.dpToPx(),
|
outFrame.top + dj,
|
||||||
outFrame.bottom - dj
|
batteryEnd + 2.dpToPx(),
|
||||||
)
|
outFrame.bottom - dj
|
||||||
batteryPaint.style = Paint.Style.STROKE
|
)
|
||||||
canvas.drawRect(outFrame, batteryPaint)
|
batteryPaint.style = Paint.Style.STROKE
|
||||||
batteryPaint.style = Paint.Style.FILL
|
drawRect(outFrame, batteryPaint)
|
||||||
canvas.drawRect(polar, batteryPaint)
|
batteryPaint.style = Paint.Style.FILL
|
||||||
|
drawRect(polar, batteryPaint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() {
|
||||||
|
super.invalidate()
|
||||||
|
kotlin.runCatching {
|
||||||
|
canvasRecorder.invalidate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -32,26 +32,19 @@ object ChineseUtils {
|
|||||||
fun fixT2sDict() {
|
fun fixT2sDict() {
|
||||||
val dict = DictionaryContainer.getInstance().getDictionary(TransType.TRADITIONAL_TO_SIMPLE)
|
val dict = DictionaryContainer.getInstance().getDictionary(TransType.TRADITIONAL_TO_SIMPLE)
|
||||||
dict.run {
|
dict.run {
|
||||||
remove("劈")
|
remove("劈", "脊")
|
||||||
remove("脊")
|
remove("支援", "沈默", "類比", "模擬", "划槳", "列根", "先進")
|
||||||
remove("支援")
|
remove("路易斯", "非同步", "出租车", "周杰倫")
|
||||||
remove("沈默")
|
|
||||||
remove("類比")
|
|
||||||
remove("模擬")
|
|
||||||
remove("划槳")
|
|
||||||
remove("列根")
|
|
||||||
remove("路易斯")
|
|
||||||
remove("非同步")
|
|
||||||
remove("出租车")
|
|
||||||
remove("周杰倫")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BasicDictionary.remove(key: String) {
|
fun BasicDictionary.remove(vararg keys: String) {
|
||||||
if (key.length == 1) {
|
for (key in keys) {
|
||||||
chars.remove(key[0])
|
if (key.length == 1) {
|
||||||
} else {
|
chars.remove(key[0])
|
||||||
dict.remove(key)
|
} else {
|
||||||
|
dict.remove(key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
package io.legado.app.utils
|
|
||||||
|
|
||||||
import android.graphics.Canvas
|
|
||||||
import android.graphics.Picture
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.core.graphics.record
|
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
|
||||||
|
|
||||||
class PictureMirror {
|
|
||||||
@Volatile
|
|
||||||
var picture: Picture? = null
|
|
||||||
|
|
||||||
@Volatile
|
|
||||||
var lock: ReentrantLock? = null
|
|
||||||
|
|
||||||
@Volatile
|
|
||||||
var isDirty = true
|
|
||||||
|
|
||||||
inline fun drawLocked(
|
|
||||||
canvas: Canvas?,
|
|
||||||
width: Int,
|
|
||||||
height: Int,
|
|
||||||
block: Canvas.() -> Unit
|
|
||||||
) {
|
|
||||||
if (atLeastApi23) {
|
|
||||||
if (picture == null || lock == null) {
|
|
||||||
synchronized(this) {
|
|
||||||
if (picture == null) {
|
|
||||||
picture = Picture()
|
|
||||||
}
|
|
||||||
if (lock == null) {
|
|
||||||
lock = ReentrantLock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val picture = picture!!
|
|
||||||
val lock = lock!!
|
|
||||||
if (isDirty) {
|
|
||||||
if (!lock.tryLock()) return
|
|
||||||
try {
|
|
||||||
picture.record(width, height, block)
|
|
||||||
isDirty = false
|
|
||||||
} finally {
|
|
||||||
lock.unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas?.drawPicture(picture)
|
|
||||||
} else {
|
|
||||||
canvas?.block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 非线程安全,多线程调用可能会崩溃
|
|
||||||
*/
|
|
||||||
inline fun draw(
|
|
||||||
canvas: Canvas?,
|
|
||||||
width: Int,
|
|
||||||
height: Int,
|
|
||||||
block: Canvas.() -> Unit
|
|
||||||
) {
|
|
||||||
if (atLeastApi23) {
|
|
||||||
if (picture == null) picture = Picture()
|
|
||||||
val picture = picture!!
|
|
||||||
if (isDirty) {
|
|
||||||
picture.record(width, height, block)
|
|
||||||
isDirty = false
|
|
||||||
}
|
|
||||||
canvas?.drawPicture(picture)
|
|
||||||
} else {
|
|
||||||
canvas?.block()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun invalidate() {
|
|
||||||
isDirty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun recycle() {
|
|
||||||
picture = null
|
|
||||||
isDirty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val atLeastApi23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -37,6 +37,8 @@ import androidx.viewpager.widget.ViewPager
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.globalExecutor
|
import io.legado.app.help.globalExecutor
|
||||||
import io.legado.app.lib.theme.TintHelper
|
import io.legado.app.lib.theme.TintHelper
|
||||||
|
import io.legado.app.utils.canvasrecorder.CanvasRecorder
|
||||||
|
import io.legado.app.utils.canvasrecorder.record
|
||||||
import splitties.systemservices.inputMethodManager
|
import splitties.systemservices.inputMethodManager
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
@@ -180,6 +182,16 @@ fun View.screenshot(picture: Picture) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.screenshot(canvasRecorder: CanvasRecorder) {
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
canvasRecorder.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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper
|
||||||
|
|
||||||
|
abstract class BaseCanvasRecorder : CanvasRecorder {
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
protected var isDirty = true
|
||||||
|
|
||||||
|
override fun invalidate() {
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun recycle() {
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun endRecording() {
|
||||||
|
isDirty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isDirty(): Boolean {
|
||||||
|
return isDirty
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLocked(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun needRecord(): Boolean {
|
||||||
|
return isDirty() && !isLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
|
||||||
|
interface CanvasRecorder {
|
||||||
|
|
||||||
|
val width: Int
|
||||||
|
|
||||||
|
val height: Int
|
||||||
|
|
||||||
|
fun beginRecording(width: Int, height: Int): Canvas
|
||||||
|
|
||||||
|
fun endRecording()
|
||||||
|
|
||||||
|
fun draw(canvas: Canvas)
|
||||||
|
|
||||||
|
fun invalidate()
|
||||||
|
|
||||||
|
fun recycle()
|
||||||
|
|
||||||
|
fun isDirty(): Boolean
|
||||||
|
|
||||||
|
fun isLocked(): Boolean
|
||||||
|
|
||||||
|
fun needRecord(): Boolean
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Picture
|
||||||
|
|
||||||
|
class CanvasRecorderApi23Impl : BaseCanvasRecorder() {
|
||||||
|
|
||||||
|
private var picture: Picture? = null
|
||||||
|
|
||||||
|
override val width get() = picture?.width ?: -1
|
||||||
|
override val height get() = picture?.height ?: -1
|
||||||
|
|
||||||
|
private fun initPicture() {
|
||||||
|
if (picture == null) {
|
||||||
|
picture = Picture()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginRecording(width: Int, height: Int): Canvas {
|
||||||
|
initPicture()
|
||||||
|
return picture!!.beginRecording(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endRecording() {
|
||||||
|
picture!!.endRecording()
|
||||||
|
super.endRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
if (picture == null) return
|
||||||
|
canvas.drawPicture(picture!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recycle() {
|
||||||
|
super.recycle()
|
||||||
|
picture = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Picture
|
||||||
|
import android.graphics.RenderNode
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
|
class CanvasRecorderApi29Impl : BaseCanvasRecorder() {
|
||||||
|
|
||||||
|
private var renderNode: RenderNode? = null
|
||||||
|
private var picture: Picture? = null
|
||||||
|
|
||||||
|
override val width get() = renderNode?.width ?: -1
|
||||||
|
override val height get() = renderNode?.height ?: -1
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
if (renderNode == null) {
|
||||||
|
renderNode = RenderNode("CanvasRecorder")
|
||||||
|
}
|
||||||
|
if (picture == null) {
|
||||||
|
picture = Picture()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginRecording(width: Int, height: Int): Canvas {
|
||||||
|
init()
|
||||||
|
renderNode!!.setPosition(0, 0, width, height)
|
||||||
|
return picture!!.beginRecording(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endRecording() {
|
||||||
|
picture!!.endRecording()
|
||||||
|
val rc = renderNode!!.beginRecording()
|
||||||
|
rc.drawPicture(picture!!)
|
||||||
|
renderNode!!.endRecording()
|
||||||
|
super.endRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
if (renderNode == null || picture == null) return
|
||||||
|
if (canvas.isHardwareAccelerated) {
|
||||||
|
if (!renderNode!!.hasDisplayList()) {
|
||||||
|
val rc = renderNode!!.beginRecording()
|
||||||
|
rc.drawPicture(picture!!)
|
||||||
|
renderNode!!.endRecording()
|
||||||
|
}
|
||||||
|
canvas.drawRenderNode(renderNode!!)
|
||||||
|
} else {
|
||||||
|
canvas.drawPicture(picture!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recycle() {
|
||||||
|
super.recycle()
|
||||||
|
renderNode?.discardDisplayList()
|
||||||
|
renderNode = null
|
||||||
|
picture = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import androidx.core.graphics.withSave
|
||||||
|
|
||||||
|
inline fun CanvasRecorder.recordIfNeeded(
|
||||||
|
width: Int,
|
||||||
|
height: Int,
|
||||||
|
block: Canvas.() -> Unit
|
||||||
|
): Boolean {
|
||||||
|
if (!needRecord()) return false
|
||||||
|
record(width, height, block)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun CanvasRecorder.record(width: Int, height: Int, block: Canvas.() -> Unit) {
|
||||||
|
val canvas = beginRecording(width, height)
|
||||||
|
try {
|
||||||
|
canvas.withSave {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
endRecording()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun CanvasRecorder.recordIfNeededThenDraw(
|
||||||
|
canvas: Canvas,
|
||||||
|
width: Int,
|
||||||
|
height: Int,
|
||||||
|
block: Canvas.() -> Unit
|
||||||
|
) {
|
||||||
|
recordIfNeeded(width, height, block)
|
||||||
|
draw(canvas)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
object CanvasRecorderFactory {
|
||||||
|
|
||||||
|
private val atLeastApi23 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
private val atLeastApi29 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||||
|
|
||||||
|
fun create(locked: Boolean = false): CanvasRecorder {
|
||||||
|
val impl = when {
|
||||||
|
atLeastApi29 -> CanvasRecorderApi29Impl()
|
||||||
|
atLeastApi23 -> CanvasRecorderApi23Impl()
|
||||||
|
else -> CanvasRecorderImpl()
|
||||||
|
}
|
||||||
|
return if (locked) {
|
||||||
|
CanvasRecorderLocked(impl)
|
||||||
|
} else {
|
||||||
|
impl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
|
||||||
|
class CanvasRecorderImpl : BaseCanvasRecorder() {
|
||||||
|
|
||||||
|
var bitmap: Bitmap? = null
|
||||||
|
var canvas: Canvas? = null
|
||||||
|
|
||||||
|
override val width get() = bitmap?.width ?: -1
|
||||||
|
override val height get() = bitmap?.height ?: -1
|
||||||
|
|
||||||
|
private fun init(width: Int, height: Int) {
|
||||||
|
if (bitmap == null) {
|
||||||
|
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
}
|
||||||
|
if (canvas == null) {
|
||||||
|
canvas = Canvas(bitmap!!)
|
||||||
|
}
|
||||||
|
if (bitmap!!.width != width || bitmap!!.height != height) {
|
||||||
|
if (canReconfigure(width, height)) {
|
||||||
|
bitmap!!.reconfigure(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
} else {
|
||||||
|
bitmap!!.recycle()
|
||||||
|
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
|
}
|
||||||
|
canvas!!.setBitmap(bitmap!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canReconfigure(width: Int, height: Int): Boolean {
|
||||||
|
return bitmap!!.allocationByteCount >= width * height * 4
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginRecording(width: Int, height: Int): Canvas {
|
||||||
|
init(width, height)
|
||||||
|
bitmap!!.eraseColor(Color.TRANSPARENT)
|
||||||
|
return canvas!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endRecording() {
|
||||||
|
bitmap!!.prepareToDraw()
|
||||||
|
super.endRecording()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
if (bitmap == null) return
|
||||||
|
canvas.drawBitmap(bitmap!!, 0f, 0f, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recycle() {
|
||||||
|
super.recycle()
|
||||||
|
bitmap?.recycle()
|
||||||
|
bitmap = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package io.legado.app.utils.canvasrecorder
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
|
class CanvasRecorderLocked(private val delegate: CanvasRecorder) :
|
||||||
|
CanvasRecorder by delegate {
|
||||||
|
|
||||||
|
var lock: ReentrantLock? = ReentrantLock()
|
||||||
|
|
||||||
|
private fun initLock() {
|
||||||
|
if (lock == null) {
|
||||||
|
synchronized(this) {
|
||||||
|
if (lock == null) {
|
||||||
|
lock = ReentrantLock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun beginRecording(width: Int, height: Int): Canvas {
|
||||||
|
initLock()
|
||||||
|
lock!!.lock()
|
||||||
|
return delegate.beginRecording(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endRecording() {
|
||||||
|
delegate.endRecording()
|
||||||
|
lock!!.unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
if (lock == null) return
|
||||||
|
if (!lock!!.tryLock()) return
|
||||||
|
try {
|
||||||
|
delegate.draw(canvas)
|
||||||
|
} finally {
|
||||||
|
lock!!.unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLocked(): Boolean {
|
||||||
|
if (lock == null) return false
|
||||||
|
return lock!!.isLocked
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recycle() {
|
||||||
|
delegate.recycle()
|
||||||
|
lock = null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user