HapeLee 1 год назад
Родитель
Сommit
cf8f9c13b6

+ 241 - 0
app/src/main/java/io/legado/app/ui/book/read/config/FontConfigDialog.kt

@@ -0,0 +1,241 @@
+package io.legado.app.ui.book.read.config
+
+import android.content.Context
+import android.graphics.Typeface
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import io.legado.app.help.config.ReadBookConfig
+import androidx.core.net.toUri
+import androidx.documentfile.provider.DocumentFile
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.GridLayoutManager
+import com.jaredrummler.android.colorpicker.ColorPickerDialog
+import io.legado.app.R
+import io.legado.app.base.BaseBottomSheetDialogFragment
+import io.legado.app.base.adapter.ItemViewHolder
+import io.legado.app.base.adapter.RecyclerAdapter
+import io.legado.app.constant.AppLog
+import io.legado.app.constant.EventBus
+import io.legado.app.constant.PreferKey
+import io.legado.app.databinding.DialogFontConfigBinding
+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.ReadBookActivity
+import io.legado.app.ui.file.HandleFileContract
+import io.legado.app.utils.FileDoc
+import io.legado.app.utils.FileUtils
+import io.legado.app.utils.RealPathUtil
+import io.legado.app.utils.cnCompare
+import io.legado.app.utils.externalFiles
+import io.legado.app.utils.getPrefString
+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
+import io.legado.app.utils.toastOnUi
+import io.legado.app.utils.viewbindingdelegate.viewBinding
+import io.legado.app.utils.visible
+import kotlinx.coroutines.launch
+import java.io.File
+import java.net.URLDecoder
+
+/**
+ * 字体选择对话框
+ */
+class FontConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_config) {
+
+    companion object {
+        const val S_COLOR = 123
+        const val TEXT_COLOR = 121
+    }
+    private val fontRegex = Regex("(?i).*\\.[ot]tf")
+    private val binding by viewBinding(DialogFontConfigBinding::bind)
+
+    private val callBack2 get() = activity as? ReadBookActivity
+    private val weightIconMap = mapOf(
+        0 to R.drawable.ic_text_weight_0,
+        1 to R.drawable.ic_text_weight_1,
+        2 to R.drawable.ic_text_weight_2,
+    )
+
+    override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
+        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()
+    }
+
+    private fun initView() = binding.run {
+        binding.btnTextColor.color = ReadBookConfig.durConfig.curTextColor()
+        binding.swUnderline.isChecked = underline
+        binding.swDottedline.isChecked = dottedLine
+        binding.swDottedline.isEnabled = underline
+        dsbTextLetterSpacing.valueFormat = {
+            ((it - 50) / 100f).toString()
+        }
+        dsbLineSize.valueFormat = { ((it - 10) / 10f).toString() }
+        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)
+        val weightValues = listOf(0, 1, 2)
+        val initialIndex = weightValues.indexOf(ReadBookConfig.textBold)
+        val initialIconRes = weightIconMap[initialIndex] ?: R.drawable.ic_custom_text
+        binding.textFontWeightConverter.setIconResource(initialIconRes)
+        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.progress =
+                            ReadBookConfig.textBold.coerceAtLeast(100)
+                        val iconRes = weightIconMap[i] ?: R.drawable.ic_custom_text
+                        binding.textFontWeightConverter.setIconResource(iconRes)
+                        postEvent(EventBus.UP_CONFIG, arrayListOf(8, 9, 6))
+                    }
+                }
+            }
+        }
+
+        binding.sliderFontWeight.apply {
+            min = 100
+            max = 900
+            progress = ReadBookConfig.textBold.coerceAtLeast(100)
+            onChanged = {
+                binding.textFontWeightConverter.setIconResource(R.drawable.ic_custom_text)
+                ReadBookConfig.textBold = it
+                postEvent(EventBus.UP_CONFIG, arrayListOf(8, 9, 6))
+            }
+        }
+
+        binding.btnShadowSet.setOnClickListener {
+            callBack2?.showShadowSet()
+            dismissAllowingStateLoss()
+        }
+
+        binding.btnSelectFonts.setOnClickListener {
+            callBack2?.showFontSelect()
+            dismissAllowingStateLoss()
+        }
+        binding.btnTextItalic.isChecked = ReadBookConfig.textItalic
+        binding.btnTextShadow.isChecked = ReadBookConfig.textShadow
+        binding.btnShadowColor.color = ReadBookConfig.textShadowColor
+
+    }
+
+    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.btnTextColor.setOnClickListener {
+            ColorPickerDialog.newBuilder()
+                .setColor(ReadBookConfig.durConfig.curTextColor())
+                .setShowAlphaSlider(false)
+                .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
+                .setDialogId(TEXT_COLOR)
+                .show(requireActivity())
+        }
+
+        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.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))
+        }
+        binding.btnTextShadow.addOnCheckedChangeListener { _, isChecked ->
+            ReadBookConfig.textShadow = isChecked
+            postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
+        }
+        binding.btnShadowColor.setOnClickListener {
+            ColorPickerDialog.newBuilder()
+                .setColor(ReadBookConfig.config.curTextShadowColor())
+                .setShowAlphaSlider(false)
+                .setDialogType(ColorPickerDialog.TYPE_CUSTOM)
+                .setDialogId(S_COLOR)
+                .show(requireActivity())
+            //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.progress = it.paragraphSpacing
+        }
+    }
+
+    private fun onDefaultFontChange() {
+        callBack?.selectFont("")
+    }
+
+    private val callBack: CallBack?
+        get() = (parentFragment as? CallBack) ?: (activity as? CallBack)
+
+    interface CallBack {
+        fun selectFont(path: String)
+        val curFontPath: String
+    }
+}

