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

+ 79 - 8
app/src/main/java/io/legato/kazusa/help/config/ReadBookConfig.kt

@@ -32,6 +32,8 @@ import io.legato.kazusa.utils.putPrefInt
 import io.legato.kazusa.utils.resizeAndRecycle
 import splitties.init.appCtx
 import java.io.File
+import kotlin.String
+import androidx.core.graphics.drawable.toDrawable
 
 /**
  * 阅读界面配置
@@ -58,6 +60,7 @@ object ReadBookConfig {
     var bg: Drawable? = null
     var bgMeanColor: Int = 0
     val textColor: Int get() = durConfig.curTextColor()
+    val textShadowColor: Int get() = durConfig.curTextShadowColor()
 
     init {
         initConfigs()
@@ -246,6 +249,36 @@ object ReadBookConfig {
             config.textBold = value
         }
 
+    var textItalic: Boolean
+        get() = config.textItalic
+        set(value) {
+            config.textItalic = value
+        }
+
+    var textShadow: Boolean
+        get() = config.textShadow
+        set(value) {
+            config.textShadow = value
+        }
+
+    var shadowRadius: Float
+        get() = config.shadowRadius
+        set(value) {
+            config.shadowRadius = value
+        }
+
+    var shadowDx: Float
+        get() = config.shadowDx
+        set(value) {
+            config.shadowDx = value
+        }
+
+    var shadowDy: Float
+        get() = config.shadowDy
+        set(value) {
+            config.shadowDy = value
+        }
+
     var textSize: Int
         get() = config.textSize
         set(value) {
@@ -509,6 +542,13 @@ object ReadBookConfig {
         var textFont: String = "",//字体
         var textBold: Int = 500,//是否粗体字 0:正常, 1:粗体, 2:细体
         var textSize: Int = 20,//文字大小
+        var textItalic: Boolean = false,// 是否启用斜体
+        var textShadow: Boolean = false,// 是否启用阴影
+        var shadowRadius: Float = 16f,// 阴影模糊半径
+        var shadowDx: Float = 1f,// 阴影x偏移
+        var shadowDy: Float = 1f,// 阴影y偏移
+        private var shadowColor: String = "#3E3D3B",
+        private var shadowColorN: String = "#3E3D3B",
         var letterSpacing: Float = 0.1f,//字间距
         var lineSpacingExtra: Int = 12,//行间距
         var paragraphSpacing: Int = 2,//段距
@@ -553,16 +593,37 @@ object ReadBookConfig {
         @Transient
         private var textColorInt = -1
 
+        @Transient
+        private var textColorSIntNight = -1
+
+        @Transient
+        private var textColorSInt = -1
+
         @Transient
         private var initColorInt = false
 
         private fun initColorInt() {
-            textColorIntEInk = Color.parseColor(textColorEInk)
-            textColorIntNight = Color.parseColor(textColorNight)
-            textColorInt = Color.parseColor(textColor)
+            textColorIntEInk = textColorEInk.toColorInt()
+            textColorIntNight = textColorNight.toColorInt()
+            textColorInt = textColor.toColorInt()
+            textColorSIntNight = shadowColorN.toColorInt()
+            textColorSInt = shadowColor.toColorInt()
             initColorInt = true
         }
 
+        fun setCurShadColor(color: Int){
+            when {
+                AppConfig.isNightTheme -> {
+                    shadowColorN = "#${color.hexString}"
+                    textColorSIntNight = color
+                }
+                else -> {
+                    shadowColor = "#${color.hexString}"
+                    textColorSInt = color
+                }
+            }
+        }
+
         fun setCurTextColor(color: Int) {
             when {
                 AppConfig.isEInkMode -> {
@@ -593,6 +654,16 @@ object ReadBookConfig {
             }
         }
 
+        fun curTextShadowColor(): Int {
+            if (!initColorInt) {
+                initColorInt()
+            }
+            return when {
+                AppConfig.isNightTheme -> textColorSIntNight
+                else -> textColorSInt
+            }
+        }
+
         fun setCurStatusIconDark(isDark: Boolean) {
             when {
                 AppConfig.isEInkMode -> darkStatusIconEInk = isDark
@@ -661,18 +732,18 @@ object ReadBookConfig {
         fun curBgDrawable(width: Int, height: Int): Drawable {
             if (width == 0 || height == 0) {
                 val backgroundColor = MaterialColors.getColor(appCtx, com.google.android.material.R.attr.colorSurface, Color.WHITE)
-                return ColorDrawable(backgroundColor)
+                return backgroundColor.toDrawable()
             }
 
             var bgDrawable: Drawable? = null
             val resources = appCtx.resources
             try {
                 bgDrawable = when (curBgType()) {
-                    0 -> ColorDrawable(Color.parseColor(curBgStr()))
+                    0 -> curBgStr().toColorInt().toDrawable()
                     1 -> {
                         val path = "bg" + File.separator + curBgStr()
                         val bitmap = BitmapUtils.decodeAssetsBitmap(appCtx, path, width, height)
-                        BitmapDrawable(resources, bitmap?.resizeAndRecycle(width, height))
+                        bitmap?.resizeAndRecycle(width, height)?.toDrawable(resources)
                     }
                     else -> {
                         val path = curBgStr().let {
@@ -680,7 +751,7 @@ object ReadBookConfig {
                             else FileUtils.getPath(appCtx.externalFiles, "bg", curBgStr())
                         }
                         val bitmap = BitmapUtils.decodeBitmap(path, width, height)
-                        BitmapDrawable(resources, bitmap?.resizeAndRecycle(width, height))
+                        bitmap?.resizeAndRecycle(width, height)?.toDrawable(resources)
                     }
                 }
             } catch (e: OutOfMemoryError) {
@@ -691,7 +762,7 @@ object ReadBookConfig {
 
             // fallback 使用 MD3 的 colorSurface 作为背景色
             val fallbackColor = MaterialColors.getColor(appCtx, com.google.android.material.R.attr.colorSurface, Color.WHITE)
-            return bgDrawable ?: ColorDrawable(fallbackColor)
+            return bgDrawable ?: fallbackColor.toDrawable()
         }
     }
 }

+ 5 - 0
app/src/main/java/io/legato/kazusa/ui/book/read/ReadBookActivity.kt

@@ -76,6 +76,7 @@ import io.legato.kazusa.ui.book.info.BookInfoActivity
 import io.legato.kazusa.ui.book.read.config.AutoReadDialog
 import io.legato.kazusa.ui.book.read.config.BgTextConfigDialog.Companion.BG_COLOR
 import io.legato.kazusa.ui.book.read.config.BgTextConfigDialog.Companion.TEXT_COLOR
+import io.legato.kazusa.ui.book.read.config.FontSelectDialog.Companion.S_COLOR
 import io.legato.kazusa.ui.book.read.config.ReadAloudDialog
 import io.legato.kazusa.ui.book.read.config.ReadStyleDialog
 import io.legato.kazusa.ui.book.read.config.TipConfigDialog.Companion.TIP_COLOR
@@ -1504,6 +1505,10 @@ class ReadBookActivity : BaseReadBookActivity(),
      */
     override fun onColorSelected(dialogId: Int, color: Int) = ReadBookConfig.durConfig.run {
         when (dialogId) {
+            S_COLOR -> {
+                setCurShadColor(color)
+                postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6, 9, 11))
+            }
             TEXT_COLOR -> {
                 setCurTextColor(color)
                 postEvent(EventBus.UP_CONFIG, arrayListOf(2, 6, 9, 11))

+ 55 - 17
app/src/main/java/io/legato/kazusa/ui/book/read/config/FontSelectDialog.kt

@@ -1,17 +1,19 @@
 package io.legato.kazusa.ui.book.read.config
 
-//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 android.widget.ArrayAdapter
 import androidx.appcompat.widget.Toolbar
+import io.legato.kazusa.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.legato.kazusa.R
 import io.legato.kazusa.base.BaseBottomSheetDialogFragment
 import io.legato.kazusa.base.adapter.ItemViewHolder
@@ -22,7 +24,6 @@ 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
@@ -54,6 +55,10 @@ import java.net.URLDecoder
  */
 class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_select),
     Toolbar.OnMenuItemClickListener {
+
+    companion object {
+        const val S_COLOR = 123
+    }
     private val fontRegex = Regex("(?i).*\\.[ot]tf")
     private val binding by viewBinding(DialogFontSelectBinding::bind)
     private val adapter by lazy {
@@ -118,21 +123,19 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
             ((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))
-                }
+        binding.dsbShadowRadius.valueFormat = { "${it.toInt()} px" }
+        binding.dsbShadowDx.valueFormat = { "${it.toInt()} px" }
+        binding.dsbShadowDy.valueFormat = { "${it.toInt()} 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)
+                postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
             }
         }
 
