增加无极字重切换

This commit is contained in:
HapeLee
2025-09-05 03:38:27 +08:00
parent cb60443323
commit 158812fd65
3 changed files with 362 additions and 30 deletions
@@ -1,25 +1,32 @@
package io.legato.kazusa.ui.font
package io.legato.kazusa.ui.book.read.config
import android.net.Uri
//import io.legado.app.lib.theme.primaryColor
import android.content.Context
import android.graphics.Typeface
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.GridLayoutManager
import io.legato.kazusa.R
import io.legato.kazusa.base.BaseBottomSheetDialogFragment
import io.legato.kazusa.base.BaseDialogFragment
import io.legato.kazusa.base.adapter.ItemViewHolder
import io.legato.kazusa.base.adapter.RecyclerAdapter
import io.legato.kazusa.constant.AppLog
import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.databinding.DialogFontSelectBinding
import io.legato.kazusa.databinding.ItemFontBinding
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.help.config.ReadBookConfig
import io.legato.kazusa.lib.dialogs.SelectItem
import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.permission.Permissions
import io.legato.kazusa.lib.permission.PermissionsCompat
//import io.legado.app.lib.theme.primaryColor
import io.legato.kazusa.ui.file.HandleFileContract
import io.legato.kazusa.utils.FileDoc
import io.legato.kazusa.utils.FileUtils
@@ -28,28 +35,30 @@ import io.legato.kazusa.utils.applyTint
import io.legato.kazusa.utils.cnCompare
import io.legato.kazusa.utils.externalFiles
import io.legato.kazusa.utils.getPrefString
import io.legato.kazusa.utils.invisible
import io.legato.kazusa.utils.isContentScheme
import io.legato.kazusa.utils.list
import io.legato.kazusa.utils.listFileDocs
import io.legato.kazusa.utils.postEvent
import io.legato.kazusa.utils.printOnDebug
import io.legato.kazusa.utils.putPrefString
import io.legato.kazusa.utils.setLayout
import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.launch
import java.io.File
import androidx.core.net.toUri
import java.net.URLDecoder
/**
* 字体选择对话框
*/
class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_select),
Toolbar.OnMenuItemClickListener,
FontAdapter.CallBack {
Toolbar.OnMenuItemClickListener {
private val fontRegex = Regex("(?i).*\\.[ot]tf")
private val binding by viewBinding(DialogFontSelectBinding::bind)
private val adapter by lazy {
val curFontPath = callBack?.curFontPath ?: ""
FontAdapter(requireContext(), curFontPath, this)
FontAdapter(requireContext(), curFontPath)
}
private val selectFontDir = registerForActivityResult(HandleFileContract()) {
it.uri?.let { uri ->
@@ -78,9 +87,17 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
binding.toolBar.inflateMenu(R.menu.font_select)
binding.toolBar.menu.applyTint(requireContext())
binding.toolBar.setOnMenuItemClickListener(this)
binding.recyclerView.layoutManager = LinearLayoutManager(context)
binding.recyclerView.layoutManager = GridLayoutManager(context, 2)
binding.recyclerView.adapter = adapter
initView()
upView()
initViewEvent()
}
private fun initView() = binding.run {
val fontPath = getPrefString(PreferKey.fontFolder)
if (fontPath.isNullOrEmpty()) {
openFolder()
@@ -96,6 +113,93 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
loadFontFilesByPermission(fontPath)
}
}
dsbTextLetterSpacing.valueFormat = {
((it - 50) / 100f).toString()
}
dsbLineSize.valueFormat = { ((it - 10) / 10f).toString() }
binding.bgTextIndent.apply {
val currentIndex = ReadBookConfig.paragraphIndent.length.coerceAtMost(childCount - 1)
val defaultButtonId = getChildAt(currentIndex).id
check(defaultButtonId)
addOnButtonCheckedListener { group, checkedId, isChecked ->
if (isChecked) {
val checkedIndex = (0 until group.childCount)
.firstOrNull { group.getChildAt(it).id == checkedId }
?: return@addOnButtonCheckedListener
ReadBookConfig.paragraphIndent = " ".repeat(checkedIndex)
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
}
}
val weightOptions = context?.resources?.getStringArray(R.array.text_font_weight)
val weightValues = listOf(500, 700, 300)
val initialIndex = weightValues.indexOf(ReadBookConfig.textBold)
binding.textFontWeightConverter.text = weightOptions?.getOrNull(initialIndex) ?: "自定义"
binding.textFontWeightConverter.setOnClickListener {
context?.alert(titleResource = R.string.text_font_weight_converter) {
weightOptions?.let { options ->
items(options.toList()) { _, i ->
ReadBookConfig.textBold = weightValues[i]
binding.sliderFontWeight.value =
ReadBookConfig.textBold.toFloat().coerceAtLeast(100f)
binding.textFontWeightConverter.text = options.getOrNull(i) ?: ""
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 9, 6))
}
}
}
}
binding.sliderFontWeight.apply {
valueFrom = 100f
valueTo = 900f
stepSize = 10f
value = ReadBookConfig.textBold.toFloat().coerceAtLeast(100f)
addOnChangeListener { _, newValue, _ ->
binding.textFontWeightConverter.text = "自定义"
ReadBookConfig.textBold = newValue.toInt()
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 9, 6))
}
}
}
private fun initViewEvent() = binding.run {
dsbTextLetterSpacing.onChanged = {
ReadBookConfig.letterSpacing = (it - 50) / 100f
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
dsbLineSize.onChanged = {
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()
if (fromUser) {
ReadBookConfig.paragraphSpacing = newValue.toInt()
postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
}
}
}
}
private fun upView() = binding.run {
ReadBookConfig.let {
dsbTextLetterSpacing.progress = (it.letterSpacing * 100).toInt() + 50
dsbLineSize.progress = it.lineSpacingExtra
dsbParagraphSpacing.value = it.paragraphSpacing.toFloat()
}
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
@@ -183,7 +287,7 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
}
}
override fun onFontSelect(docItem: FileDoc) {
fun onFontSelect(docItem: FileDoc) {
execute {
callBack?.selectFont(docItem.toString())
}.onSuccess {
@@ -198,6 +302,57 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
private val callBack: CallBack?
get() = (parentFragment as? CallBack) ?: (activity as? CallBack)
inner class FontAdapter(context: Context, curFilePath: String) :
RecyclerAdapter<FileDoc, ItemFontBinding>(context) {
private val curName = runCatching {
URLDecoder.decode(curFilePath, "utf-8")
}.getOrNull()?.substringAfterLast(File.separator)
override fun getViewBinding(parent: ViewGroup): ItemFontBinding {
return ItemFontBinding.inflate(inflater, parent, false)
}
override fun convert(
holder: ItemViewHolder,
binding: ItemFontBinding,
item: FileDoc,
payloads: MutableList<Any>
) {
binding.run {
runCatching {
val typeface: Typeface? = if (item.isContentScheme) {
context.contentResolver
.openFileDescriptor(item.uri, "r")?.use {
Typeface.Builder(it.fileDescriptor).build()
}
} else {
Typeface.createFromFile(item.uri.path!!)
}
tvFont.typeface = typeface
}.onFailure {
it.printOnDebug()
AppLog.put("读取字体 ${item.name} 出错\n${it.localizedMessage}", it, true)
}
tvFont.text = item.name
root.setOnClickListener { onFontSelect(item) }
if (item.name == curName) {
ivChecked.visible()
} else {
ivChecked.invisible()
}
}
}
override fun registerListener(holder: ItemViewHolder, binding: ItemFontBinding) {
holder.itemView.setOnClickListener {
getItem(holder.layoutPosition)?.let {
onFontSelect(it)
}
}
}
}
interface CallBack {
fun selectFont(path: String)
val curFontPath: String
@@ -912,24 +912,18 @@ object ChapterProvider {
private fun getPaints(typeface: Typeface?): Pair<TextPaint, TextPaint> {
// 字体统一处理
val bold = Typeface.create(typeface, Typeface.BOLD)
val normal = Typeface.create(typeface, Typeface.NORMAL)
val (titleFont, textFont) = when (ReadBookConfig.textBold) {
1 -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
Pair(Typeface.create(typeface, 900, false), bold)
else
Pair(bold, bold)
val (titleFont, textFont) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
Pair(
Typeface.create(typeface, ReadBookConfig.textBold, false),
Typeface.create(typeface, ReadBookConfig.textBold, false)
)
} else {
val tf = when (ReadBookConfig.textBold) {
in 700..900 -> Typeface.DEFAULT_BOLD
in 300..499 -> Typeface.DEFAULT
else -> Typeface.DEFAULT
}
2 -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
Pair(normal, Typeface.create(typeface, 300, false))
else
Pair(normal, normal)
}
else -> Pair(bold, normal)
Pair(tf, tf)
}
//标题