diff --git a/app/src/main/java/io/legato/kazusa/ui/font/FontSelectDialog.kt b/app/src/main/java/io/legato/kazusa/ui/book/read/config/FontSelectDialog.kt similarity index 50% rename from app/src/main/java/io/legato/kazusa/ui/font/FontSelectDialog.kt rename to app/src/main/java/io/legato/kazusa/ui/book/read/config/FontSelectDialog.kt index 42b7af054..120c9939b 100644 --- a/app/src/main/java/io/legato/kazusa/ui/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/read/config/FontSelectDialog.kt @@ -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(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 + ) { + 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 diff --git a/app/src/main/java/io/legato/kazusa/ui/book/read/page/provider/ChapterProvider.kt b/app/src/main/java/io/legato/kazusa/ui/book/read/page/provider/ChapterProvider.kt index 3f1d15ef9..50bbebd27 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/read/page/provider/ChapterProvider.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/read/page/provider/ChapterProvider.kt @@ -912,24 +912,18 @@ object ChapterProvider { private fun getPaints(typeface: Typeface?): Pair { // 字体统一处理 - 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) } //标题 diff --git a/app/src/main/res/layout/dialog_font_select.xml b/app/src/main/res/layout/dialog_font_select.xml index db9e44a3c..9917c8e31 100644 --- a/app/src/main/res/layout/dialog_font_select.xml +++ b/app/src/main/res/layout/dialog_font_select.xml @@ -1,5 +1,6 @@ @@ -10,9 +11,191 @@ android:layout_height="wrap_content" android:theme="?attr/actionBarStyle" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:layout_height="match_parent" + android:layout_margin="2dp" /> \ No newline at end of file