重新规划了阅读设置与相关修复 #251

This commit is contained in:
HapeLee
2025-11-09 02:47:16 +08:00
parent 9977c6385d
commit bcf4469b7d
25 changed files with 1148 additions and 789 deletions
@@ -32,6 +32,7 @@ import io.legado.app.model.CacheBook
import io.legado.app.model.ReadBook
import io.legado.app.ui.book.read.config.BgTextConfigDialog
import io.legado.app.ui.book.read.config.ClickActionConfigDialog
import io.legado.app.ui.book.read.config.InfoConfigDialog
import io.legado.app.ui.book.read.config.PaddingConfigDialog
import io.legado.app.ui.book.read.config.PageKeyDialog
import io.legado.app.ui.file.HandleFileContract
@@ -127,7 +128,7 @@ abstract class BaseReadBookActivity :
}
fun showPaddingConfig() {
showDialogFragment<PaddingConfigDialog>()
showDialogFragment<InfoConfigDialog>()
}
fun showBgTextConfig() {
@@ -1748,7 +1748,10 @@ class ReadBookActivity : BaseReadBookActivity(),
when (value) {
0 -> upSystemUiVisibility()
1 -> readView.upBg()
2 -> readView.upStyle()
2 -> {
readView.upStyle()
binding.readMenu.reset()
}
3 -> readView.upBgAlpha()
4 -> readView.upPageSlopSquare()
5 -> if (isInitFinish) ReadBook.loadContent(resetPageOffset = false)
@@ -115,7 +115,6 @@ class BgTextConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_bg
ItemBgImageBinding.inflate(layoutInflater, it, false).apply {
tvName.text = getString(R.string.select_image)
ivBg.setImageResource(R.drawable.ic_add)
swUnderline.isGone = ReadBook.book?.isImage == true
root.setOnClickListener {
selectBgImage.launch()
}
@@ -130,9 +129,6 @@ class BgTextConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_bg
private fun initData() = with(ReadBookConfig.durConfig) {
binding.tvName.text = name.ifBlank { "文字" }
binding.swDarkStatusIcon.isChecked = curStatusIconDark()
binding.swUnderline.isChecked = underline
binding.swDottedline.isChecked = dottedLine
binding.swDottedline.isEnabled = underline
binding.sbBgAlpha.value = ReadBookConfig.bgAlpha.toFloat()
binding.dottedRatio.valueFormat = {
(ReadBookConfig.dottedRatio * 100).toInt().toString()
@@ -175,27 +171,6 @@ class BgTextConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_bg
setCurStatusIconDark(isChecked)
(activity as? ReadBookActivity)?.upSystemUiVisibility()
}
binding.swUnderline.setOnCheckedChangeListener { _, isChecked ->
underline = isChecked
binding.swDottedline.isEnabled = isChecked
if (!isChecked) {
dottedLine = false
binding.swDottedline.isChecked = false
}
postEvent(EventBus.UP_CONFIG, arrayListOf(6, 9, 11))
}
binding.swDottedline.setOnCheckedChangeListener { _, isChecked ->
dottedLine = isChecked
postEvent(EventBus.UP_CONFIG, arrayListOf(6, 9, 11))
}
binding.tvTextColor.setOnClickListener {
ColorPickerDialog.newBuilder()
.setColor(curTextColor())
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TEXT_COLOR)
.show(requireActivity())
}
binding.tvBgColor.setOnClickListener {
val bgColor =
if (curBgType() == 0) curBgStr().toColorInt()
@@ -24,10 +24,13 @@ import io.legado.app.constant.PreferKey
import io.legado.app.databinding.DialogFontSelectBinding
import io.legado.app.databinding.ItemFontBinding
import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.ReadBookConfig.dottedLine
import io.legado.app.help.config.ReadBookConfig.underline
import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.permission.Permissions
import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.TEXT_COLOR
import io.legado.app.ui.file.HandleFileContract
import io.legado.app.utils.FileDoc
import io.legado.app.utils.FileUtils
@@ -40,6 +43,7 @@ import io.legado.app.utils.invisible
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.list
import io.legado.app.utils.listFileDocs
import io.legado.app.utils.observeEvent
import io.legado.app.utils.postEvent
import io.legado.app.utils.printOnDebug
import io.legado.app.utils.putPrefString
@@ -47,14 +51,14 @@ import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.legado.app.utils.visible
import kotlinx.coroutines.launch
import splitties.resources.color
import java.io.File
import java.net.URLDecoder
/**
* 字体选择对话框
*/
class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_select),
Toolbar.OnMenuItemClickListener {
class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_select) {
companion object {
const val S_COLOR = 123
@@ -88,14 +92,14 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
//binding.toolBar.setBackgroundColor(primaryColor)
binding.toolBar.setTitle(R.string.select_font)
binding.toolBar.inflateMenu(R.menu.font_select)
binding.toolBar.menu.applyTint(requireContext())
binding.toolBar.setOnMenuItemClickListener(this)
binding.recyclerView.layoutManager = GridLayoutManager(context, 2)
binding.recyclerView.adapter = adapter
observeEvent<ArrayList<Int>>(EventBus.UP_CONFIG) { list ->
if (list.contains(2)) {
binding.btnTextColor.color = ReadBookConfig.durConfig.curTextColor()
binding.btnShadowColor.color = ReadBookConfig.durConfig.curTextShadowColor()
}
}
initView()
upView()
initViewEvent()
@@ -118,7 +122,10 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
loadFontFilesByPermission(fontPath)
}
}
binding.btnTextColor.color = ReadBookConfig.durConfig.curTextColor()
binding.swUnderline.isChecked = underline
binding.swDottedline.isChecked = dottedLine
binding.swDottedline.isEnabled = underline
dsbTextLetterSpacing.valueFormat = {
((it - 50) / 100f).toString()
}
@@ -126,17 +133,19 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
binding.dsbShadowRadius.valueFormat = { "$it px" }
binding.dsbShadowDx.valueFormat = { "$it px" }
binding.dsbShadowDy.valueFormat = { "$it px" }
binding.textIndentDropdown.apply {
val items = listOf("0", "1", "2", "3", "4")
val adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, items)
setAdapter(adapter)
val currentIndex = ReadBookConfig.paragraphIndent.length.coerceIn(0, items.lastIndex)
setText(items[currentIndex], false)
setOnItemClickListener { _, _, position, _ ->
ReadBookConfig.paragraphIndent = " ".repeat(position)
binding.dsbParagraphSpacing.valueFormat = { value ->
(value / 10f).toString()
}
binding.btnIndentLayout.apply {
valueFormat = { value ->
value.toString()
}
onChanged = { value ->
val indentCount = value.coerceIn(0, 4)
ReadBookConfig.paragraphIndent = " ".repeat(indentCount)
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
progress = ReadBookConfig.paragraphIndent.length
}
val weightOptions = context?.resources?.getStringArray(R.array.text_font_weight)
@@ -172,6 +181,7 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
binding.btnTextItalic.isChecked = ReadBookConfig.textItalic
binding.btnTextShadow.isChecked = ReadBookConfig.textShadow
binding.btnShadowColor.color = ReadBookConfig.textShadowColor
}
private fun initViewEvent() = binding.run {
@@ -183,21 +193,48 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
ReadBookConfig.lineSpacingExtra = it
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
binding.dsbParagraphSpacing.apply {
valueFrom = 0f
valueTo = 20f
stepSize = 1f
value = ReadBookConfig.paragraphSpacing.toFloat()
textParagraphSpacing.text = (ReadBookConfig.paragraphSpacing.toFloat() / 10f).toString()
addOnChangeListener { slider, newValue, fromUser ->
binding.textParagraphSpacing.text = (newValue / 10f).toString()
binding.btnTextColor.setOnClickListener {
ColorPickerDialog.newBuilder()
.setColor(ReadBookConfig.durConfig.curTextColor())
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TEXT_COLOR)
.show(requireActivity())
}
if (fromUser) {
ReadBookConfig.paragraphSpacing = newValue.toInt()
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
binding.swUnderline.addOnCheckedChangeListener { _, isChecked ->
underline = isChecked
binding.swDottedline.isEnabled = isChecked
if (!isChecked) {
dottedLine = false
binding.swDottedline.isChecked = false
}
postEvent(EventBus.UP_CONFIG, arrayListOf(6, 9, 11))
}
binding.swDottedline.addOnCheckedChangeListener { _, isChecked ->
dottedLine = isChecked
postEvent(EventBus.UP_CONFIG, arrayListOf(6, 9, 11))
}
binding.btnDefaultFonts.setOnClickListener {
val requireContext = requireContext()
alert(titleResource = R.string.system_typeface) {
items(
requireContext.resources.getStringArray(R.array.system_typefaces).toList()
) { _, i ->
AppConfig.systemTypefaces = i
onDefaultFontChange()
dismissAllowingStateLoss()
}
}
}
binding.btnOtherDir.setOnClickListener {
openFolder()
}
binding.dsbParagraphSpacing.onChanged = { value ->
ReadBookConfig.paragraphSpacing = value
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
binding.btnTextItalic.addOnCheckedChangeListener { _, isChecked ->
ReadBookConfig.textItalic = isChecked
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
@@ -233,34 +270,13 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
ReadBookConfig.let {
dsbTextLetterSpacing.progress = (it.letterSpacing * 100).toInt() + 50
dsbLineSize.progress = it.lineSpacingExtra
dsbParagraphSpacing.value = it.paragraphSpacing.toFloat()
dsbParagraphSpacing.progress = it.paragraphSpacing
binding.dsbShadowRadius.progress = it.shadowRadius.toInt()
binding.dsbShadowDx.progress = it.shadowDx.toInt()
binding.dsbShadowDy.progress = it.shadowDy.toInt()
}
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.menu_default -> {
val requireContext = requireContext()
alert(titleResource = R.string.system_typeface) {
items(
requireContext.resources.getStringArray(R.array.system_typefaces).toList()
) { _, i ->
AppConfig.systemTypefaces = i
onDefaultFontChange()
dismissAllowingStateLoss()
}
}
}
R.id.menu_other -> {
openFolder()
}
}
return true
}
private fun openFolder() {
lifecycleScope.launch {
val defaultPath = "SD${File.separator}Fonts"
@@ -0,0 +1,242 @@
package io.legado.app.ui.book.read.config
import android.os.Bundle
import android.view.View
import com.google.android.material.chip.Chip
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import io.legado.app.R
import io.legado.app.base.BaseBottomSheetDialogFragment
import io.legado.app.constant.EventBus
import io.legado.app.databinding.DialogReadInfoBinding
import io.legado.app.help.config.ReadBookConfig
import io.legado.app.help.config.ReadTipConfig
import io.legado.app.lib.dialogs.selector
import io.legado.app.model.ReadBook
import io.legado.app.ui.book.read.config.TipConfigDialog.Companion.TIP_COLOR
import io.legado.app.ui.book.read.config.TipConfigDialog.Companion.TIP_DIVIDER_COLOR
import io.legado.app.ui.book.read.page.provider.ChapterProvider
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.observeEvent
import io.legado.app.utils.postEvent
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlin.collections.component1
import kotlin.collections.component2
class InfoConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_info) {
private val binding by viewBinding(DialogReadInfoBinding::bind)
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
initView()
initEvent()
observeEvent<String>(EventBus.TIP_COLOR) {
upTvTipColor()
upTvTipDividerColor()
}
observeEvent<ArrayList<Int>>(EventBus.UP_CONFIG) { list ->
if (list.contains(2)) {
upBtnHeaderMode()
upBtnFooterMode()
}
}
}
private fun initView() {
ReadTipConfig.run {
tipNames.let { tipNames ->
binding.tvHeaderLeft.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderLeft)) { tipNames[none] }
binding.tvHeaderMiddle.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderMiddle)) { tipNames[none] }
binding.tvHeaderRight.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderRight)) { tipNames[none] }
binding.tvFooterLeft.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterLeft)) { tipNames[none] }
binding.tvFooterMiddle.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterMiddle)) { tipNames[none] }
binding.tvFooterRight.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterRight)) { tipNames[none] }
}
}
binding.btnPaddingSetting.setOnClickListener {
showDialogFragment<PaddingConfigDialog>()
}
upTvTipColor()
upTvTipDividerColor()
}
private fun upTvTipColor() {
val tipColor = if (ReadTipConfig.tipColor == 0) {
ReadBookConfig.textColor
} else {
ReadTipConfig.tipColor
}
binding.btnTipColor.color = tipColor
}
private fun upTvTipDividerColor() {
val tipDividerColor = when (ReadTipConfig.tipDividerColor) {
-1 -> getCompatColor(R.color.divider)
0 -> ReadBookConfig.textColor
else -> ReadTipConfig.tipDividerColor
}
binding.btnDividerColor.color = tipDividerColor
}
private fun upBtnHeaderMode() {
val headerModes = ReadTipConfig.getHeaderModes(requireContext())
binding.btnHeaderMode.text = headerModes[ReadTipConfig.headerMode] ?: getString(R.string.header)
}
private fun upBtnFooterMode() {
val footerModes = ReadTipConfig.getFooterModes(requireContext())
binding.btnFooterMode.text = footerModes[ReadTipConfig.footerMode] ?: getString(R.string.footer)
}
private fun initEvent() = binding.run {
val headerModes = ReadTipConfig.getHeaderModes(requireContext())
binding.btnHeaderMode.text = headerModes[ReadTipConfig.headerMode] ?: getString(R.string.header)
binding.btnHeaderMode.setOnClickListener {
val items = headerModes.values.toList()
context?.selector(items = items) { _, index ->
val selectedKey = headerModes.keys.toList()[index]
ReadTipConfig.headerMode = selectedKey
binding.btnHeaderMode.text = headerModes[selectedKey]
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
}
val footerModes = ReadTipConfig.getFooterModes(requireContext())
binding.btnFooterMode.text = footerModes[ReadTipConfig.footerMode] ?: getString(R.string.footer)
binding.btnFooterMode.setOnClickListener {
val items = footerModes.values.toList()
context?.selector(items = items) { _, index ->
val selectedKey = footerModes.keys.toList()[index]
ReadTipConfig.footerMode = selectedKey
binding.btnFooterMode.text = footerModes[selectedKey]
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
}
llHeaderLeft.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderLeft = tipValue
tvHeaderLeft.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llHeaderMiddle.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderMiddle = tipValue
tvHeaderMiddle.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llHeaderRight.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderRight = tipValue
tvHeaderRight.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterLeft.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterLeft = tipValue
tvFooterLeft.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterMiddle.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterMiddle = tipValue
tvFooterMiddle.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterRight.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterRight = tipValue
tvFooterRight.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
btnTipColor.setOnClickListener {
context?.selector(items = ReadTipConfig.tipColorNames) { _, i ->
when (i) {
0 -> {
ReadTipConfig.tipColor = 0
upTvTipColor()
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
1 -> ColorPickerDialog.newBuilder()
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TIP_COLOR)
.show(requireActivity())
}
}
}
btnDividerColor.setOnClickListener {
context?.selector(items = ReadTipConfig.tipDividerColorNames) { _, i ->
when (i) {
0, 1 -> {
ReadTipConfig.tipDividerColor = i - 1
upTvTipDividerColor()
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
2 -> ColorPickerDialog.newBuilder()
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TIP_DIVIDER_COLOR)
.show(requireActivity())
}
}
}
}
private fun clearRepeat(repeat: Int) = ReadTipConfig.apply {
if (repeat != none) {
if (tipHeaderLeft == repeat) {
tipHeaderLeft = none
binding.tvHeaderLeft.text = tipNames[none]
}
if (tipHeaderMiddle == repeat) {
tipHeaderMiddle = none
binding.tvHeaderMiddle.text = tipNames[none]
}
if (tipHeaderRight == repeat) {
tipHeaderRight = none
binding.tvHeaderRight.text = tipNames[none]
}
if (tipFooterLeft == repeat) {
tipFooterLeft = none
binding.tvFooterLeft.text = tipNames[none]
}
if (tipFooterMiddle == repeat) {
tipFooterMiddle = none
binding.tvFooterMiddle.text = tipNames[none]
}
if (tipFooterRight == repeat) {
tipFooterRight = none
binding.tvFooterRight.text = tipNames[none]
}
}
}
}
@@ -208,17 +208,14 @@ class ReadStyleDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_book_
tvStyle.text = item.name.ifBlank { "文字" }
tvStyle.setTextColor(item.curTextColor())
ivStyle.setImageDrawable(item.curBgDrawable(100, 150))
cdStyle.strokeWidth = 1.dpToPx()
if (ReadBookConfig.styleSelect == holder.layoutPosition) {
llStyle.gravity = Gravity.TOP
cdStyle.cardElevation = 1f.dpToPx()
cdStyle.radius = 16f.dpToPx()
cdStyle.strokeWidth = 1.dpToPx()
cdStyle.radius = 32f.dpToPx()
//cdStyle.strokeColor = item.curTextColor()
//tvStyle.setTextBold(true)
} else {
cdStyle.cardElevation = 2f.dpToPx()
cdStyle.radius = 32f.dpToPx()
cdStyle.strokeWidth = 0
cdStyle.radius = 8f.dpToPx()
//cdStyle.strokeColor = item.curTextColor()
//tvStyle.setTextBold(false)
}
@@ -19,6 +19,7 @@ import io.legado.app.utils.hexString
import io.legado.app.utils.observeEvent
import io.legado.app.utils.postEvent
import io.legado.app.utils.requestInputMethod
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.viewbindingdelegate.viewBinding
@@ -41,10 +42,6 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
initView()
initEvent()
observeEvent<String>(EventBus.TIP_COLOR) {
upTvTipColor()
upTvTipDividerColor()
}
observeEvent<Boolean>(EventBus.UPDATE_READ_ACTION_BAR) {
binding.abtnBackgroundColor.color = ReadBookConfig.durConfig.curMenuBg()
binding.abtnAccentColor.color = ReadBookConfig.durConfig.curMenuAc()
@@ -62,7 +59,6 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config
val weightOptions = context?.resources?.getStringArray(R.array.text_font_weight)
val weightValues = listOf(0, 1, 2)
val initialIndex = weightValues.indexOf(ReadBookConfig.titleBold)
binding.textFontWeightConverter.text = weightOptions?.getOrNull(initialIndex) ?: "自定义"
binding.textFontWeightConverter.setOnClickListener {
context?.alert(titleResource = R.string.text_font_weight_converter) {
weightOptions?.let { options ->
@@ -186,82 +182,6 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config
binding.dsbTitleSize.progress = ReadBookConfig.titleSize
binding.dsbTitleTop.progress = ReadBookConfig.titleTopSpacing
binding.dsbTitleBottom.progress = ReadBookConfig.titleBottomSpacing
val headerModes = ReadTipConfig.getHeaderModes(requireContext())
binding.chipHeaderMode.removeAllViews()
headerModes.forEach { (key, value) ->
val chip = Chip(requireContext()).apply {
id = View.generateViewId()
text = value
isCheckable = true
isClickable = true
tag = key
}
binding.chipHeaderMode.addView(chip)
if (key == ReadTipConfig.headerMode) {
chip.isChecked = true
}
}
val footerModes = ReadTipConfig.getFooterModes(requireContext())
binding.chipFooterMode.removeAllViews()
footerModes.forEach { (key, value) ->
val chip = Chip(requireContext()).apply {
id = View.generateViewId()
text = value
isCheckable = true
isClickable = true
tag = key
}
binding.chipFooterMode.addView(chip)
if (key == ReadTipConfig.footerMode) {
chip.isChecked = true
}
}
ReadTipConfig.run {
tipNames.let { tipNames ->
binding.tvHeaderLeft.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderLeft)) { tipNames[none] }
binding.tvHeaderMiddle.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderMiddle)) { tipNames[none] }
binding.tvHeaderRight.text =
tipNames.getOrElse(tipValues.indexOf(tipHeaderRight)) { tipNames[none] }
binding.tvFooterLeft.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterLeft)) { tipNames[none] }
binding.tvFooterMiddle.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterMiddle)) { tipNames[none] }
binding.tvFooterRight.text =
tipNames.getOrElse(tipValues.indexOf(tipFooterRight)) { tipNames[none] }
}
}
upTvTipColor()
upTvTipDividerColor()
}
private fun upTvTipColor() {
val tipColorNames = ReadTipConfig.tipColorNames
val tipColor = ReadTipConfig.tipColor
binding.tvTipColor.text = if (tipColor == 0) {
tipColorNames.first()
} else {
"#${tipColor.hexString}"
}
}
private fun upTvTipDividerColor() {
val tipDividerColorNames = ReadTipConfig.tipDividerColorNames
val tipDividerColor = ReadTipConfig.tipDividerColor
binding.tvTipDividerColor.text = when (tipDividerColor) {
-1, 0 -> tipDividerColorNames[tipDividerColor + 1]
else -> "#${tipDividerColor.hexString}"
}
}
private fun initEvent() = binding.run {
@@ -291,139 +211,6 @@ class TipConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tip_config
ReadBookConfig.titleBottomSpacing = it
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
chipHeaderMode.setOnCheckedStateChangeListener { group, checkedIds ->
if (checkedIds.isNotEmpty()) {
val selectedChip = group.findViewById<Chip>(checkedIds[0])
val mode = selectedChip.tag as Int
ReadTipConfig.headerMode = mode
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
}
chipFooterMode.setOnCheckedStateChangeListener { group, checkedIds ->
if (checkedIds.isNotEmpty()) {
val selectedChip = group.findViewById<Chip>(checkedIds[0])
val mode = selectedChip.tag as Int
ReadTipConfig.footerMode = mode
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
}
llHeaderLeft.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderLeft = tipValue
tvHeaderLeft.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llHeaderMiddle.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderMiddle = tipValue
tvHeaderMiddle.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llHeaderRight.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipHeaderRight = tipValue
tvHeaderRight.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterLeft.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterLeft = tipValue
tvFooterLeft.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterMiddle.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterMiddle = tipValue
tvFooterMiddle.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llFooterRight.setOnClickListener {
context?.selector(items = ReadTipConfig.tipNames) { _, i ->
val tipValue = ReadTipConfig.tipValues[i]
clearRepeat(tipValue)
ReadTipConfig.tipFooterRight = tipValue
tvFooterRight.text = ReadTipConfig.tipNames[i]
postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6))
}
}
llTipColor.setOnClickListener {
context?.selector(items = ReadTipConfig.tipColorNames) { _, i ->
when (i) {
0 -> {
ReadTipConfig.tipColor = 0
upTvTipColor()
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
1 -> ColorPickerDialog.newBuilder()
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TIP_COLOR)
.show(requireActivity())
}
}
}
llTipDividerColor.setOnClickListener {
context?.selector(items = ReadTipConfig.tipDividerColorNames) { _, i ->
when (i) {
0, 1 -> {
ReadTipConfig.tipDividerColor = i - 1
upTvTipDividerColor()
postEvent(EventBus.UP_CONFIG, arrayListOf(2))
}
2 -> ColorPickerDialog.newBuilder()
.setShowAlphaSlider(false)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setDialogId(TIP_DIVIDER_COLOR)
.show(requireActivity())
}
}
}
}
private fun clearRepeat(repeat: Int) = ReadTipConfig.apply {
if (repeat != none) {
if (tipHeaderLeft == repeat) {
tipHeaderLeft = none
binding.tvHeaderLeft.text = tipNames[none]
}
if (tipHeaderMiddle == repeat) {
tipHeaderMiddle = none
binding.tvHeaderMiddle.text = tipNames[none]
}
if (tipHeaderRight == repeat) {
tipHeaderRight = none
binding.tvHeaderRight.text = tipNames[none]
}
if (tipFooterLeft == repeat) {
tipFooterLeft = none
binding.tvFooterLeft.text = tipNames[none]
}
if (tipFooterMiddle == repeat) {
tipFooterMiddle = none
binding.tvFooterMiddle.text = tipNames[none]
}
if (tipFooterRight == repeat) {
tipFooterRight = none
binding.tvFooterRight.text = tipNames[none]
}
}
}
}
@@ -20,10 +20,10 @@ class AccentColorButton @JvmOverloads constructor(
}
init {
setPaddingRelative(14.dpToPx(), 8.dpToPx(), 6.dpToPx(), 8.dpToPx())
setPaddingRelative(14.dpToPx(), 8.dpToPx(), 10.dpToPx(), 8.dpToPx())
iconGravity = ICON_GRAVITY_END
iconPadding = 8.dpToPx()
iconSize = 28.dpToPx()
iconSize = 24.dpToPx()
}
private fun createColorPreviewDrawable(color: Int): Drawable {
@@ -0,0 +1,172 @@
package io.legado.app.ui.widget
import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.TooltipCompat
import io.legado.app.R
import io.legado.app.databinding.ViewSimpleSliderBinding
import io.legado.app.lib.dialogs.alert
@SuppressLint("ViewConstructor", "ClickableViewAccessibility")
class SimpleSliderView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {
private val binding = ViewSimpleSliderBinding.inflate(LayoutInflater.from(context), this, true)
private var _orientation: Int = 1
private var _progress = 0
private var _max = 100
private var _min = 0
private val isBottomBackground: Boolean
var valueFormat: ((Int) -> String)? = null
var onChanged: ((Int) -> Unit)? = null
private val handler = Handler(Looper.getMainLooper())
private val repeatInterval = 320L
private val tvTit: TextView
var progress: Int
get() = _progress
set(value) {
_progress = value.coerceIn(_min, _max)
updateValue()
}
var max: Int
get() = _max
set(value) {
_max = value
_progress = _progress.coerceAtMost(_max)
updateValue()
}
var min: Int
get() = _min
set(value) {
_min = value
_progress = _progress.coerceAtLeast(_min)
updateValue()
}
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DetailSeekBar)
isBottomBackground = typedArray.getBoolean(R.styleable.DetailSeekBar_isBottomBackground, false)
val title = typedArray.getText(R.styleable.DetailSeekBar_title)
_max = typedArray.getInt(R.styleable.DetailSeekBar_max, 100)
_min = typedArray.getInt(R.styleable.DetailSeekBar_min, 0)
_progress = _progress.coerceIn(_min, _max)
val ta = context.obtainStyledAttributes(attrs, R.styleable.SimpleCounterView)
_orientation = ta.getInt(R.styleable.SimpleCounterView_orientation, 1)
ta.recycle()
val slider = binding.slider
slider.valueFrom = _min.toFloat()
slider.valueTo = _max.toFloat()
slider.value = _progress.toFloat()
slider.addOnChangeListener { _, value, fromUser ->
if (fromUser) {
_progress = value.toInt()
updateValue()
onChanged?.invoke(_progress)
}
}
tvTit = binding.tvSeekTitleVertical
typedArray.recycle()
tvTit.text = title
TooltipCompat.setTooltipText(tvTit, title)
binding.tvSeekValue.setOnClickListener {
showSeekBarDialog()
}
updateValue()
}
private fun showSeekBarDialog() {
context.alert(title = null, message = null) {
customView {
val detailSeekBar = DetailSeekBar(ctx).apply {
max = _max
min = _min
progress = _progress
valueFormat = this@SimpleSliderView.valueFormat
setTitle(tvTit.text)
onChanged = {
_progress = it
updateValue()
this@SimpleSliderView.onChanged?.invoke(it)
}
}
FrameLayout(ctx).apply {
setPadding(64, 0, 64, 0)
addView(detailSeekBar, LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
))
}
}
okButton()
cancelButton()
}
}
private fun updateValue() {
binding.tvSeekValue.text = valueFormat?.invoke(_progress) ?: _progress.toString()
if (binding.slider.value.toInt() != _progress) {
binding.slider.value = _progress.toFloat()
}
}
private val incrementRunnable = object : Runnable {
override fun run() {
if (_progress < _max) {
_progress++
updateValue()
onChanged?.invoke(_progress)
handler.postDelayed(this, repeatInterval)
}
}
}
private val decrementRunnable = object : Runnable {
override fun run() {
if (_progress > _min) {
_progress--
updateValue()
onChanged?.invoke(_progress)
handler.postDelayed(this, repeatInterval)
}
}
}
override fun onDetachedFromWindow() {
handler.removeCallbacks(incrementRunnable)
handler.removeCallbacks(decrementRunnable)
super.onDetachedFromWindow()
}
override fun setEnabled(enabled: Boolean) {
super.setEnabled(enabled)
tvTit.isEnabled = enabled
binding.tvSeekValue.isEnabled = enabled
}
}