新增漫画阅读模式[条漫、日漫等]
新增条漫侧边留白功能 更新滤镜功能,现在支持亮度跟随系统 其他界面更新
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 +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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
<declare-styleable name="DetailSeekBar">
|
||||
<attr name="title" />
|
||||
<attr name="max" />
|
||||
<attr name="min" />
|
||||
<attr name="isBottomBackground" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user