新增漫画阅读模式[条漫、日漫等]

新增条漫侧边留白功能
更新滤镜功能,现在支持亮度跟随系统
其他界面更新
This commit is contained in:
HapeLee
2025-07-21 03:25:18 +08:00
parent c35177715c
commit 1701285d33
24 changed files with 585 additions and 277 deletions
@@ -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"
}
@@ -403,6 +403,8 @@ data class Book(
var startDate: LocalDate? = null,
var startChapter: Int? = null, // 用户设置的起始章节
var dailyChapters: Int = 3 // 用户设置的每日更新章节数
) : Parcelable
class Converters {
@@ -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)
}
}
@@ -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}"))
}
@@ -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 {
@@ -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)
@@ -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 -> "未知"
}
}
@@ -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)
}
}
@@ -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 -> {
@@ -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)
}
}
@@ -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()
}
}
@@ -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] = idMy
bottomMenuCount = index + 1
adapter.notifyDataSetChanged()
realPositions[index] = idExplore
}
else getNavigationBarView().gone()
if (AppConfig.showRSS) {
index++
realPositions[index] = idRss
}
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) {
@@ -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())
@@ -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)