@@ -166,6 +169,9 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
                 postEvent(EventBus.UP_CONFIG, arrayListOf(8, 9, 6))
             }
         }
+
+        binding.btnTextItalic.isChecked = ReadBookConfig.textItalic
+        binding.btnTextShadow.isChecked = ReadBookConfig.textShadow
     }
 
     private fun initViewEvent() = binding.run {
@@ -192,6 +198,35 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
                 }
             }
         }
+        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.dsbShadowRadius.onChanged = {
+            ReadBookConfig.shadowRadius = it.toFloat()
+            postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
+        }
+        binding.dsbShadowDx.onChanged = {
+            ReadBookConfig.shadowDx = it.toFloat()
+            postEvent(EventBus.UP_CONFIG, arrayListOf(8, 5))
+        }
+        binding.dsbShadowDy.onChanged = {
+            ReadBookConfig.shadowDy = it.toFloat()
+            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 {
@@ -199,6 +234,9 @@ class FontSelectDialog : BaseBottomSheetDialogFragment(R.layout.dialog_font_sele
             dsbTextLetterSpacing.progress = (it.letterSpacing * 100).toInt() + 50
             dsbLineSize.progress = it.lineSpacingExtra
             dsbParagraphSpacing.value = it.paragraphSpacing.toFloat()
+            binding.dsbShadowRadius.progress = it.shadowRadius.toInt()
+            binding.dsbShadowDx.progress = it.shadowDx.toInt()
+            binding.dsbShadowDy.progress = it.shadowDy.toInt()
         }
     }
 

+ 26 - 1
app/src/main/java/io/legato/kazusa/ui/book/read/page/provider/ChapterProvider.kt

@@ -1,5 +1,7 @@
 package io.legato.kazusa.ui.book.read.page.provider
 
+import android.annotation.SuppressLint
+import android.graphics.Color
 import android.graphics.Paint.FontMetrics
 import android.graphics.RectF
 import android.graphics.Typeface
@@ -38,6 +40,7 @@ import splitties.init.appCtx
 import java.io.File
 import java.util.LinkedList
 import java.util.Locale
+import androidx.core.graphics.toColorInt
 
 /**
  * 解析内容生成章节和页面
@@ -910,6 +913,7 @@ object ChapterProvider {
         } ?: Typeface.DEFAULT
     }
 
+    @SuppressLint("UseKtx")
     private fun getPaints(typeface: Typeface?): Pair<TextPaint, TextPaint> {
         val bold = Typeface.create(typeface, Typeface.BOLD)
         val normal = Typeface.create(typeface, Typeface.NORMAL)
@@ -952,6 +956,17 @@ object ChapterProvider {
         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q && AppConfig.optimizeRender) {
             tPaint.isLinearText = true
         }
+        if (ReadBookConfig.textItalic) {
+            tPaint.textSkewX = -0.25f
+        }
+        if (ReadBookConfig.textShadow) {
+            tPaint.setShadowLayer(
+                ReadBookConfig.shadowRadius,
+                ReadBookConfig.shadowDx,
+                ReadBookConfig.shadowDy,
+                ReadBookConfig.textShadowColor
+            )
+        }
         //正文
         val cPaint = TextPaint()
         cPaint.color = ReadBookConfig.textColor
@@ -964,7 +979,17 @@ object ChapterProvider {
         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q && AppConfig.optimizeRender) {
             cPaint.isLinearText = true
         }
-
+        if (ReadBookConfig.textItalic) {
+            cPaint.textSkewX = -0.25f
+        }
+        if (ReadBookConfig.textShadow) {
+            cPaint.setShadowLayer(
+                ReadBookConfig.shadowRadius,
+                ReadBookConfig.shadowDx,
+                ReadBookConfig.shadowDy,
+                ReadBookConfig.textShadowColor
+            )
+        }
         return Pair(tPaint, cPaint)
     }
 

+ 10 - 0
app/src/main/res/drawable/ic_format_italic.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M200,760L200,660L360,660L480,300L320,300L320,200L720,200L720,300L580,300L460,660L600,660L600,760L200,760Z"/>
+</vector>

+ 10 - 0
app/src/main/res/drawable/ic_shadow.xml

@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M160,880Q127,880 103.5,856.5Q80,833 80,800L80,320Q80,287 103.5,263.5Q127,240 160,240L240,240L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,640Q880,673 856.5,696.5Q833,720 800,720L720,720L720,800Q720,833 696.5,856.5Q673,880 640,880L160,880ZM320,640L800,640Q800,640 800,640Q800,640 800,640L800,160Q800,160 800,160Q800,160 800,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640Z"/>
+</vector>

+ 167 - 120
app/src/main/res/layout/dialog_font_select.xml

@@ -11,28 +11,53 @@
         android:layout_height="wrap_content"
         android:theme="?attr/actionBarStyle" />
 
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="16dp"
+        android:text="@string/text_font"
+        android:textSize="12sp"
+        android:textStyle="bold" />
+
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        android:paddingStart="16dp"
-        android:paddingEnd="2dp">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/text_font_weight_converter"
-            android:textSize="12sp"
-            android:textStyle="bold" />
+        android:paddingStart="10dp"
+        android:paddingEnd="10dp">
 
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/textFontWeightConverter"
-            style="@style/Widget.Material3Expressive.Button.TonalButton"
+        <com.google.android.material.button.MaterialButtonGroup
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginStart="12dp"
-            android:minWidth="80dp"
-            android:textSize="12sp" />
+            android:gravity="center_vertical">
+
+            <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/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/textFontWeightConverter"
+                style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minWidth="0dp"
+                android:textSize="12sp" />
+
+        </com.google.android.material.button.MaterialButtonGroup>
 
         <com.google.android.material.slider.Slider
             android:id="@+id/sliderFontWeight"
@@ -47,70 +72,141 @@
         android:layout_marginHorizontal="16dp"
         android:orientation="vertical">
 
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:layout_marginBottom="4dp"
-            android:text="@string/text_indent"
-            android:textSize="12sp"
-            android:textStyle="bold" />
-
-        <com.google.android.material.button.MaterialButtonToggleGroup
-            android:id="@+id/bgTextIndent"
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="center"
-            android:spacing="2dp"
-            app:innerCornerSize="8dp"
-            app:selectionRequired="true"
-            app:singleSelection="true">
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
 
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/btnIndent0"
-                style="@style/Widget.Material3Expressive.Button.OutlinedButton"
-                android:layout_width="0dp"
+            <io.legato.kazusa.ui.widget.SimpleCounterView
+                android:id="@+id/dsb_shadow_dx"
+                android:layout_width="120dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="0"
-                android:textStyle="bold" />
+                app:isBottomBackground="true"
+                app:max="20"
+                app:title="@string/text_shadow_x" />
 
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/btnIndent1"
-                style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            <View
                 android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"/>
+
+            <io.legato.kazusa.ui.widget.SimpleCounterView
+                android:id="@+id/dsb_shadow_dy"
+                android:layout_width="120dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="1"
-                android:textStyle="bold" />
+                app:isBottomBackground="true"
+                app:max="20"
+                app:title="@string/text_shadow_y" />
 
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/btnIndent2"
-                style="@style/Widget.Material3Expressive.Button.OutlinedButton"
-                android:layout_width="0dp"
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="bottom">
+
+            <io.legato.kazusa.ui.widget.SimpleCounterView
+                android:id="@+id/dsb_shadow_radius"
+                android:layout_width="120dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="2"
-                android:textStyle="bold" />
+                android:layout_marginBottom="4dp"
+                app:isBottomBackground="true"
+                app:max="50"
+                app:title="@string/text_shadow_radius" />
 
-            <com.google.android.material.button.MaterialButton
-                android:id="@+id/btnIndent3"
-                style="@style/Widget.Material3Expressive.Button.OutlinedButton"
+            <View
                 android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="3"
-                android:textStyle="bold" />
+                android:layout_height="match_parent"
+                android:layout_weight="1"/>
 
             <com.google.android.material.button.MaterialButton
-                android:id="@+id/btnIndent4"
+                android:id="@+id/btnShadowColor"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
                 style="@style/Widget.Material3Expressive.Button.OutlinedButton"
-                android:layout_width="0dp"
+                android:text="@string/text_shadow_color" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+            <com.google.android.material.textfield.TextInputLayout
+                android:id="@+id/textInputIndentLayout"
+                android:layout_width="120dp"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="8dp"
+                style="@style/Widget.Material3.TextInputLayout.FilledBox.Dense.ExposedDropdownMenu"
+                android:hint="@string/text_indent">
+
+                <com.google.android.material.textfield.MaterialAutoCompleteTextView
+                    android:id="@+id/textIndentDropdown"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:inputType="none"
+                    android:focusable="false"
+                    android:clickable="true" />
+            </com.google.android.material.textfield.TextInputLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:text="4"
-                android:textStyle="bold" />
-        </com.google.android.material.button.MaterialButtonToggleGroup>
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginHorizontal="16dp"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center_vertical"
+                        android:layout_weight="1"
+                        android:text="@string/paragraph_size"
+                        android:textSize="12sp"
+                        android:textStyle="bold" />
+
+                    <com.google.android.material.card.MaterialCardView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:cardBackgroundColor="?attr/colorSurfaceContainer"
+                        app:cardCornerRadius="4dp"
+                        app:strokeWidth="0dp">
+
+                        <TextView
+                            android:id="@+id/textParagraphSpacing"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="4dp"
+                            android:paddingVertical="2dp"
+                            android:text="@string/text"
+                            android:textSize="12sp"
+                            android:textStyle="bold" />
+                    </com.google.android.material.card.MaterialCardView>
+
+                </LinearLayout>
+
+                <com.google.android.material.slider.Slider
+                    android:id="@+id/dsb_paragraph_spacing"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:stepSize="1"
+                    android:valueFrom="0"
+                    android:valueTo="20"
+                    app:isBottomBackground="true"
+                    app:thumbHeight="24dp"
+                    app:title="@string/paragraph_size"
+                    app:trackHeight="24dp" />
+            </LinearLayout>
+
+        </LinearLayout>
+
 
         <LinearLayout
             android:layout_width="match_parent"
@@ -121,19 +217,21 @@
 
             <io.legato.kazusa.ui.widget.SimpleCounterView
                 android:id="@+id/dsb_line_size"
-                android:layout_width="0dp"
+                android:layout_width="120dp"
                 android:layout_height="wrap_content"
-                android:layout_marginEnd="32dp"
-                android:layout_weight="1"
                 app:isBottomBackground="true"
                 app:max="20"
                 app:title="@string/line_size" />
 
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"/>
+
             <io.legato.kazusa.ui.widget.SimpleCounterView
                 android:id="@+id/dsb_text_letter_spacing"
-                android:layout_width="0dp"
+                android:layout_width="120dp"
                 android:layout_height="wrap_content"
-                android:layout_weight="1"
                 app:isBottomBackground="true"
                 app:max="100"
                 app:title="@string/text_letter_spacing" />
@@ -141,57 +239,6 @@
         </LinearLayout>
     </LinearLayout>
 
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginHorizontal="16dp"
-        android:layout_marginTop="8dp"
-        android:orientation="horizontal">
-
-        <TextView
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:layout_weight="1"
-            android:text="@string/paragraph_size"
-            android:textSize="12sp"
-            android:textStyle="bold" />
-
-        <com.google.android.material.card.MaterialCardView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            app:cardBackgroundColor="?attr/colorSurfaceContainer"
-            app:cardCornerRadius="4dp"
-            app:strokeWidth="0dp">
-
-            <TextView
-                android:id="@+id/textParagraphSpacing"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="center_vertical"
-                android:paddingHorizontal="4dp"
-                android:paddingVertical="2dp"
-                android:text="@string/text"
-                android:textSize="12sp"
-                android:textStyle="bold" />
-        </com.google.android.material.card.MaterialCardView>
-
-    </LinearLayout>
-
-    <com.google.android.material.slider.Slider
-        android:id="@+id/dsb_paragraph_spacing"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginHorizontal="4dp"
-        android:stepSize="1"
-        android:valueFrom="0"
-        android:valueTo="20"
-        app:isBottomBackground="true"
-        app:thumbHeight="24dp"
-        app:title="@string/paragraph_size"
-        app:trackHeight="24dp" />
-
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/recycler_view"
         android:layout_width="match_parent"

+ 1 - 3
app/src/main/res/layout/view_simple_counter.xml

@@ -33,7 +33,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginVertical="4dp"
-                android:maxWidth="48sp"
+                android:maxWidth="56sp"
                 android:maxLines="2"
                 android:text="@string/text"
                 android:textColor="?android:attr/textColorSecondary"
@@ -63,7 +63,6 @@
                         android:layout_weight="3"
                         android:minWidth="64dp"
                         android:contentDescription="@string/reduce"
-                        android:elevation="4dp"
                         app:backgroundTint="?attr/colorSurfaceContainer"
                         app:icon="@drawable/ic_reduce"
                         app:iconGravity="textStart"
@@ -88,7 +87,6 @@
                         android:layout_weight="3"
                         android:minWidth="64dp"
                         android:contentDescription="@string/plus"
-                        android:elevation="4dp"
                         app:backgroundTint="?attr/colorSurfaceContainer"
                         app:icon="@drawable/ic_add"
                         app:iconGravity="textStart"

+ 4 - 0
app/src/main/res/values-zh/strings.xml

@@ -1305,4 +1305,8 @@
     <string name="read_type_long">长按设置为全局默认模式</string>
     <string name="read_slider_mode">滑动条显示样式</string>
     <string name="bookshelf_update_limit">书架更新数量限制</string>
+    <string name="text_shadow_x">X轴距离</string>
+    <string name="text_shadow_y">Y轴距离</string>
+    <string name="text_shadow_radius">阴影半径</string>
+    <string name="text_shadow_color">阴影颜色</string>
 </resources>

+ 4 - 0
app/src/main/res/values/strings.xml

@@ -1306,4 +1306,8 @@
     <string name="read_type_long">长按设置为全局默认模式</string>
     <string name="read_slider_mode">滑动条显示样式</string>
     <string name="bookshelf_update_limit">书架更新数量限制</string>
+    <string name="text_shadow_x">X轴距离</string>
+    <string name="text_shadow_y">Y轴距离</string>
+    <string name="text_shadow_radius">阴影半径</string>
+    <string name="text_shadow_color">阴影颜色</string>
 </resources>