From 82a2aa349ee9a2e3c149a9d31cbfc7118553e536 Mon Sep 17 00:00:00 2001 From: HapeLee <1321903405@qq.com> Date: Tue, 22 Jul 2025 02:24:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=98=85=E8=AF=BB=E6=BC=AB?= =?UTF-8?q?=E7=94=BB=E8=87=AA=E5=AE=9A=E4=B9=89=E7=82=B9=E5=87=BB=E5=8C=BA?= =?UTF-8?q?=E5=9F=9F=E5=8A=9F=E8=83=BD=20=E5=A2=9E=E5=8A=A0=E9=A1=B5?= =?UTF-8?q?=E8=84=9A=E9=85=8D=E7=BD=AE=E9=A2=84=E8=A7=88=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legato/kazusa/constant/PreferKey.kt | 11 ++ .../io/legato/kazusa/help/config/AppConfig.kt | 50 ++++++ .../kazusa/ui/book/manga/ReadMangaActivity.kt | 33 +++- .../config/MangaClickActionConfigDialog.kt | 145 ++++++++++++++++++ .../manga/config/MangaFooterSettingDialog.kt | 8 +- .../ui/book/manga/recyclerview/ScrollTimer.kt | 1 + .../book/manga/recyclerview/WebtoonFrame.kt | 85 ++++++---- .../io/legato/kazusa/ui/dict/DictDialog.kt | 20 +-- app/src/main/res/layout/dialog_dict.xml | 63 +++++--- .../layout/dialog_manga_footer_setting.xml | 8 + .../res/layout/dialog_manga_scroll_mode.xml | 3 +- app/src/main/res/layout/popup_action.xml | 3 +- app/src/main/res/layout/popup_action_menu.xml | 2 +- 13 files changed, 361 insertions(+), 71 deletions(-) create mode 100644 app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaClickActionConfigDialog.kt diff --git a/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt b/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt index b27dc3ab6..93657544f 100644 --- a/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt +++ b/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt @@ -192,4 +192,15 @@ object PreferKey { const val showBottomView = "showBottomView" const val mangaScrollMode = "mangaScrollMode" const val webtoonSidePaddingDp = "webtoonSidePaddingDp" + + const val mangaClickActionTL = "mangaClickActionTopLeft" + const val mangaClickActionTC = "mangaClickActionTopCenter" + const val mangaClickActionTR = "mangaClickActionTopRight" + const val mangaClickActionML = "mangaClickActionMiddleLeft" + const val mangaClickActionMC = "mangaClickActionMiddleCenter" + const val mangaClickActionMR = "mangaClickActionMiddleRight" + const val mangaClickActionBL = "mangaClickActionBottomLeft" + const val mangaClickActionBC = "mangaClickActionBottomCenter" + const val mangaClickActionBR = "mangaClickActionBottomRight" + } diff --git a/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt b/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt index 1c07c58ce..9b7fdba06 100644 --- a/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt +++ b/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt @@ -36,6 +36,18 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { var clickActionBL = appCtx.getPrefInt(PreferKey.clickActionBL, 2) var clickActionBC = appCtx.getPrefInt(PreferKey.clickActionBC, 1) var clickActionBR = appCtx.getPrefInt(PreferKey.clickActionBR, 1) + + // -1无操作 1下一页 2上一页 0显示菜单 + var mangaClickActionTL = appCtx.getPrefInt(PreferKey.mangaClickActionTL, -1) + var mangaClickActionTC = appCtx.getPrefInt(PreferKey.mangaClickActionTC, -1) + var mangaClickActionTR = appCtx.getPrefInt(PreferKey.mangaClickActionTR, 1) + var mangaClickActionML = appCtx.getPrefInt(PreferKey.mangaClickActionML, 2) + var mangaClickActionMC = appCtx.getPrefInt(PreferKey.mangaClickActionMC, 0) + var mangaClickActionMR = appCtx.getPrefInt(PreferKey.mangaClickActionMR, 1) + var mangaClickActionBL = appCtx.getPrefInt(PreferKey.mangaClickActionBL, 2) + var mangaClickActionBC = appCtx.getPrefInt(PreferKey.mangaClickActionBC, 1) + var mangaClickActionBR = appCtx.getPrefInt(PreferKey.mangaClickActionBR, 1) + var themeMode = appCtx.getPrefString(PreferKey.themeMode, "0") var useDefaultCover = appCtx.getPrefBoolean(PreferKey.useDefaultCover, false) var optimizeRender = CanvasRecorderFactory.isSupport @@ -76,6 +88,33 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { PreferKey.clickActionBR -> clickActionBR = appCtx.getPrefInt(PreferKey.clickActionBR, 1) + PreferKey.mangaClickActionTL -> mangaClickActionTL = + appCtx.getPrefInt(PreferKey.mangaClickActionTL, -1) + + PreferKey.mangaClickActionTC -> mangaClickActionTC = + appCtx.getPrefInt(PreferKey.mangaClickActionTC, -1) + + PreferKey.mangaClickActionTR -> mangaClickActionTR = + appCtx.getPrefInt(PreferKey.mangaClickActionTR, 1) + + PreferKey.mangaClickActionML -> mangaClickActionML = + appCtx.getPrefInt(PreferKey.mangaClickActionML, 2) + + PreferKey.mangaClickActionMC -> mangaClickActionMC = + appCtx.getPrefInt(PreferKey.mangaClickActionMC, 0) + + PreferKey.mangaClickActionMR -> mangaClickActionMR = + appCtx.getPrefInt(PreferKey.mangaClickActionMR, 1) + + PreferKey.mangaClickActionBL -> mangaClickActionBL = + appCtx.getPrefInt(PreferKey.mangaClickActionBL, 2) + + PreferKey.mangaClickActionBC -> mangaClickActionBC = + appCtx.getPrefInt(PreferKey.mangaClickActionBC, 1) + + PreferKey.mangaClickActionBR -> mangaClickActionBR = + appCtx.getPrefInt(PreferKey.mangaClickActionBR, 1) + PreferKey.readBodyToLh -> ReadBookConfig.readBodyToLh = appCtx.getPrefBoolean(PreferKey.readBodyToLh, true) @@ -619,6 +658,17 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { } } + fun detectMangaClickArea() { + if (mangaClickActionTL * mangaClickActionTC * mangaClickActionTR + * mangaClickActionML * mangaClickActionMC * mangaClickActionMR + * mangaClickActionBL * mangaClickActionBC * mangaClickActionBR != 0 + ) { + appCtx.putPrefInt(PreferKey.mangaClickActionMC, 0) + appCtx.toastOnUi("当前没有配置菜单区域,自动恢复中间区域为菜单.") + } + } + + //跳转到漫画界面不使用富文本模式 val showMangaUi: Boolean get() = appCtx.getPrefBoolean(PreferKey.showMangaUi, true) diff --git a/app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt b/app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt index 90438ee06..e46456d7d 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/manga/ReadMangaActivity.kt @@ -42,6 +42,7 @@ import io.legato.kazusa.model.ReadManga import io.legato.kazusa.receiver.NetworkChangedListener import io.legato.kazusa.ui.book.changesource.ChangeBookSourceDialog import io.legato.kazusa.ui.book.info.BookInfoActivity +import io.legato.kazusa.ui.book.manga.config.MangaClickActionConfigDialog 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 @@ -53,6 +54,7 @@ import io.legato.kazusa.ui.book.manga.entities.MangaPage import io.legato.kazusa.ui.book.manga.recyclerview.MangaAdapter import io.legato.kazusa.ui.book.manga.recyclerview.MangaLayoutManager import io.legato.kazusa.ui.book.manga.recyclerview.ScrollTimer +import io.legato.kazusa.ui.book.manga.recyclerview.WebtoonFrame import io.legato.kazusa.ui.book.read.MangaMenu import io.legato.kazusa.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED import io.legato.kazusa.ui.book.toc.TocActivityResult @@ -121,6 +123,7 @@ class ReadMangaActivity : VMBaseActivity + putPrefInt(PreferKey.mangaClickActionTL, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvTopCenter.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionTC, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvTopRight.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionTR, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvMiddleLeft.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionML, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvMiddleCenter.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionMC, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvMiddleRight.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionMR, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvBottomLeft.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionBL, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvBottomCenter.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionBC, action) + (it as? TextView)?.text = actions[action] + } + } + + binding.tvBottomRight.setOnClickListener { + selectAction { action -> + putPrefInt(PreferKey.mangaClickActionBR, action) + (it as? TextView)?.text = actions[action] + } + } + } + + private fun selectAction(success: (action: Int) -> Unit) { + context?.selector( + getString(R.string.select_action), + actions.values.toList() + ) { _, index -> + success.invoke(actions.keys.toList()[index]) + } + } + + override fun onDestroy() { + super.onDestroy() + AppConfig.detectMangaClickArea() + } +} + diff --git a/app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt b/app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt index fcc51d698..f284aea85 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/manga/config/MangaFooterSettingDialog.kt @@ -23,8 +23,6 @@ class MangaFooterSettingDialog : var callback: Callback? = null - var initialAutoPageEnabled: Boolean = false - private val binding by viewBinding(DialogMangaFooterSettingBinding::bind) override fun onStart() { @@ -134,6 +132,11 @@ class MangaFooterSettingDialog : dismiss() } + binding.btnClickSet.setOnClickListener { + callback?.showClickConfig() + dismiss() + } + updateChapterText() } @@ -183,6 +186,7 @@ class MangaFooterSettingDialog : fun onAutoPageToggle(enable: Boolean) fun onAutoPageSpeedChanged(speed: Int) fun showColorFilterConfig() + fun showClickConfig() } } \ No newline at end of file diff --git a/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt b/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt index 03ad76af8..d960841df 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/ScrollTimer.kt @@ -15,6 +15,7 @@ class ScrollTimer( ) : RecyclerView.OnScrollListener() { private var distance = 1 private var mScrollPageJob: Job? = null + var isEnabled: Boolean = false set(value) { if (field != value) { diff --git a/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/WebtoonFrame.kt b/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/WebtoonFrame.kt index a68fb43a0..67e550c92 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/WebtoonFrame.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/manga/recyclerview/WebtoonFrame.kt @@ -8,6 +8,7 @@ import android.view.GestureDetector import android.view.MotionEvent import android.view.ScaleGestureDetector import android.widget.FrameLayout +import io.legato.kazusa.help.config.AppConfig class WebtoonFrame : FrameLayout { @@ -21,6 +22,7 @@ class WebtoonFrame : FrameLayout { private val scaleDetector = ScaleGestureDetector(context, ScaleListener()) private val flingDetector = GestureDetector(context, FlingListener()) + private val regionRects = mutableMapOf() var doubleTapZoom = true set(value) { @@ -34,45 +36,55 @@ class WebtoonFrame : FrameLayout { private val recycler: WebtoonRecyclerView? get() = getChildAt(0) as? WebtoonRecyclerView - private val mcRect = RectF() - private val blRect = RectF() - private val brRect = RectF() - - private var mTouchMiddle: (() -> Unit)? = null - fun onTouchMiddle(init: () -> Unit) = apply { this.mTouchMiddle = init } - private var mNextPage: (() -> Unit)? = null - fun onNextPage(init: () -> Unit) = apply { this.mNextPage = init } - private var mPrevPage: (() -> Unit)? = null - fun onPrevPage(init: () -> Unit) = apply { this.mPrevPage = init } - var disabledClickScroll = false + var actionHandler: ClickActionHandler? = null + override fun onAttachedToWindow() { super.onAttachedToWindow() - recycler?.tapListener = { ev -> - when { - mcRect.contains(ev.rawX, ev.rawY) -> { - mTouchMiddle?.invoke() - } + recycler?.tapListener = tapListener@{ ev -> + val x = ev.rawX + val y = ev.rawY + val key = + regionRects.entries.find { it.value.contains(x, y) }?.key ?: return@tapListener - blRect.contains(ev.rawX, ev.rawY) && !disabledClickScroll -> { - mPrevPage?.invoke() - } - - brRect.contains(ev.rawX, ev.rawY) && !disabledClickScroll -> { - mNextPage?.invoke() - } + val action = when (key) { + "TL" -> AppConfig.mangaClickActionTL + "TC" -> AppConfig.mangaClickActionTC + "TR" -> AppConfig.mangaClickActionTR + "ML" -> AppConfig.mangaClickActionML + "MC" -> AppConfig.mangaClickActionMC + "MR" -> AppConfig.mangaClickActionMR + "BL" -> AppConfig.mangaClickActionBL + "BC" -> AppConfig.mangaClickActionBC + "BR" -> AppConfig.mangaClickActionBR + else -> -1 } + + performClickAction(action) } + } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) - mcRect.set(width * 0.33f, height * 0.33f, width * 0.66f, height * 0.66f) - blRect.set(0f, height * 0.66f, width * 0.33f, height.toFloat()) - brRect.set(width * 0.66f, height * 0.66f, width.toFloat(), height.toFloat()) + val cellWidth = w / 3f + val cellHeight = h / 3f + val keys = listOf("TL", "TC", "TR", "ML", "MC", "MR", "BL", "BC", "BR") + + keys.forEachIndexed { index, key -> + val row = index / 3 + val col = index % 3 + regionRects[key] = RectF( + col * cellWidth, + row * cellHeight, + (col + 1) * cellWidth, + (row + 1) * cellHeight + ) + } } + override fun dispatchTouchEvent(ev: MotionEvent): Boolean { if (!disableMangaScale) { scaleDetector.onTouchEvent(ev) @@ -93,6 +105,18 @@ class WebtoonFrame : FrameLayout { return super.dispatchTouchEvent(ev) } + private fun performClickAction(action: Int) { + when (action) { + -1 -> return + 0 -> actionHandler?.showMenu() + 1 -> actionHandler?.nextPage() + 2 -> actionHandler?.prevPage() + 3 -> actionHandler?.nextChapter() + 4 -> actionHandler?.prevChapter() + else -> {} + } + } + inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() { override fun onScaleBegin(detector: ScaleGestureDetector): Boolean { recycler?.onScaleBegin() @@ -123,4 +147,13 @@ class WebtoonFrame : FrameLayout { return recycler?.zoomFling(velocityX.toInt(), velocityY.toInt()) ?: false } } + + interface ClickActionHandler { + fun showMenu() + fun nextPage() + fun prevPage() + fun nextChapter() + fun prevChapter() + } + } diff --git a/app/src/main/java/io/legato/kazusa/ui/dict/DictDialog.kt b/app/src/main/java/io/legato/kazusa/ui/dict/DictDialog.kt index 8f6597d02..95f895897 100644 --- a/app/src/main/java/io/legato/kazusa/ui/dict/DictDialog.kt +++ b/app/src/main/java/io/legato/kazusa/ui/dict/DictDialog.kt @@ -3,24 +3,22 @@ package io.legato.kazusa.ui.dict import android.os.Bundle import android.text.method.LinkMovementMethod import android.view.View -import android.view.ViewGroup import androidx.fragment.app.viewModels import com.google.android.material.tabs.TabLayout import io.legato.kazusa.R -import io.legato.kazusa.base.BaseDialogFragment +import io.legato.kazusa.base.BaseBottomSheetDialogFragment import io.legato.kazusa.data.entities.DictRule import io.legato.kazusa.databinding.DialogDictBinding -//import io.legado.app.lib.theme.accentColor -//import io.legado.app.lib.theme.backgroundColor +import io.legato.kazusa.utils.invisible import io.legato.kazusa.utils.setHtml -import io.legato.kazusa.utils.setLayout import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.viewbindingdelegate.viewBinding +import io.legato.kazusa.utils.visible /** * 词典 */ -class DictDialog() : BaseDialogFragment(R.layout.dialog_dict) { +class DictDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_dict) { constructor(word: String) : this() { arguments = Bundle().apply { @@ -33,11 +31,6 @@ class DictDialog() : BaseDialogFragment(R.layout.dialog_dict) { private var word: String? = null - override fun onStart() { - super.onStart() - setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - } - override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { binding.tvDict.movementMethod = LinkMovementMethod() word = arguments?.getString("word") @@ -46,8 +39,7 @@ class DictDialog() : BaseDialogFragment(R.layout.dialog_dict) { dismiss() return } -// binding.tabLayout.setBackgroundColor(backgroundColor) -// binding.tabLayout.setSelectedTabIndicatorColor(accentColor) + binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab) { @@ -61,7 +53,7 @@ class DictDialog() : BaseDialogFragment(R.layout.dialog_dict) { val dictRule = tab.tag as DictRule binding.rotateLoading.visible() viewModel.dict(dictRule, word!!) { - binding.rotateLoading.inVisible() + binding.rotateLoading.invisible() binding.tvDict.setHtml(it) } } diff --git a/app/src/main/res/layout/dialog_dict.xml b/app/src/main/res/layout/dialog_dict.xml index 80aa8e924..04350daac 100644 --- a/app/src/main/res/layout/dialog_dict.xml +++ b/app/src/main/res/layout/dialog_dict.xml @@ -1,34 +1,59 @@ - + android:layout_height="wrap_content" + android:minHeight="320dp" + android:orientation="vertical" + android:paddingHorizontal="16dp" + android:paddingVertical="8dp"> + + + + + + + + + android:background="@android:color/transparent" /> - + android:layout_height="wrap_content"> - + + + + + android:indeterminate="true" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_manga_footer_setting.xml b/app/src/main/res/layout/dialog_manga_footer_setting.xml index f7d70b003..3d4c082ea 100644 --- a/app/src/main/res/layout/dialog_manga_footer_setting.xml +++ b/app/src/main/res/layout/dialog_manga_footer_setting.xml @@ -173,6 +173,14 @@ android:layout_height="wrap_content" android:text="@string/manga_color_filter" /> + + diff --git a/app/src/main/res/layout/dialog_manga_scroll_mode.xml b/app/src/main/res/layout/dialog_manga_scroll_mode.xml index 331e1ccb7..89ebff1c2 100644 --- a/app/src/main/res/layout/dialog_manga_scroll_mode.xml +++ b/app/src/main/res/layout/dialog_manga_scroll_mode.xml @@ -102,7 +102,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingHorizontal="16dp" - android:paddingVertical="8dp" + android:paddingTop="8dp" android:text="条漫" android:textStyle="bold" /> @@ -112,6 +112,7 @@ android:layout_height="wrap_content" app:max="30" app:title="侧边留白" /> + + android:orientation="vertical">