+ 244 - 0
app/src/main/res/layout/dialog_font_config.xml

@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center"
+        android:paddingBottom="8dp"
+        android:paddingHorizontal="16dp">
+
+        <com.google.android.material.bottomsheet.BottomSheetDragHandleView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingVertical="8dp"
+            android:minHeight="0dp"
+            android:layout_gravity="center_horizontal" />
+
+        <TextView
+            android:id="@+id/bottom_sheet_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/text_font"
+            android:textSize="16sp"
+            android:textStyle="bold" />
+
+    </LinearLayout>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginHorizontal="16dp"
+        android:layout_marginBottom="8dp"
+        android:text="@string/text_typeface"
+        android:textSize="14sp"
+        android:textStyle="bold" />
+
+    <com.google.android.material.button.MaterialButtonGroup
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="16dp"
+        android:gravity="center_horizontal">
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btn_textShadow"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+            app:icon="@drawable/ic_shadow"
+            android:checkable="true"
+            android:focusable="true"/>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/sw_underline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+            app:icon="@drawable/ic_underline"
+            android:checkable="true"
+            android:focusable="true"/>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/sw_dottedline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+            app:icon="@drawable/ic_dottedline"
+            android:checkable="true"
+            android:focusable="true"/>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btn_textItalic"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+            app:icon="@drawable/ic_format_italic"
+            android:checkable="true"
+            android:focusable="true"/>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/textFontWeightConverter"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:icon="@drawable/ic_text_weight_2"/>
+
+    </com.google.android.material.button.MaterialButtonGroup>
+
+    <com.google.android.material.button.MaterialButtonGroup
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="4dp"
+        android:gravity="center">
+
+        <io.legado.app.ui.widget.AccentColorButton
+            android:id="@+id/btn_text_color"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            android:text="@string/text_color" />
+
+        <io.legado.app.ui.widget.AccentColorButton
+            android:id="@+id/btnShadowColor"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            android:text="@string/text_shadow_color" />
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btnShadowSet"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
+            app:iconSize="20sp"
+            app:iconGravity="textStart"
+            app:icon="@drawable/ic_fill_colors" />
+
+    </com.google.android.material.button.MaterialButtonGroup>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="end">
+
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:text="@string/paragraph_typeface"
+            android:layout_marginHorizontal="16dp"
+            android:layout_marginVertical="8dp"
+            android:textSize="14sp"
+            android:textStyle="bold" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="bottom">
+
+            <io.legado.app.ui.widget.SimpleSliderView
+                android:id="@+id/btn_indent_layout"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_marginEnd="32dp"
+                app:title="@string/text_indent"
+                app:max="4" />
+
+            <io.legado.app.ui.widget.SimpleSliderView
+                android:id="@+id/sliderFontWeight"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                app:title="@string/font_weight_text"
+                app:min="100"
+                app:max="900" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+
+            <io.legado.app.ui.widget.SimpleSliderView
+                android:id="@+id/dsb_paragraph_spacing"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="32dp"
+                android:layout_weight="1"
+                app:max="20"
+                app:isBottomBackground="true"
+                app:title="@string/paragraph_size" />
+
+            <io.legado.app.ui.widget.SimpleSliderView
+                android:id="@+id/dsb_line_size"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                app:isBottomBackground="true"
+                app:max="20"
+                app:title="@string/line_size" />
+
+        </LinearLayout>
+
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+
+            <io.legado.app.ui.widget.SimpleSliderView
+                android:id="@+id/dsb_text_letter_spacing"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                app:isBottomBackground="true"
+                app:max="100"
+                app:title="@string/text_letter_spacing" />
+
+        </LinearLayout>
+    </LinearLayout>
+
+    <com.google.android.material.button.MaterialButtonGroup
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="end"
+        android:paddingHorizontal="16dp">
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btn_select_fonts"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            android:text="@string/select_font"/>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btn_default_fonts"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            android:text="@string/default_font"/>
+
+    </com.google.android.material.button.MaterialButtonGroup>
+
+</LinearLayout>