Просмотр исходного кода

新增漫画阅读模式[条漫、日漫等]
新增条漫侧边留白功能
更新滤镜功能,现在支持亮度跟随系统
其他界面更新

HapeLee 1 год назад
Родитель
Сommit
1701285d33
24 измененных файлов с 585 добавлено и 277 удалено
  1. 2 0
      app/src/main/java/io/legato/kazusa/constant/PreferKey.kt
  2. 2 0
      app/src/main/java/io/legato/kazusa/data/entities/Book.kt
  3. 16 0
      app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt
  4. 1 1
      app/src/main/java/io/legato/kazusa/model/ReadManga.kt
  5. 164 77
      app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt
  6. 0 24
      app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt
  7. 27 0
      app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaScrollMode.kt
  8. 103 0
      app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaScrollModeDialog.kt
  9. 11 9
      app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/MangaAdapter.kt
  10. 2 2
      app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt
  11. 2 1
      app/src/main/java/io/legato/kazusa/ui/book/read/MangaMenu.kt
  12. 21 30
      app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt
  13. 6 11
      app/src/main/java/io/legato/kazusa/ui/widget/DetailSeekBar.kt
  14. 16 3
      app/src/main/java/io/legato/kazusa/ui/widget/SimpleCounterView.kt
  15. 11 0
      app/src/main/res/drawable/ic_filter.xml
  16. 8 7
      app/src/main/res/layout/activity_manga.xml
  17. 3 28
      app/src/main/res/layout/dialog_manga_footer_setting.xml
  18. 137 0
      app/src/main/res/layout/dialog_manga_scroll_mode.xml
  19. 30 8
      app/src/main/res/layout/item_book_manga_edge.xml
  20. 14 14
      app/src/main/res/layout/item_book_manga_page.xml
  21. 7 34
      app/src/main/res/layout/view_detail_seek_bar.xml
  22. 0 27
      app/src/main/res/menu/book_manga.xml
  23. 1 1
      app/src/main/res/values-zh/strings.xml
  24. 1 0
      app/src/main/res/values/attrs.xml

+ 2 - 0
app/src/main/java/io/legato/kazusa/constant/PreferKey.kt

@@ -190,4 +190,6 @@ object PreferKey {
     const val themePref = "themePref"
     const val bookshelfSortOrder = "bookshelfSortOrder"
     const val showBottomView = "showBottomView"
+    const val mangaScrollMode = "mangaScrollMode"
+    const val webtoonSidePaddingDp = "webtoonSidePaddingDp"
 }

+ 2 - 0
app/src/main/java/io/legato/kazusa/data/entities/Book.kt

@@ -403,6 +403,8 @@ data class Book(
         var startDate: LocalDate? = null,
         var startChapter: Int? = null,     // 用户设置的起始章节
         var dailyChapters: Int = 3    // 用户设置的每日更新章节数
+
+
     ) : Parcelable
 
     class Converters {

+ 16 - 0
app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt

@@ -5,6 +5,7 @@ import android.os.Build
 import io.legato.kazusa.BuildConfig
 import io.legato.kazusa.constant.PreferKey
 import io.legato.kazusa.data.appDb
+import io.legato.kazusa.ui.book.manga.config.MangaScrollMode
 import io.legato.kazusa.utils.canvasrecorder.CanvasRecorderFactory
 import io.legato.kazusa.utils.getPrefBoolean
 import io.legato.kazusa.utils.getPrefInt
@@ -664,6 +665,14 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
             appCtx.putPrefBoolean(PreferKey.enableMangaHorizontalScroll, value)
         }
 
+    //漫画滚动方式
+    var mangaScrollMode: Int
+        get() = appCtx.getPrefInt(PreferKey.mangaScrollMode, MangaScrollMode.PAGE_RIGHT_TO_LEFT)
+        set(value) {
+            appCtx.putPrefInt(PreferKey.mangaScrollMode, value)
+        }
+
+    //漫画滤镜
     var mangaColorFilter
         get() = appCtx.getPrefString(PreferKey.mangaColorFilter, "")
         set(value) {
@@ -701,5 +710,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
         set(value) {
             appCtx.putPrefBoolean(PreferKey.enableMangaGray, value)
         }
+
+    var webtoonSidePaddingDp: Int
+        get() = appCtx.getPrefInt(PreferKey.webtoonSidePaddingDp, 0)
+        set(value) {
+            appCtx.putPrefInt(PreferKey.webtoonSidePaddingDp, value)
+        }
+
 }
 

+ 1 - 1
app/src/main/java/io/legato/kazusa/model/ReadManga.kt

