增加阅读底部按钮自定义功能
This commit is contained in:
@@ -80,6 +80,7 @@ import io.legato.kazusa.ui.book.read.config.ReadAloudDialog
|
||||
import io.legato.kazusa.ui.book.read.config.ReadStyleDialog
|
||||
import io.legato.kazusa.ui.book.read.config.TipConfigDialog.Companion.TIP_COLOR
|
||||
import io.legato.kazusa.ui.book.read.config.TipConfigDialog.Companion.TIP_DIVIDER_COLOR
|
||||
import io.legato.kazusa.ui.book.read.config.ToolButtonConfigDialog
|
||||
import io.legato.kazusa.ui.book.read.page.ContentTextView
|
||||
import io.legato.kazusa.ui.book.read.page.ReadView
|
||||
import io.legato.kazusa.ui.book.read.page.entities.PageDirection
|
||||
@@ -151,6 +152,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
ChangeChapterSourceDialog.CallBack,
|
||||
ReadBook.CallBack,
|
||||
AutoReadDialog.CallBack,
|
||||
ToolButtonConfigDialog.CallBack,
|
||||
TxtTocRuleDialog.CallBack,
|
||||
ColorPickerDialogListener,
|
||||
LayoutProgressListener {
|
||||
@@ -533,6 +535,11 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
ReadBook.loadContent(false)
|
||||
}
|
||||
|
||||
R.id.menu_tool_button -> {
|
||||
binding.readMenu.runMenuOut()
|
||||
showDialogFragment(ToolButtonConfigDialog())
|
||||
}
|
||||
|
||||
// R.id.menu_enable_review -> {
|
||||
// AppConfig.enableReview = !AppConfig.enableReview
|
||||
// item.isChecked = AppConfig.enableReview
|
||||
@@ -1485,6 +1492,10 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
binding.readView.autoPager.resume()
|
||||
}
|
||||
|
||||
override fun refresh() {
|
||||
recreate()
|
||||
}
|
||||
|
||||
override fun onLayoutPageCompleted(index: Int, page: TextPage) {
|
||||
upSeekBarThrottle.invoke()
|
||||
binding.readView.onLayoutPageCompleted(index, page)
|
||||
|
||||
@@ -2,6 +2,8 @@ package io.legato.kazusa.ui.book.read
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
@@ -13,6 +15,8 @@ import android.widget.SeekBar
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.button.MaterialButtonGroup
|
||||
import com.google.android.material.slider.Slider
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.PreferKey
|
||||
@@ -41,7 +45,6 @@ import io.legato.kazusa.utils.startActivity
|
||||
import io.legato.kazusa.utils.themeColor
|
||||
import io.legato.kazusa.utils.visible
|
||||
import splitties.views.onClick
|
||||
import splitties.views.onLongClick
|
||||
|
||||
/**
|
||||
* 阅读界面菜单
|
||||
@@ -189,6 +192,10 @@ class ReadMenu @JvmOverloads constructor(
|
||||
//// tvChapterName.setTextColor(textColor)
|
||||
//// tvChapterUrl.setTextColor(textColor)
|
||||
// }
|
||||
|
||||
val allButtons = getUserButtons()
|
||||
renderButtons(binding.bottomView, allButtons)
|
||||
|
||||
val brightnessBackground = GradientDrawable()
|
||||
brightnessBackground.cornerRadius = 5F.dpToPx()
|
||||
//brightnessBackground.setColor(ColorUtils.adjustAlpha(bgColor, 0.5f))
|
||||
@@ -231,7 +238,12 @@ class ReadMenu @JvmOverloads constructor(
|
||||
/**
|
||||
* 确保视图不被导航栏遮挡
|
||||
*/
|
||||
binding.bottomView.applyNavigationBarPadding()
|
||||
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
binding.bottomMenu.applyNavigationBarPadding()
|
||||
} else {
|
||||
binding.bottomView.applyNavigationBarPadding()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
@@ -459,20 +471,6 @@ class ReadMenu @JvmOverloads constructor(
|
||||
}
|
||||
})
|
||||
|
||||
//搜索
|
||||
fabSearch.setOnClickListener {
|
||||
runMenuOut {
|
||||
callBack.openSearchActivity(null)
|
||||
}
|
||||
}
|
||||
|
||||
//自动翻页
|
||||
fabAutoPage.setOnClickListener {
|
||||
runMenuOut {
|
||||
callBack.autoPage()
|
||||
}
|
||||
}
|
||||
|
||||
//替换
|
||||
//fabReplaceRule.setOnClickListener { callBack.openReplaceRule() }
|
||||
|
||||
@@ -488,32 +486,130 @@ class ReadMenu @JvmOverloads constructor(
|
||||
//下一章
|
||||
tvNext.setOnClickListener { ReadBook.moveToNextChapter(true) }
|
||||
|
||||
//目录
|
||||
ivCatalog.setOnClickListener {
|
||||
runMenuOut {
|
||||
callBack.openChapterList()
|
||||
|
||||
}
|
||||
|
||||
fun renderButtons(group: MaterialButtonGroup, buttons: List<ToolButton>) {
|
||||
group.removeAllViews()
|
||||
|
||||
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
buttons.forEach { btn ->
|
||||
val button = MaterialButton(
|
||||
group.context,
|
||||
null,
|
||||
com.google.android.material.R.attr.materialIconButtonFilledTonalStyle
|
||||
).apply {
|
||||
id = btn.id.hashCode()
|
||||
setIconResource(btn.iconRes)
|
||||
contentDescription = btn.description
|
||||
tooltipText = btn.description
|
||||
|
||||
setOnClickListener { btn.onClick() }
|
||||
btn.onLongClick?.let { longAction ->
|
||||
setOnLongClickListener {
|
||||
longAction()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
group.addView(button)
|
||||
}
|
||||
} else {
|
||||
buttons.forEach { btn ->
|
||||
val button = MaterialButton(
|
||||
group.context,
|
||||
null,
|
||||
com.google.android.material.R.attr.materialIconButtonOutlinedStyle
|
||||
).apply {
|
||||
id = btn.id.hashCode()
|
||||
setIconResource(btn.iconRes)
|
||||
contentDescription = btn.description
|
||||
tooltipText = btn.description
|
||||
strokeWidth = 0
|
||||
val primaryColor = context.themeColor(androidx.appcompat.R.attr.colorPrimary)
|
||||
iconTint = ColorStateList.valueOf(primaryColor)
|
||||
|
||||
setOnClickListener { btn.onClick() }
|
||||
btn.onLongClick?.let { longAction ->
|
||||
setOnLongClickListener {
|
||||
longAction()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
group.addView(button)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAllButtons(): List<ToolButton> {
|
||||
return listOf(
|
||||
ToolButton(
|
||||
id = "search",
|
||||
iconRes = R.drawable.ic_search,
|
||||
description = context.getString(R.string.search_content),
|
||||
onClick = { callBack.openSearchActivity(null) }
|
||||
),
|
||||
ToolButton(
|
||||
id = "auto_page",
|
||||
iconRes = R.drawable.ic_auto_page,
|
||||
description = context.getString(R.string.auto_next_page),
|
||||
onClick = { callBack.autoPage() }
|
||||
),
|
||||
ToolButton(
|
||||
id = "catalog",
|
||||
iconRes = R.drawable.ic_toc,
|
||||
description = context.getString(R.string.chapter_list),
|
||||
onClick = { callBack.openChapterList() }
|
||||
),
|
||||
ToolButton(
|
||||
id = "read_aloud",
|
||||
iconRes = R.drawable.ic_read_aloud,
|
||||
description = context.getString(R.string.read_aloud),
|
||||
onClick = { callBack.onClickReadAloud() },
|
||||
onLongClick = { callBack.showReadAloudDialog() }
|
||||
),
|
||||
ToolButton(
|
||||
id = "setting",
|
||||
iconRes = R.drawable.ic_settings,
|
||||
description = context.getString(R.string.setting),
|
||||
onClick = { callBack.showReadStyle() }
|
||||
),
|
||||
ToolButton(
|
||||
id = "addBookmark",
|
||||
iconRes = R.drawable.ic_bookmark,
|
||||
description = context.getString(R.string.bookmark),
|
||||
onClick = { callBack.addBookmark() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getUserButtons(): List<ToolButton> {
|
||||
val prefs by lazy {
|
||||
context.getSharedPreferences("tool_button_config", Context.MODE_PRIVATE)
|
||||
}
|
||||
val allButtons = getAllButtons().associateBy { it.id }
|
||||
|
||||
val str = prefs.getString("tool_buttons", null)
|
||||
val savedList = str?.split(";")?.mapNotNull {
|
||||
val parts = it.split(",")
|
||||
if (parts.size == 2) parts[0] to parts[1].toBoolean() else null
|
||||
} ?: emptyList()
|
||||
|
||||
val result = mutableListOf<ToolButton>()
|
||||
|
||||
savedList.forEach { (id, enabled) ->
|
||||
if (enabled) allButtons[id]?.let { result.add(it) }
|
||||
}
|
||||
|
||||
getAllButtons().forEach { btn ->
|
||||
if (savedList.none { it.first == btn.id }) {
|
||||
result.add(btn)
|
||||
}
|
||||
}
|
||||
|
||||
//朗读
|
||||
ivReadAloud.setOnClickListener {
|
||||
runMenuOut {
|
||||
callBack.onClickReadAloud()
|
||||
}
|
||||
}
|
||||
|
||||
ivReadAloud.onLongClick {
|
||||
runMenuOut {
|
||||
callBack.showReadAloudDialog()
|
||||
}
|
||||
}
|
||||
|
||||
//设置
|
||||
ivSetting.setOnClickListener {
|
||||
runMenuOut {
|
||||
callBack.showReadStyle()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun initAnimation() {
|
||||
@@ -522,8 +618,16 @@ class ReadMenu @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun upBookView() {
|
||||
binding.titleBar.title = " "
|
||||
binding.tvBookName.text = ReadBook.book?.name
|
||||
val bookName = ReadBook.book?.name ?: ""
|
||||
|
||||
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
binding.titleBar.title = bookName
|
||||
binding.tvBookName.gone()
|
||||
} else {
|
||||
binding.titleBar.title = " "
|
||||
binding.tvBookName.text = bookName
|
||||
}
|
||||
|
||||
ReadBook.curTextChapter?.let {
|
||||
binding.tvChapterName.text = it.title
|
||||
if (!ReadBook.isLocalBook) {
|
||||
@@ -598,16 +702,18 @@ class ReadMenu @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun setAutoPage(autoPage: Boolean) = binding.run {
|
||||
if (autoPage) {
|
||||
fabAutoPage.setIconResource(R.drawable.ic_auto_page_stop)
|
||||
fabAutoPage.contentDescription = context.getString(R.string.auto_next_page_stop)
|
||||
} else {
|
||||
fabAutoPage.setIconResource(R.drawable.ic_auto_page)
|
||||
fabAutoPage.contentDescription = context.getString(R.string.auto_next_page)
|
||||
fabAutoPage?.let { fab ->
|
||||
if (autoPage) {
|
||||
fab.setIconResource(R.drawable.ic_auto_page_stop)
|
||||
fab.contentDescription = context.getString(R.string.auto_next_page_stop)
|
||||
} else {
|
||||
fab.setIconResource(R.drawable.ic_auto_page)
|
||||
fab.contentDescription = context.getString(R.string.auto_next_page)
|
||||
}
|
||||
}
|
||||
//fabAutoPage.setColorFilter(textColor)
|
||||
}
|
||||
|
||||
|
||||
private fun upBrightnessVwPos() {
|
||||
if (AppConfig.brightnessVwPos) {
|
||||
binding.root.modifyBegin()
|
||||
@@ -630,6 +736,7 @@ class ReadMenu @JvmOverloads constructor(
|
||||
fun openSourceEditActivity()
|
||||
fun openBookInfoActivity()
|
||||
fun showReadStyle()
|
||||
fun addBookmark()
|
||||
fun showReadAloudDialog()
|
||||
fun upSystemUiVisibility()
|
||||
fun onClickReadAloud()
|
||||
@@ -642,4 +749,11 @@ class ReadMenu @JvmOverloads constructor(
|
||||
fun onMenuHide()
|
||||
}
|
||||
|
||||
}
|
||||
data class ToolButton(
|
||||
val id: String, // 唯一标识
|
||||
val iconRes: Int, // 图标资源
|
||||
val description: String, // contentDescription / tooltipText
|
||||
val onClick: () -> Unit, // 点击事件
|
||||
val onLongClick: (() -> Unit)? = null // 可选长按
|
||||
)
|
||||
}
|
||||
@@ -24,20 +24,6 @@ class AutoReadDialog : BaseBottomSheetDialogFragment(R.layout.dialog_auto_read)
|
||||
private val binding by viewBinding(DialogAutoReadBinding::bind)
|
||||
private val callBack: CallBack? get() = activity as? CallBack
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
// dialog?.window?.run {
|
||||
// clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||
// setBackgroundDrawableResource(R.color.background)
|
||||
// decorView.setPadding(0, 0, 0, 0)
|
||||
// val attr = attributes
|
||||
// attr.dimAmount = 0.0f
|
||||
// attr.gravity = Gravity.BOTTOM
|
||||
// attributes = attr
|
||||
// setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
(activity as ReadBookActivity).bottomDialog--
|
||||
@@ -49,20 +35,6 @@ class AutoReadDialog : BaseBottomSheetDialogFragment(R.layout.dialog_auto_read)
|
||||
dismiss()
|
||||
return
|
||||
}
|
||||
//val bg = requireContext().bottomBackground
|
||||
//val isLight = ColorUtils.isColorLight(bg)
|
||||
//val textColor = requireContext().getPrimaryTextColor(isLight)
|
||||
//root.setBackgroundColor(bg)
|
||||
// tvReadSpeedTitle.setTextColor(textColor)
|
||||
// tvReadSpeed.setTextColor(textColor)
|
||||
// ivCatalog.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
// tvCatalog.setTextColor(textColor)
|
||||
// ivMainMenu.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
// tvMainMenu.setTextColor(textColor)
|
||||
// ivAutoPageStop.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
// tvAutoPageStop.setTextColor(textColor)
|
||||
// ivSetting.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
// tvSetting.setTextColor(textColor)
|
||||
initOnChange()
|
||||
initData()
|
||||
initEvent()
|
||||
|
||||
@@ -31,14 +31,6 @@ import io.legato.kazusa.utils.showDialogFragment
|
||||
class ReadAloudConfigDialog : BasePrefDialogFragment() {
|
||||
private val readAloudPreferTag = "readAloudPreferTag"
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
dialog?.window?.run {
|
||||
//setBackgroundDrawableResource(R.color.transparent)
|
||||
//setLayout(0.9f, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package io.legato.kazusa.ui.book.read.config
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.edit
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseBottomSheetDialogFragment
|
||||
import io.legato.kazusa.databinding.DialogToolButtonConfigBinding
|
||||
import io.legato.kazusa.databinding.ItemToolButtonBinding
|
||||
import io.legato.kazusa.ui.book.read.ReadBookActivity
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
|
||||
class ToolButtonConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_tool_button_config) {
|
||||
|
||||
private val binding by viewBinding(DialogToolButtonConfigBinding::bind)
|
||||
private val prefs by lazy {
|
||||
requireContext().getSharedPreferences(
|
||||
"tool_button_config",
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
}
|
||||
|
||||
private val callBack: CallBack? get() = activity as? CallBack
|
||||
|
||||
private lateinit var adapter: ToolButtonAdapter
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) = binding.run {
|
||||
val configList = loadButtonConfig().toMutableList()
|
||||
|
||||
adapter = ToolButtonAdapter(configList)
|
||||
recyclerView.adapter = adapter
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
|
||||
val touchHelper = ItemTouchHelper(TouchHelperCallback(adapter))
|
||||
touchHelper.attachToRecyclerView(recyclerView)
|
||||
|
||||
btnSave.setOnClickListener {
|
||||
saveButtonConfig(adapter.items)
|
||||
callBack?.refresh()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
(activity as ReadBookActivity).bottomDialog--
|
||||
}
|
||||
|
||||
data class ConfigEntry(val id: String, var enabled: Boolean)
|
||||
|
||||
inner class ToolButtonAdapter(val items: MutableList<ConfigEntry>) :
|
||||
RecyclerView.Adapter<ToolButtonAdapter.VH>() {
|
||||
|
||||
inner class VH(val binding: ItemToolButtonBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
|
||||
val binding = ItemToolButtonBinding.inflate(layoutInflater, parent, false)
|
||||
return VH(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: VH, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
val (iconRes, name) = getButtonInfo(item.id)
|
||||
holder.binding.tvName.text = name
|
||||
holder.binding.ivIcon.setIconResource(iconRes)
|
||||
holder.binding.ivIcon.isEnabled = item.enabled
|
||||
holder.binding.btnDisable.icon = ContextCompat.getDrawable(
|
||||
holder.itemView.context,
|
||||
if (item.enabled) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
|
||||
)
|
||||
|
||||
holder.binding.btnDisable.setOnClickListener {
|
||||
val pos = holder.bindingAdapterPosition
|
||||
if (pos == RecyclerView.NO_POSITION) return@setOnClickListener
|
||||
|
||||
item.enabled = !item.enabled
|
||||
|
||||
holder.binding.btnDisable.icon = ContextCompat.getDrawable(
|
||||
holder.itemView.context,
|
||||
if (item.enabled) R.drawable.ic_visibility_on else R.drawable.ic_visibility_off
|
||||
)
|
||||
|
||||
if (!item.enabled) {
|
||||
val removed = items.removeAt(pos)
|
||||
items.add(removed)
|
||||
notifyItemMoved(pos, items.size - 1)
|
||||
} else {
|
||||
notifyItemChanged(pos)
|
||||
}
|
||||
holder.binding.ivIcon.isEnabled = item.enabled
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
fun swap(from: Int, to: Int) {
|
||||
if (from == RecyclerView.NO_POSITION || to == RecyclerView.NO_POSITION) return
|
||||
val fromItem = items[from]
|
||||
val toItem = items[to]
|
||||
if (!fromItem.enabled || !toItem.enabled) return
|
||||
|
||||
items.add(to, items.removeAt(from))
|
||||
notifyItemMoved(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAllButtonIds(): List<String> {
|
||||
return listOf("search", "auto_page", "catalog", "read_aloud", "setting", "addBookmark")
|
||||
}
|
||||
|
||||
private fun getButtonInfo(id: String): Pair<Int, String> {
|
||||
return when (id) {
|
||||
"search" -> R.drawable.ic_search to getString(R.string.search_content)
|
||||
"auto_page" -> R.drawable.ic_auto_page to getString(R.string.auto_next_page)
|
||||
"catalog" -> R.drawable.ic_toc to getString(R.string.chapter_list)
|
||||
"read_aloud" -> R.drawable.ic_read_aloud to getString(R.string.read_aloud)
|
||||
"setting" -> R.drawable.ic_settings to getString(R.string.setting)
|
||||
"addBookmark" -> R.drawable.ic_bookmark to getString(R.string.bookmark)
|
||||
else -> R.drawable.ic_help to id
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadButtonConfig(): List<ConfigEntry> {
|
||||
val str = prefs.getString("tool_buttons", null)
|
||||
|
||||
return if (str.isNullOrBlank()) {
|
||||
getAllButtonIds().map { ConfigEntry(it, true) }
|
||||
} else {
|
||||
val saved = str.split(";").mapNotNull {
|
||||
val parts = it.split(",")
|
||||
if (parts.size == 2) ConfigEntry(parts[0], parts[1].toBoolean()) else null
|
||||
}.toMutableList()
|
||||
|
||||
val allIds = getAllButtonIds()
|
||||
for (id in allIds) {
|
||||
if (saved.none { it.id == id }) {
|
||||
saved.add(ConfigEntry(id, true))
|
||||
}
|
||||
}
|
||||
|
||||
saved
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveButtonConfig(list: List<ConfigEntry>) {
|
||||
val str = list.joinToString(";") { "${it.id},${it.enabled}" }
|
||||
prefs.edit { putString("tool_buttons", str) }
|
||||
}
|
||||
|
||||
class TouchHelperCallback(
|
||||
private val adapter: ToolButtonAdapter
|
||||
) : ItemTouchHelper.Callback() {
|
||||
|
||||
override fun getMovementFlags(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int {
|
||||
val pos = viewHolder.bindingAdapterPosition
|
||||
if (pos == RecyclerView.NO_POSITION) return 0
|
||||
|
||||
val item = adapter.items[pos]
|
||||
return if (!item.enabled) {
|
||||
0
|
||||
} else {
|
||||
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||
makeMovementFlags(dragFlags, 0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMove(
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
target: RecyclerView.ViewHolder
|
||||
): Boolean {
|
||||
val fromPos = viewHolder.bindingAdapterPosition
|
||||
val toPos = target.bindingAdapterPosition
|
||||
if (fromPos == RecyclerView.NO_POSITION || toPos == RecyclerView.NO_POSITION) return false
|
||||
|
||||
adapter.swap(fromPos, toPos)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||
override fun isLongPressDragEnabled() = true
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
fun refresh()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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="M160,600L160,520L800,520L800,600L160,600ZM160,440L160,360L800,360L800,440L160,440Z" />
|
||||
</vector>
|
||||
@@ -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="M480,640Q555,640 607.5,587.5Q660,535 660,460Q660,385 607.5,332.5Q555,280 480,280Q405,280 352.5,332.5Q300,385 300,460Q300,535 352.5,587.5Q405,640 480,640ZM480,568Q435,568 403.5,536.5Q372,505 372,460Q372,415 403.5,383.5Q435,352 480,352Q525,352 556.5,383.5Q588,415 588,460Q588,505 556.5,536.5Q525,568 480,568ZM480,760Q334,760 214,678.5Q94,597 40,460Q94,323 214,241.5Q334,160 480,160Q626,160 746,241.5Q866,323 920,460Q866,597 746,678.5Q626,760 480,760ZM480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460ZM480,680Q593,680 687.5,620.5Q782,561 832,460Q782,359 687.5,299.5Q593,240 480,240Q367,240 272.5,299.5Q178,359 128,460Q178,561 272.5,620.5Q367,680 480,680Z" />
|
||||
</vector>
|
||||
@@ -136,13 +136,13 @@
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_weight="2" />
|
||||
|
||||
<!--章节设置-->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_weight="2"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:gravity="center"
|
||||
@@ -174,8 +174,6 @@
|
||||
android:layout_gravity="center_vertical"/>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/tv_next"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
|
||||
@@ -189,15 +187,15 @@
|
||||
tools:ignore="TouchTargetSizeCheck"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.button.MaterialButtonGroup
|
||||
android:id="@+id/bottom_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end"
|
||||
android:layout_weight="2"
|
||||
android:importantForAccessibility="no"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@@ -256,7 +254,7 @@
|
||||
app:iconGravity="textStart"
|
||||
tools:ignore="NestedWeights" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.button.MaterialButtonGroup>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/header_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal" />
|
||||
|
||||
<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>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnSave"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/action_save"
|
||||
android:textColor="?attr/colorTertiary"
|
||||
app:backgroundTint="?attr/colorTertiaryContainer" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<!-- 图标 -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/ivIcon"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false" />
|
||||
|
||||
<!-- 按钮名称 -->
|
||||
<TextView
|
||||
android:id="@+id/tvName"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:text="按钮名称"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<!-- 禁用/隐藏按钮 -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnDisable"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:icon="@drawable/ic_visibility_on" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:src="@drawable/ic_drag_handle" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -180,7 +180,7 @@
|
||||
tools:ignore="TouchTargetSizeCheck"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.button.MaterialButtonGroup
|
||||
android:id="@+id/bottom_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -188,99 +188,11 @@
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:background="?attr/colorSurfaceContainer"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fabSearch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:iconTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/search_content"
|
||||
android:tooltipText="@string/search_content"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:iconGravity="textStart"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/iv_read_aloud"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:iconTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/read_aloud"
|
||||
android:maxHeight="24dp"
|
||||
app:icon="@drawable/ic_read_aloud"
|
||||
app:iconGravity="textStart"
|
||||
tools:ignore="NestedWeights" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/iv_catalog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:iconTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/chapter_list"
|
||||
android:tooltipText="@string/chapter_list"
|
||||
android:maxHeight="24dp"
|
||||
app:icon="@drawable/ic_toc"
|
||||
app:iconGravity="textStart"
|
||||
tools:ignore="NestedWeights" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fabAutoPage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:iconTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/auto_next_page"
|
||||
android:tooltipText="@string/auto_next_page"
|
||||
app:icon="@drawable/ic_auto_page"
|
||||
app:iconGravity="textStart"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:importantForAccessibility="no" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/iv_setting"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:iconTint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/setting"
|
||||
android:tooltipText="@string/setting"
|
||||
android:maxHeight="24dp"
|
||||
app:icon="@drawable/ic_settings"
|
||||
app:iconGravity="textStart"
|
||||
tools:ignore="NestedWeights" />
|
||||
|
||||
</LinearLayout>
|
||||
</com.google.android.material.button.MaterialButtonGroup>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
|
||||
</group>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_tool_button"
|
||||
android:title="配置底部按钮"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_add_bookmark"
|
||||
android:title="@string/bookmark_add"
|
||||
|
||||
Reference in New Issue
Block a user