@@ -607,7 +607,7 @@ object ReadManga : CoroutineScope by MainScope() {
         if (imageCount == 0 && chapter.isVolume) {
             pages.add(ReaderLoading(chapter.index, -1, chapter.title, true))
         } else {
-            pages.add(ReaderLoading(chapter.index, -1, "阅读 ${chapter.title}"))
+            pages.add(ReaderLoading(chapter.index, -1, "下一章 ${chapter.title}"))
             pages.addAll(list)
             pages.add(ReaderLoading(chapter.index, imageCount, "已读完 ${chapter.title}"))
         }

+ 164 - 77
app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt

@@ -12,6 +12,7 @@ import android.view.WindowManager
 import android.view.animation.LinearInterpolator
 import androidx.activity.viewModels
 import androidx.appcompat.app.AlertDialog
+import androidx.core.view.doOnLayout
 import androidx.core.view.isGone
 import androidx.core.view.isVisible
 import androidx.lifecycle.lifecycleScope
@@ -45,6 +46,8 @@ import io.legato.kazusa.ui.book.manga.config.MangaColorFilterConfig
 import io.legato.kazusa.ui.book.manga.config.MangaColorFilterDialog
 import io.legato.kazusa.ui.book.manga.config.MangaFooterConfig
 import io.legato.kazusa.ui.book.manga.config.MangaFooterSettingDialog
+import io.legato.kazusa.ui.book.manga.config.MangaScrollMode
+import io.legato.kazusa.ui.book.manga.config.MangaScrollModeDialog
 import io.legato.kazusa.ui.book.manga.entities.BaseMangaPage
 import io.legato.kazusa.ui.book.manga.entities.MangaPage
 import io.legato.kazusa.ui.book.manga.recyclerview.MangaAdapter
@@ -77,11 +80,13 @@ import kotlin.math.ceil
 
 class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewModel>(),
     ReadManga.Callback, ChangeBookSourceDialog.CallBack, MangaMenu.CallBack,
-    MangaColorFilterDialog.Callback, ScrollTimer.ScrollCallback, MangaFooterSettingDialog.Callback {
+    MangaColorFilterDialog.Callback, ScrollTimer.ScrollCallback, MangaFooterSettingDialog.Callback,
+    MangaScrollModeDialog.Callback {
 
     private val mLayoutManager by lazy {
         MangaLayoutManager(this)
     }
+
     private val mAdapter: MangaAdapter by lazy {
         MangaAdapter(this)
     }
@@ -99,6 +104,8 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
 
     private var mMenu: Menu? = null
 
+    private var scrollMode: Int = MangaScrollMode.PAGE_LEFT_TO_RIGHT
+
     private var mRecyclerViewPreloader: RecyclerViewPreloader<Any>? = null
 
     private val networkChangedListener by lazy {
@@ -192,7 +199,8 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
             enableMangaEInk(AppConfig.enableMangaEInk, AppConfig.mangaEInkThreshold)
             enableGray(AppConfig.enableMangaGray)
         }
-        setHorizontalScroll(AppConfig.enableMangaHorizontalScroll)
+        //setHorizontalScroll(AppConfig.enableMangaHorizontalScroll)
+        setScrollMode(AppConfig.mangaScrollMode)
         binding.recyclerView.run {
             adapter = mAdapter
             itemAnimator = null
@@ -201,6 +209,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
             setDisableClickScroll(AppConfig.disableClickScroll)
             setDisableMangaScale(AppConfig.disableMangaScale)
             setRecyclerViewPreloader(AppConfig.mangaPreDownloadNum)
+            updateWebtoonSidePadding(AppConfig.webtoonSidePaddingDp)
             setPreScrollListener { _, _, _, position ->
                 if (mAdapter.isNotEmpty()) {
                     val item = mAdapter.getItem(position)
@@ -431,10 +440,26 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         binding.recyclerView.smoothScrollBy(10000, 10000, mLinearInterpolator, time)
     }
 
-    override fun scrollPage() {
-        scrollToNext()
+    override fun scrollPage(direction: Int) {
+        if (scrollMode == MangaScrollMode.WEBTOON || scrollMode == MangaScrollMode.WEBTOON_WITH_GAP) {
+            // 条漫平滑滚动距离
+            val dy =
+                (binding.recyclerView.height - binding.recyclerView.paddingTop - binding.recyclerView.paddingBottom) * direction
+            binding.recyclerView.smoothScrollBy(0, dy)
+        } else {
+            // 分页按 position 翻页
+            val layoutManager = binding.recyclerView.layoutManager as? LinearLayoutManager ?: return
+            val currentPosition = layoutManager.findFirstVisibleItemPosition()
+            val nextPosition = currentPosition + direction
+            val itemCount = binding.recyclerView.adapter?.itemCount ?: return
+
+            if (nextPosition in 0 until itemCount) {
+                binding.recyclerView.smoothScrollToPosition(nextPosition)
+            }
+        }
     }
 
+
     override val oldBook: Book?
         get() = ReadManga.book
 
@@ -495,46 +520,11 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
                 }
             }
 
-            R.id.menu_disable_manga_scale -> {
-                item.isChecked = !item.isChecked
-                AppConfig.disableMangaScale = item.isChecked
-                setDisableMangaScale(item.isChecked)
-            }
-
-            R.id.menu_disable_click_scroll -> {
-                item.isChecked = !item.isChecked
-                AppConfig.disableClickScroll = item.isChecked
-                setDisableClickScroll(item.isChecked)
-            }
-
-            R.id.menu_enable_horizontal_scroll -> {
-                item.isChecked = !item.isChecked
-                AppConfig.enableMangaHorizontalScroll = item.isChecked
-                mMenu?.findItem(R.id.menu_disable_horizontal_animation)?.isVisible = item.isChecked
-                setHorizontalScroll(item.isChecked)
-                mAdapter.notifyDataSetChanged()
-            }
-
             R.id.menu_manga_color_filter -> {
                 binding.mangaMenu.runMenuOut()
                 showDialogFragment(MangaColorFilterDialog())
             }
 
-            R.id.menu_enable_auto_scroll -> {
-                item.isChecked = !item.isChecked
-                mScrollTimer.isEnabled = item.isChecked
-
-                enableAutoScroll = item.isChecked
-                enableAutoScrollPage = false
-                mScrollTimer.isEnabledPage = false
-
-                if (enableAutoScroll) {
-                    mPagerSnapHelper.attachToRecyclerView(null)
-                } else if (AppConfig.enableMangaHorizontalScroll) {
-                    mPagerSnapHelper.attachToRecyclerView(binding.recyclerView)
-                }
-            }
-
             R.id.menu_hide_manga_title -> {
                 item.isChecked = !item.isChecked
                 AppConfig.hideMangaTitle = item.isChecked
@@ -577,6 +567,40 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         showDialogFragment(MangaColorFilterDialog())
     }
 
+    override fun showScrollModeDialog() {
+        showDialogFragment(MangaScrollModeDialog().apply {
+            initialScrollMode = AppConfig.mangaScrollMode
+            callback = this@ReadMangaActivity
+        })
+    }
+
+    //漫画模式
+    override fun onScrollModeChanged(mode: Int) {
+        AppConfig.mangaScrollMode = mode
+        setScrollMode(mode)
+        updateWebtoonSidePadding(AppConfig.webtoonSidePaddingDp)
+        setAutoReadEnabled(false)
+    }
+
+    //点击滑动
+    override fun onClickScrollDisabledChanged(enabled: Boolean) {
+        AppConfig.disableClickScroll = enabled
+        setDisableClickScroll(enabled)
+    }
+
+    //双击缩放
+    override fun onMangaScaleDisabledChanged(enabled: Boolean) {
+        AppConfig.disableMangaScale = enabled
+        setDisableMangaScale(enabled)
+    }
+
+    //侧边留白
+    override fun upSidePadding(paddingDp: Int) {
+        AppConfig.webtoonSidePaddingDp = paddingDp
+        updateWebtoonSidePadding(paddingDp)
+    }
+
+    //墨水屏
     override fun updateEpaperMode(enabled: Boolean, threshold: Int) {
         AppConfig.enableMangaEInk = enabled
         AppConfig.enableMangaGray = false
@@ -584,12 +608,28 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         mAdapter.enableMangaEInk(enabled, threshold)
     }
 
+    //灰度
     override fun updateGrayMode(enabled: Boolean) {
         AppConfig.enableMangaGray = enabled
         AppConfig.enableMangaEInk = false
         mAdapter.enableGray(enabled)
     }
 
+    //自动翻页
+    override fun onAutoPageToggle(enabled: Boolean) {
+        setAutoReadEnabled(enabled)
+    }
+
+    //自动翻页速度
+    override fun onAutoPageSpeedChanged(speed: Int) {
+        setAutoReadEnabled(false)
+        AppConfig.mangaAutoPageSpeed = speed
+        mScrollTimer.setSpeed(speed)
+        setAutoReadEnabled(true)
+//        if (enableAutoScrollPage) {
+//            mScrollTimer.isEnabledPage = true
+//        }
+    }
 
     override fun openBookInfoActivity() {
         ReadManga.book?.let {
@@ -600,22 +640,27 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         }
     }
 
-    override fun onAutoPageToggle(enabled: Boolean) {
-        mScrollTimer.isEnabledPage = enabled
-        mScrollTimer.isEnabled = false
-
-        enableAutoScrollPage = enabled
-        enableAutoScroll = false
-
-        mMenu?.findItem(R.id.menu_enable_auto_scroll)?.isChecked = false
-    }
-
-    override fun onAutoPageSpeedChanged(speed: Int) {
-        AppConfig.mangaAutoPageSpeed = speed
-        mScrollTimer.setSpeed(speed)
-
-        if (enableAutoScrollPage) {
-            mScrollTimer.isEnabledPage = true
+    //1 自动翻页 2 自动滚动 0 关闭
+    fun setAutoReadEnabled(enabled: Boolean) {
+        val isWebtoonMode =
+            scrollMode == MangaScrollMode.WEBTOON || scrollMode == MangaScrollMode.WEBTOON_WITH_GAP
+        if (enabled) {
+            if (isWebtoonMode) {
+                mScrollTimer.isEnabled = true
+                enableAutoScroll = true
+                enableAutoScrollPage = false
+                mScrollTimer.isEnabledPage = false
+            } else {
+                mScrollTimer.isEnabledPage = true
+                enableAutoScrollPage = true
+                enableAutoScroll = false
+                mScrollTimer.isEnabled = false
+            }
+        } else {
+            enableAutoScroll = false
+            enableAutoScrollPage = false
+            mScrollTimer.isEnabled = false
+            mScrollTimer.isEnabledPage = false
         }
     }
 
@@ -648,6 +693,70 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         return super.dispatchKeyEvent(event)
     }
 
+    @SuppressLint("NotifyDataSetChanged")
+    private fun setScrollMode(mode: Int) {
+        scrollMode = mode
+
+        val isHorizontalPage =
+            mode == MangaScrollMode.PAGE_LEFT_TO_RIGHT || mode == MangaScrollMode.PAGE_RIGHT_TO_LEFT
+
+        val isWebtoon = mode == MangaScrollMode.WEBTOON || mode == MangaScrollMode.WEBTOON_WITH_GAP
+
+        when (mode) {
+            MangaScrollMode.PAGE_LEFT_TO_RIGHT -> {
+                mLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
+                mLayoutManager.reverseLayout = false
+            }
+
+            MangaScrollMode.PAGE_RIGHT_TO_LEFT -> {
+                mLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
+                mLayoutManager.reverseLayout = true
+            }
+
+            MangaScrollMode.PAGE_TOP_TO_BOTTOM,
+            MangaScrollMode.WEBTOON,
+            MangaScrollMode.WEBTOON_WITH_GAP -> {
+                mLayoutManager.orientation = LinearLayoutManager.VERTICAL
+                mLayoutManager.reverseLayout = false
+            }
+        }
+
+        mAdapter.isHorizontal = isHorizontalPage || mode == MangaScrollMode.PAGE_TOP_TO_BOTTOM
+
+        if (!isWebtoon) {
+            mPagerSnapHelper.attachToRecyclerView(binding.recyclerView)
+        } else {
+            mPagerSnapHelper.attachToRecyclerView(null)
+        }
+
+        mAdapter.notifyDataSetChanged()
+    }
+
+    /**
+     * 调整条漫侧边留白设置
+     * @param paddingDp 侧边留白距离,单位dp,默认16dp
+     */
+    private fun updateWebtoonSidePadding(paddingDp: Int) {
+        if (scrollMode != MangaScrollMode.WEBTOON && scrollMode != MangaScrollMode.WEBTOON_WITH_GAP) {
+            // 非条漫模式,取消留白
+            binding.recyclerView.setPadding(0, 0, 0, 0)
+            binding.recyclerView.clipToPadding = true
+            return
+        }
+
+        binding.recyclerView.doOnLayout { recyclerView ->
+            val width = recyclerView.width
+            if (paddingDp == 0) {
+                recyclerView.setPadding(0, 0, 0, 0)
+            } else if (width > 0) {
+                val paddingPx = (width * paddingDp / 100).toInt()
+                recyclerView.setPadding(paddingPx, 0, paddingPx, 0)
+            }
+        }
+
+    }
+
+
     private fun setRecyclerViewPreloader(maxPreload: Int) {
         if (mRecyclerViewPreloader != null) {
             binding.recyclerView.removeOnScrollListener(mRecyclerViewPreloader!!)
@@ -658,33 +767,11 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
         binding.recyclerView.addOnScrollListener(mRecyclerViewPreloader!!)
     }
 
-    private fun setHorizontalScroll(enable: Boolean) {
-        mAdapter.isHorizontal = enable
-        if (enable) {
-            if (!enableAutoScroll) {
-                mPagerSnapHelper.attachToRecyclerView(binding.recyclerView)
-                if (AppConfig.disableHorizontalAnimator) {
-                    mPagerSnapHelper.attachToRecyclerView(null)
-                } else {
-                    mPagerSnapHelper.attachToRecyclerView(binding.recyclerView)
-                }
-            }
-            mLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
-        } else {
-            mPagerSnapHelper.attachToRecyclerView(null)
-            mLayoutManager.orientation = LinearLayoutManager.VERTICAL
-        }
-    }
-
     @SuppressLint("StringFormatMatches")
     private fun upMenu(menu: Menu) {
         this.mMenu = menu
         menu.findItem(R.id.menu_pre_manga_number).title =
             getString(R.string.pre_download_m, AppConfig.mangaPreDownloadNum)
-        menu.findItem(R.id.menu_disable_manga_scale).isChecked = AppConfig.disableMangaScale
-        menu.findItem(R.id.menu_disable_click_scroll).isChecked = AppConfig.disableClickScroll
-        menu.findItem(R.id.menu_enable_horizontal_scroll).isChecked =
-            AppConfig.enableMangaHorizontalScroll
         menu.findItem(R.id.menu_hide_manga_title).isChecked = AppConfig.hideMangaTitle
 
         menu.findItem(R.id.menu_disable_horizontal_animation).run {

+ 0 - 24
app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt

@@ -129,38 +129,14 @@ class MangaFooterSettingDialog :
             postEvent(EventBus.UP_MANGA_CONFIG, config)
         }
 
-
-        binding.chipAutoPage.run {
-            isChecked = initialAutoPageEnabled
-            setOnCheckedChangeListener { _, isChecked ->
-                callback?.onAutoPageToggle(isChecked)
-                initAutoPageSpeed(isChecked)
-            }
-        }
-
         binding.btnColorFilter.setOnClickListener {
             callback?.showColorFilterConfig()
             dismiss()
         }
 
-        initAutoPageSpeed(initialAutoPageEnabled)
-
         updateChapterText()
     }
 
-    private fun initAutoPageSpeed(boolean: Boolean) {
-        TransitionManager.beginDelayedTransition(binding.rootView)
-        binding.scvAutoPageSpeed.run {
-            isEnabled = boolean
-            valueFormat = { "$it 秒" }
-            progress = initialAutoPageSpeed
-
-            onChanged = { newValue ->
-                callback?.onAutoPageSpeedChanged(newValue)
-            }
-        }
-    }
-
     override fun onDismiss(dialog: DialogInterface) {
         super.onDismiss(dialog)
         AppConfig.mangaFooterConfig = GSON.toJson(config)

+ 27 - 0
app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaScrollMode.kt

@@ -0,0 +1,27 @@
+package io.legato.kazusa.ui.book.manga.config
+
+object MangaScrollMode {
+    const val PAGE_LEFT_TO_RIGHT = 1      // 单页式(从左到右)
+    const val PAGE_RIGHT_TO_LEFT = 2      // 单页式(从右到左)
+    const val PAGE_TOP_TO_BOTTOM = 3      // 单页式(从上到下)
+    const val WEBTOON = 4                 // 条漫
+    const val WEBTOON_WITH_GAP = 5        // 条漫(页面有空隙)
+
+    val ALL = listOf(
+        PAGE_LEFT_TO_RIGHT,
+        PAGE_RIGHT_TO_LEFT,
+        PAGE_TOP_TO_BOTTOM,
+        WEBTOON,
+        WEBTOON_WITH_GAP
+    )
+
+    fun labelOf(mode: Int): String = when (mode) {
+        PAGE_LEFT_TO_RIGHT -> "单页式(从左到右)"
+        PAGE_RIGHT_TO_LEFT -> "单页式(从右到左)"
+        PAGE_TOP_TO_BOTTOM -> "单页式(从上到下)"
+        WEBTOON -> "条漫"
+        WEBTOON_WITH_GAP -> "条漫(页面有空隙)"
+        else -> "未知"
+    }
+}
+

+ 103 - 0
app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaScrollModeDialog.kt

@@ -0,0 +1,103 @@
+package io.legato.kazusa.ui.book.manga.config
+
+import android.os.Bundle
+import android.view.View
+import androidx.transition.TransitionManager
+import com.google.android.material.chip.Chip
+import io.legato.kazusa.R
+import io.legato.kazusa.base.BaseBottomSheetDialogFragment
+import io.legato.kazusa.databinding.DialogMangaScrollModeBinding
+import io.legato.kazusa.help.config.AppConfig
+import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
+
+class MangaScrollModeDialog : BaseBottomSheetDialogFragment(R.layout.dialog_manga_scroll_mode) {
+
+    private val binding by viewBinding(DialogMangaScrollModeBinding::bind)
+
+    var initialScrollMode: Int = AppConfig.mangaScrollMode
+    var initialAutoPageSpeed: Int = AppConfig.mangaAutoPageSpeed
+    var initialSidePadding: Int = AppConfig.webtoonSidePaddingDp
+    var initialAutoPageEnabled: Boolean = false
+    var callback: Callback? = null
+
+    override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
+        initView()
+    }
+
+    private fun initView() {
+        binding.chipGroupScrollMode.removeAllViews()
+
+        MangaScrollMode.ALL.forEach { mode ->
+            binding.chipGroupScrollMode.addView(Chip(requireContext()).apply {
+                text = MangaScrollMode.labelOf(mode)
+                isCheckable = true
+                isChecked = (mode == initialScrollMode)
+
+                setOnClickListener {
+                    AppConfig.mangaScrollMode = mode
+                    callback?.onScrollModeChanged(mode)
+                    binding.chipAutoPage.isChecked = false
+                }
+            })
+        }
+
+        binding.chipAutoPage.run {
+            isChecked = initialAutoPageEnabled
+            setOnCheckedChangeListener { _, isChecked ->
+                callback?.onAutoPageToggle(isChecked)
+                initAutoPageSpeed(isChecked)
+            }
+        }
+
+        binding.checkboxDisableClickScroll.apply {
+            isChecked = AppConfig.disableClickScroll
+            setOnCheckedChangeListener { _, isChecked ->
+                AppConfig.disableClickScroll = isChecked
+                callback?.onClickScrollDisabledChanged(isChecked)
+            }
+        }
+
+        binding.checkboxDisableMangaScale.apply {
+            isChecked = AppConfig.disableMangaScale
+            setOnCheckedChangeListener { _, isChecked ->
+                AppConfig.disableMangaScale = isChecked
+                callback?.onMangaScaleDisabledChanged(isChecked)
+            }
+        }
+
+        binding.scvPadding.apply {
+            valueFormat = { "$it %" }
+            progress = initialSidePadding
+            onChanged = { newValue ->
+                callback?.upSidePadding(newValue)
+                initialSidePadding = newValue
+            }
+        }
+
+        initAutoPageSpeed(initialAutoPageEnabled)
+    }
+
+    private fun initAutoPageSpeed(boolean: Boolean) {
+        TransitionManager.beginDelayedTransition(binding.rootView)
+        binding.scvAutoPageSpeed.run {
+            isEnabled = boolean
+            valueFormat = { "$it 秒" }
+            progress = initialAutoPageSpeed
+
+            onChanged = { newValue ->
+                callback?.onAutoPageSpeedChanged(newValue)
+                initialAutoPageSpeed = newValue
+            }
+        }
+    }
+
+    interface Callback {
+        fun onAutoPageToggle(enable: Boolean)
+        fun onAutoPageSpeedChanged(speed: Int)
+        fun onScrollModeChanged(mode: Int)
+        fun onClickScrollDisabledChanged(disabled: Boolean)
+        fun onMangaScaleDisabledChanged(disabled: Boolean)
+        fun upSidePadding(padding: Int)
+    }
+
+}

+ 11 - 9
app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/MangaAdapter.kt

@@ -30,7 +30,6 @@ import io.legato.kazusa.ui.book.manga.entities.EpaperTransformation
 import io.legato.kazusa.ui.book.manga.entities.GrayscaleTransformation
 import io.legato.kazusa.ui.book.manga.entities.MangaPage
 import io.legato.kazusa.ui.book.manga.entities.ReaderLoading
-import io.legato.kazusa.utils.dpToPx
 
 
 class MangaAdapter(private val context: Context) :
@@ -47,6 +46,8 @@ class MangaAdapter(private val context: Context) :
     }
 
     var isHorizontal = false
+    var enableDoublePageInLandscape = false
+
 
     private val mDiffCallback: DiffUtil.ItemCallback<Any> = object : DiffUtil.ItemCallback<Any>() {
         override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean {
@@ -131,19 +132,20 @@ class MangaAdapter(private val context: Context) :
     inner class PageMoreViewHolder(val binding: ItemBookMangaEdgeBinding) :
         RecyclerView.ViewHolder(binding.root) {
         fun onBind(item: ReaderLoading) {
-            val message = item.mMessage
-            binding.text.text = message
-            itemView.updateLayoutParams {
-                height = if (item.isVolume) {
-                    MATCH_PARENT
-                } else {
-                    96.dpToPx()
-                }
+            val message = item.mMessage ?: ""
+            val parts = message.split(" ", limit = 2)
+            if (parts.size == 2) {
+                binding.text.text = parts[0]
+                binding.textChapter.text = parts[1]
+            } else {
+                binding.text.text = message
+                binding.textChapter.text = ""
             }
         }
     }
 
 
+
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
         return when {
             viewType >= TYPE_FOOTER_VIEW -> {

+ 2 - 2
app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt

@@ -63,13 +63,13 @@ class ScrollTimer(
         mScrollPageJob = coroutineScope.launch {
             while (isActive) {
                 delay(distance.times(1000L))
-                callback.scrollPage()
+                callback.scrollPage(1)
             }
         }
     }
 
     interface ScrollCallback {
         fun scrollBy(distance: Int)
-        fun scrollPage()
+        fun scrollPage(direction: Int)
     }
 }

+ 2 - 1
app/src/main/java/io/legato/kazusa/ui/book/read/MangaMenu.kt

@@ -243,7 +243,7 @@ class MangaMenu @JvmOverloads constructor(
         }
 
         btnAutoPage.setOnClickListener {
-            callBack.showFooterConfig()
+            callBack.showScrollModeDialog()
         }
 
     }
@@ -263,6 +263,7 @@ class MangaMenu @JvmOverloads constructor(
         fun skipToPage(index: Int)
         fun openCatalog()
         fun showFooterConfig()
+        fun showScrollModeDialog()
     }
 
 }

+ 21 - 30
app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt

@@ -10,6 +10,7 @@ import android.view.MotionEvent
 import android.view.ViewGroup
 import androidx.activity.addCallback
 import androidx.activity.viewModels
+import androidx.core.view.get
 import androidx.core.view.postDelayed
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
@@ -17,6 +18,7 @@ import androidx.fragment.app.FragmentStatePagerAdapter
 import androidx.lifecycle.lifecycleScope
 import androidx.viewpager.widget.ViewPager
 import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.google.android.material.navigation.NavigationBarView
 import io.legato.kazusa.BuildConfig
 import io.legato.kazusa.R
 import io.legato.kazusa.base.VMBaseActivity
@@ -37,10 +39,12 @@ import io.legato.kazusa.ui.about.CrashLogsDialog
 import io.legato.kazusa.ui.main.bookshelf.BaseBookshelfFragment
 import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment1
 import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment2
+import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment3
 import io.legato.kazusa.ui.main.explore.ExploreFragment
 import io.legato.kazusa.ui.main.my.MyFragment
 import io.legato.kazusa.ui.main.rss.RssFragment
 import io.legato.kazusa.ui.widget.dialog.TextDialog
+import io.legato.kazusa.utils.gone
 import io.legato.kazusa.utils.hideSoftInput
 import io.legato.kazusa.utils.isCreated
 import io.legato.kazusa.utils.observeEvent
@@ -48,16 +52,12 @@ import io.legato.kazusa.utils.shouldHideSoftInput
 import io.legato.kazusa.utils.showDialogFragment
 import io.legato.kazusa.utils.toastOnUi
 import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
+import io.legato.kazusa.utils.visible
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
-import androidx.core.view.get
-import com.google.android.material.navigation.NavigationBarView
-import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment3
-import io.legato.kazusa.utils.gone
-import io.legato.kazusa.utils.visible
 
 /**
  * 主界面
@@ -90,7 +90,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
         getNavigationBarView().getOrCreateBadge(R.id.menu_bookshelf)
     }
 
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
@@ -382,32 +381,25 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
         )
     }
 
-
     private fun upBottomMenu() {
-        if (AppConfig.showBottomView)
-        {
-            getNavigationBarView().visible()
-            val showDiscovery = AppConfig.showDiscovery
-            val showRss = AppConfig.showRSS
-            val menu = getNavigationBarView().menu
-            menu.findItem(R.id.menu_discovery).isVisible = showDiscovery
-            menu.findItem(R.id.menu_rss).isVisible = showRss
-
-            var index = 0
-            if (showDiscovery) {
-                index++
-                realPositions[index] = idExplore
-            }
-            if (showRss) {
-                index++
-                realPositions[index] = idRss
-            }
+        val menu = getNavigationBarView().menu
+        menu.findItem(R.id.menu_discovery).isVisible = AppConfig.showDiscovery
+        menu.findItem(R.id.menu_rss).isVisible = AppConfig.showRSS
+        var index = 0
+        if (AppConfig.showDiscovery) {
+            index++
+            realPositions[index] = idExplore
+        }
+        if (AppConfig.showRSS) {
             index++
-            realPositions[index] = idMy
-            bottomMenuCount = index + 1
-            adapter.notifyDataSetChanged()
+            realPositions[index] = idRss
         }
-        else getNavigationBarView().gone()
+        index++
+        realPositions[index] = idMy
+        bottomMenuCount = index + 1
+        adapter.notifyDataSetChanged()
+        if (AppConfig.showBottomView) getNavigationBarView().visible()
+        else binding.bottomNavigationView?.gone()
     }
 
     private fun upHomePage() {
@@ -450,7 +442,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
 
     }
 
-
     private inner class TabFragmentPageAdapter(fm: FragmentManager) :
         FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
 

+ 6 - 11
app/src/main/java/io/legato/kazusa/ui/widget/DetailSeekBar.kt

@@ -44,6 +44,12 @@ class DetailSeekBar @JvmOverloads constructor(
             binding.slider.valueTo = value.toFloat()
         }
 
+    var min: Int
+        get() = binding.slider.valueFrom.toInt()
+        set(value) {
+            binding.slider.valueFrom = value.toFloat()
+        }
+
     init {
         val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DetailSeekBar)
         isBottomBackground =
@@ -57,17 +63,6 @@ class DetailSeekBar @JvmOverloads constructor(
 
         binding.slider.valueTo = typedArray.getInteger(R.styleable.DetailSeekBar_max, 0).toFloat()
         typedArray.recycle()
-        binding.ivSeekPlus.setOnClickListener {
-            val newValue = (binding.slider.value + 1).coerceAtMost(binding.slider.valueTo)
-            binding.slider.value = newValue
-            onChanged?.invoke(newValue.toInt())
-        }
-
-        binding.ivSeekReduce.setOnClickListener {
-            val newValue = (binding.slider.value - 1).coerceAtLeast(binding.slider.valueFrom)
-            binding.slider.value = newValue
-            onChanged?.invoke(newValue.toInt())
-        }
 
         binding.slider.addOnChangeListener { _, value, fromUser ->
             upValue(value.toInt())

+ 16 - 3
app/src/main/java/io/legato/kazusa/ui/widget/SimpleCounterView.kt

@@ -23,6 +23,7 @@ class SimpleCounterView @JvmOverloads constructor(
 
     private var _progress = 0
     private var _max = 100
+    private var _min = 0
     private val isBottomBackground: Boolean
 
     var valueFormat: ((Int) -> String)? = null
@@ -39,7 +40,7 @@ class SimpleCounterView @JvmOverloads constructor(
     var progress: Int
         get() = _progress
         set(value) {
-            _progress = value.coerceIn(0, _max)
+            _progress = value.coerceIn(_min, _max)
             updateValue()
         }
 
@@ -51,11 +52,22 @@ class SimpleCounterView @JvmOverloads constructor(
             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)
+
         typedArray.recycle()
 
         binding.tvSeekTitle.text = title
@@ -70,7 +82,7 @@ class SimpleCounterView @JvmOverloads constructor(
         }
 
         binding.ivSeekReduce.setOnClickListener {
-            if (_progress > 0) {
+            if (_progress > _min) {
                 _progress--
                 updateValue()
                 onChanged?.invoke(_progress)
@@ -119,6 +131,7 @@ class SimpleCounterView @JvmOverloads constructor(
             customView {
                 val detailSeekBar = DetailSeekBar(ctx).apply {
                     max = _max
+                    min = _min
                     progress = _progress
                     valueFormat = this@SimpleCounterView.valueFormat
                     setTitle(binding.tvSeekTitle.text)
@@ -168,7 +181,7 @@ class SimpleCounterView @JvmOverloads constructor(
 
     private val decrementRunnable = object : Runnable {
         override fun run() {
-            if (_progress > 0) {
+            if (_progress > _min) {
                 _progress--
                 updateValue()
                 onChanged?.invoke(_progress)

+ 11 - 0
app/src/main/res/drawable/ic_filter.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?attr/colorControlNormal"
+    android:viewportWidth="960"
+    android:viewportHeight="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M200,700Q226,700 243,683Q260,666 260,640Q260,614 243,597Q226,580 200,580Q174,580 157,597Q140,614 140,640Q140,666 157,683Q174,700 200,700ZM360,520Q377,520 388.5,508.5Q400,497 400,480Q400,463 388.5,451.5Q377,440 360,440Q343,440 331.5,451.5Q320,463 320,480Q320,497 331.5,508.5Q343,520 360,520ZM360,360Q377,360 388.5,348.5Q400,337 400,320Q400,303 388.5,291.5Q377,280 360,280Q343,280 331.5,291.5Q320,303 320,320Q320,337 331.5,348.5Q343,360 360,360ZM120,840L120,760L840,760L840,840L120,840ZM200,380Q226,380 243,363Q260,346 260,320Q260,294 243,277Q226,260 200,260Q174,260 157,277Q140,294 140,320Q140,346 157,363Q174,380 200,380ZM200,540Q226,540 243,523Q260,506 260,480Q260,454 243,437Q226,420 200,420Q174,420 157,437Q140,454 140,480Q140,506 157,523Q174,540 200,540ZM360,680Q377,680 388.5,668.5Q400,657 400,640Q400,623 388.5,611.5Q377,600 360,600Q343,600 331.5,611.5Q320,623 320,640Q320,657 331.5,668.5Q343,680 360,680ZM680,660Q689,660 694.5,654.5Q700,649 700,640Q700,631 694.5,625.5Q689,620 680,620Q671,620 665.5,625.5Q660,631 660,640Q660,649 665.5,654.5Q671,660 680,660ZM120,200L120,120L840,120L840,200L120,200ZM680,340Q689,340 694.5,334.5Q700,329 700,320Q700,311 694.5,305.5Q689,300 680,300Q671,300 665.5,305.5Q660,311 660,320Q660,329 665.5,334.5Q671,340 680,340ZM680,500Q689,500 694.5,494.5Q700,489 700,480Q700,471 694.5,465.5Q689,460 680,460Q671,460 665.5,465.5Q660,471 660,480Q660,489 665.5,494.5Q671,500 680,500ZM520,360Q537,360 548.5,348.5Q560,337 560,320Q560,303 548.5,291.5Q537,280 520,280Q503,280 491.5,291.5Q480,303 480,320Q480,337 491.5,348.5Q503,360 520,360ZM520,520Q537,520 548.5,508.5Q560,497 560,480Q560,463 548.5,451.5Q537,440 520,440Q503,440 491.5,451.5Q480,463 480,480Q480,497 491.5,508.5Q503,520 520,520ZM520,680Q537,680 548.5,668.5Q560,657 560,640Q560,623 548.5,611.5Q537,600 520,600Q503,600 491.5,611.5Q480,623 480,640Q480,657 491.5,668.5Q503,680 520,680ZM120,760L120,760L120,200L120,200L120,760Z" />
+</vector>

+ 8 - 7
app/src/main/res/layout/activity_manga.xml

@@ -8,7 +8,8 @@
     <io.legato.kazusa.ui.book.manga.recyclerview.WebtoonFrame
         android:id="@+id/webtoon_frame"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:background="@color/black">
 
         <io.legato.kazusa.ui.book.manga.recyclerview.WebtoonRecyclerView
             android:id="@+id/recycler_view"
@@ -48,20 +49,19 @@
             android:gravity="center"
             android:orientation="vertical">
 
-            <ProgressBar
+            <com.google.android.material.progressindicator.CircularProgressIndicator
                 style="@style/Widget.Material3.CircularProgressIndicator.Small"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:indeterminate="true"
-                app:indicatorSize="36dp"
-                app:trackCornerRadius="99dp"
-                app:trackThickness="3dp" />
+                app:indicatorSize="40dp" />
 
             <TextView
                 android:id="@+id/tv_loading_message"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_marginTop="10dp"
+                android:layout_marginTop="8dp"
+                android:textColor="?attr/colorSurface"
                 android:text="@string/loading" />
         </LinearLayout>
 
@@ -78,10 +78,11 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content" />
 
-            <io.legato.kazusa.ui.widget.text.AccentTextView
+            <com.google.android.material.button.MaterialButton
                 android:id="@+id/tv_retry"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                style="@style/Widget.Material3.Button.TonalButton"
                 android:layout_margin="16dp"
                 android:text="重新加载"
                 android:textSize="18sp"

+ 3 - 28
app/src/main/res/layout/dialog_manga_footer_setting.xml

@@ -48,8 +48,8 @@
                 android:layout_height="wrap_content"
                 android:layout_marginEnd="8dp"
                 android:text="@string/footer"
+                android:textStyle="bold"
                 android:textSize="14sp" />
-
             <View
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
@@ -165,35 +165,10 @@
                 android:text="2.1%" />
         </com.google.android.material.chip.ChipGroup>
 
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-            android:orientation="horizontal">
-
-            <com.google.android.material.chip.Chip
-                android:id="@+id/chip_autoPage"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/enable_auto_page_scroll" />
-
-            <View
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1" />
-
-            <io.legato.kazusa.ui.widget.SimpleCounterView
-                android:id="@+id/scv_autoPageSpeed"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:max="100"
-                app:title="翻页速度" />
-
-        </LinearLayout>
-
         <com.google.android.material.button.MaterialButton
             android:id="@+id/btn_color_filter"
-            style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
+            style="@style/Widget.Material3.Button.TonalButton"
+            app:icon="@drawable/ic_filter"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/manga_color_filter" />

+ 137 - 0
app/src/main/res/layout/dialog_manga_scroll_mode.xml

@@ -0,0 +1,137 @@
+<?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:id="@+id/rootView"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+
+    android:paddingVertical="8dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="8dp">
+
+        <View
+            android:layout_width="36dp"
+            android:layout_height="4dp"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginBottom="16dp"
+            android:background="@drawable/bg_bottom_sheet_handle" />
+
+        <TextView
+            android:id="@+id/bottom_sheet_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="漫画设置"
+            android:textSize="18sp"
+            android:textStyle="bold" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingHorizontal="16dp">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingVertical="8dp"
+            android:text="阅读模式"
+            android:textStyle="bold" />
+
+        <com.google.android.material.chip.ChipGroup
+            android:id="@+id/chipGroupScrollMode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:singleLine="false"
+            app:chipSpacingVertical="0dp"
+            app:selectionRequired="true"
+            app:singleSelection="true" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingVertical="8dp"
+            android:text="自动阅读"
+            android:textStyle="bold" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+
+            <com.google.android.material.chip.Chip
+                android:id="@+id/chip_autoPage"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/enable_auto_page_scroll" />
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1" />
+
+            <io.legato.kazusa.ui.widget.SimpleCounterView
+                android:id="@+id/scv_autoPageSpeed"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                app:max="100"
+                app:min="1"
+                app:title="翻页速度" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/ll_webtoon"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingHorizontal="16dp"
+            android:paddingVertical="8dp"
+            android:text="条漫"
+            android:textStyle="bold" />
+
+        <io.legato.kazusa.ui.widget.DetailSeekBar
+            android:id="@+id/scv_Padding"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:max="30"
+            app:title="侧边留白" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingHorizontal="12dp">
+
+        <com.google.android.material.checkbox.MaterialCheckBox
+            android:id="@+id/checkboxDisableClickScroll"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/disable_manga_click_scroll" />
+
+        <com.google.android.material.checkbox.MaterialCheckBox
+            android:id="@+id/checkboxDisableMangaScale"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/disable_manga_scale" />
+    </LinearLayout>
+
+
+</LinearLayout>

+ 30 - 8
app/src/main/res/layout/item_book_manga_edge.xml

@@ -1,16 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
-    android:layout_height="96dp"
+    android:layout_height="wrap_content"
     android:background="@color/book_ant_10">
 
-    <TextView
-        android:id="@+id/text"
+    <LinearLayout
+        android:id="@+id/ll_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:textColor="@android:color/white"
-        android:textStyle="bold"
-        tools:text="上一章节:第一话" />
+        android:layout_gravity="center_vertical"
+        android:orientation="vertical"
+        android:padding="32dp">
+
+        <TextView
+            android:id="@+id/text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="start"
+            android:autoSizeTextType="uniform"
+            android:text="已读完"
+            android:textColor="?attr/colorSurface"
+            android:textStyle="bold" />
+
+        <TextView
+            android:id="@+id/textChapter"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:autoSizeTextType="uniform"
+            android:text="下一章123"
+            android:textColor="?attr/colorSurface"
+            android:textSize="22sp"
+            android:textStyle="bold" />
+
+    </LinearLayout>
+
+
 </FrameLayout>

+ 14 - 14
app/src/main/res/layout/item_book_manga_page.xml

@@ -21,33 +21,32 @@
         android:layout_height="match_parent"
         android:background="@color/book_ant_10">
 
-        <ProgressBar
+        <com.google.android.material.progressindicator.CircularProgressIndicator
             android:id="@+id/loading"
-            style="@style/Widget.Material3.CircularProgressIndicator.Small"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            style="@style/Widget.Material3.CircularProgressIndicator"
             android:layout_gravity="center"
             android:indeterminate="true"
-            android:indeterminateTint="@color/white"
-            android:progressTint="@color/white"
-            app:indicatorColor="@color/white"
-            app:indicatorSize="36dp"
-            app:trackCornerRadius="99dp"
-            app:trackThickness="3dp" />
+            app:indicatorSize="64dp" />
 
 
-        <Button
+        <com.google.android.material.button.MaterialButton
             android:id="@+id/retry"
-            style="@style/Widget.Material3.Button.TonalButton"
+            style="@style/Widget.Material3.Button.OutlinedButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
+            android:padding="8dp"
             android:text="重新加载"
-            android:textColor="@color/white"
             android:textSize="18sp"
+            android:textColor="?attr/colorSurfaceVariant"
+            app:backgroundTint="?attr/colorOnSurface"
+            app:cornerRadius="12dp"
+            app:icon="@drawable/ic_refresh"
+            app:iconSize="24sp"
+            app:iconTint="?attr/colorSurfaceVariant"
             android:visibility="gone"
-            app:backgroundTint="@color/white"
-            app:cornerRadius="10dp"
             tools:visibility="visible" />
 
         <TextView
@@ -56,9 +55,10 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center"
             android:text="0%"
-            android:textColor="@color/white"
+            android:textColor="?attr/colorSurfaceVariant"
             android:visibility="gone"
             tools:visibility="visible" />
+
     </FrameLayout>
 
 </FrameLayout>

+ 7 - 34
app/src/main/res/layout/view_detail_seek_bar.xml

@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_marginVertical="4dp"
+    android:layout_marginVertical="8dp"
     android:orientation="vertical">
 
     <LinearLayout
@@ -12,6 +11,7 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:gravity="center_vertical"
+        android:paddingHorizontal="16dp"
         android:paddingTop="8dp"
         android:paddingBottom="4dp">
 
@@ -19,10 +19,9 @@
             android:id="@+id/tv_seek_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginStart="4dp"
             android:singleLine="true"
             android:text="seek"
-            tools:ignore="HardcodedText" />
+            android:textStyle="bold" />
 
         <View
             android:layout_width="0dp"
@@ -32,7 +31,6 @@
         <com.google.android.material.card.MaterialCardView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginEnd="4dp"
             app:strokeWidth="0dp"
             app:cardBackgroundColor="?attr/colorSurfaceVariant">
             <TextView
@@ -47,35 +45,10 @@
 
     </LinearLayout>
 
-    <LinearLayout
-        android:layout_width="wrap_content"
+    <com.google.android.material.slider.Slider
+        android:id="@+id/slider"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:gravity="center">
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/iv_seek_reduce"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
-            android:contentDescription="@string/reduce"
-            app:icon="@drawable/ic_reduce" />
-
-        <io.legato.kazusa.lib.theme.view.ThemeSlider
-            android:id="@+id/slider"
-            android:layout_width="0dp"
-            android:layout_height="25dp"
-            android:layout_gravity="center_vertical"
-            app:labelBehavior="gone"
-            android:layout_weight="4"
-            android:stepSize="1"/>
-
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/iv_seek_plus"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
-            android:contentDescription="@string/plus"
-            app:icon="@drawable/ic_add" />
-    </LinearLayout>
+        android:stepSize="1" />
 
 </LinearLayout>

+ 0 - 27
app/src/main/res/menu/book_manga.xml

@@ -24,33 +24,6 @@
         android:title="@string/pre_download"
         app:showAsAction="never" />
 
-    <item
-        android:id="@+id/menu_disable_manga_scale"
-        android:checkable="true"
-        android:checked="false"
-        android:title="@string/disable_manga_scale"
-        app:showAsAction="never" />
-
-    <item
-        android:id="@+id/menu_disable_click_scroll"
-        android:checkable="true"
-        android:checked="false"
-        android:title="@string/disable_manga_click_scroll"
-        app:showAsAction="never" />
-
-    <item
-        android:id="@+id/menu_enable_auto_scroll"
-        android:checkable="true"
-        android:checked="false"
-        android:title="@string/enable_auto_scroll"
-        app:showAsAction="never" />
-
-    <item
-        android:id="@+id/menu_enable_horizontal_scroll"
-        android:checkable="true"
-        android:checked="false"
-        android:title="@string/enable_manga_horizontal_scroll"
-        app:showAsAction="never" />
 
     <item
         android:id="@+id/menu_disable_horizontal_animation"

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

@@ -1194,7 +1194,7 @@
     <string name="disable_manga_click_scroll">禁用点击翻页</string>
     <string name="enable_auto_page_scroll">开启自动翻页</string>
     <string name="manga_auto_page_speed">翻页速度 %s</string>
-    <string name="enable_auto_scroll">开启滚动</string>
+    <string name="enable_auto_scroll">开启自动滚动</string>
     <string name="manga_footer_config">页脚配置</string>
     <string name="setting_manga_auto_page_speed">设置自动翻页速度</string>
     <string name="book_reader_info_bar">页数. %1$d/%2$d 章节. %3$d/%4$d -> %5$s%%</string>

+ 1 - 0
app/src/main/res/values/attrs.xml

@@ -80,6 +80,7 @@
     <declare-styleable name="DetailSeekBar">
         <attr name="title" />
         <attr name="max" />
+        <attr name="min" />
         <attr name="isBottomBackground" />
     </declare-styleable>