This commit is contained in:
kunfei
2023-02-20 09:31:02 +08:00
parent e3bad0469a
commit f8ea278110
4 changed files with 346 additions and 3 deletions

View File

@@ -5,6 +5,8 @@ import androidx.room.Delete
import androidx.room.Query
import androidx.room.Upsert
import io.legado.app.data.entities.DictRule
import kotlinx.coroutines.flow.Flow
@Dao
interface DictRuleDao {
@@ -15,6 +17,9 @@ interface DictRuleDao {
@get:Query("select * from dictRules where enabled = 1")
val enabled: List<DictRule>
@Query("select * from dictRules where enabled = 1")
fun flowAll(): Flow<List<DictRule>>
@Upsert
fun upsert(vararg dictRule: DictRule)

View File

@@ -1,17 +1,112 @@
package io.legado.app.ui.dict.rule
import android.os.Bundle
import android.view.MenuItem
import androidx.activity.viewModels
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.data.appDb
import io.legado.app.data.entities.DictRule
import io.legado.app.databinding.ActivityDictRuleBinding
import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.widget.SelectActionBar
import io.legado.app.ui.widget.recycler.DragSelectTouchHelper
import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.setEdgeEffectColor
import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.launch
class DictRuleActivity : VMBaseActivity<ActivityDictRuleBinding, DictRuleViewModel>() {
class DictRuleActivity : VMBaseActivity<ActivityDictRuleBinding, DictRuleViewModel>(),
PopupMenu.OnMenuItemClickListener,
SelectActionBar.CallBack,
DictRuleAdapter.CallBack {
override val viewModel by viewModels<DictRuleViewModel>()
override val binding by viewBinding(ActivityDictRuleBinding::inflate)
override fun onActivityCreated(savedInstanceState: Bundle?) {
private val adapter by lazy { DictRuleAdapter(this, this) }
override fun onActivityCreated(savedInstanceState: Bundle?) {
initRecyclerView()
initSelectActionView()
observeDictRuleData()
}
private fun initRecyclerView() {
binding.recyclerView.setEdgeEffectColor(primaryColor)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
binding.recyclerView.addItemDecoration(VerticalDivider(this))
val itemTouchCallback = ItemTouchCallback(adapter)
itemTouchCallback.isCanDrag = true
val dragSelectTouchHelper: DragSelectTouchHelper =
DragSelectTouchHelper(adapter.dragSelectCallback).setSlideArea(16, 50)
dragSelectTouchHelper.attachToRecyclerView(binding.recyclerView)
// When this page is opened, it is in selection mode
dragSelectTouchHelper.activeSlideSelect()
// Note: need judge selection first, so add ItemTouchHelper after it.
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(binding.recyclerView)
}
private fun initSelectActionView() {
binding.selectActionBar.setMainActionText(R.string.delete)
binding.selectActionBar.inflateMenu(R.menu.replace_rule_sel)
binding.selectActionBar.setOnMenuItemClickListener(this)
binding.selectActionBar.setCallBack(this)
}
private fun observeDictRuleData() {
launch {
appDb.dictRuleDao.flowAll().collect {
adapter.setItems(it, adapter.diffItemCallBack)
}
}
}
override fun selectAll(selectAll: Boolean) {
TODO("Not yet implemented")
}
override fun revertSelection() {
TODO("Not yet implemented")
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
TODO("Not yet implemented")
}
override fun update(vararg rule: DictRule) {
TODO("Not yet implemented")
}
override fun delete(rule: DictRule) {
TODO("Not yet implemented")
}
override fun edit(rule: DictRule) {
TODO("Not yet implemented")
}
override fun toTop(rule: DictRule) {
TODO("Not yet implemented")
}
override fun toBottom(rule: DictRule) {
TODO("Not yet implemented")
}
override fun upOrder() {
TODO("Not yet implemented")
}
override fun upCountView() {
TODO("Not yet implemented")
}
}

View File

@@ -0,0 +1,226 @@
package io.legado.app.ui.dict.rule
import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.data.entities.DictRule
import io.legado.app.databinding.ItemReplaceRuleBinding
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.ui.widget.recycler.DragSelectTouchHelper
import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.utils.ColorUtils
class DictRuleAdapter(context: Context, var callBack: CallBack) :
RecyclerAdapter<DictRule, ItemReplaceRuleBinding>(context),
ItemTouchCallback.Callback {
private val selected = linkedSetOf<DictRule>()
val selection: List<DictRule>
get() {
return getItems().filter {
selected.contains(it)
}
}
val diffItemCallBack = object : DiffUtil.ItemCallback<DictRule>() {
override fun areItemsTheSame(oldItem: DictRule, newItem: DictRule): Boolean {
return oldItem.name == newItem.name
}
override fun areContentsTheSame(oldItem: DictRule, newItem: DictRule): Boolean {
if (oldItem.name != newItem.name) {
return false
}
if (oldItem.enabled != newItem.enabled) {
return false
}
return true
}
override fun getChangePayload(oldItem: DictRule, newItem: DictRule): Any? {
val payload = Bundle()
if (oldItem.name != newItem.name) {
payload.putBoolean("upName", true)
}
if (oldItem.enabled != newItem.enabled) {
payload.putBoolean("enabled", newItem.enabled)
}
if (payload.isEmpty) {
return null
}
return payload
}
}
fun selectAll() {
getItems().forEach {
selected.add(it)
}
notifyItemRangeChanged(0, itemCount, bundleOf(Pair("selected", null)))
callBack.upCountView()
}
fun revertSelection() {
getItems().forEach {
if (selected.contains(it)) {
selected.remove(it)
} else {
selected.add(it)
}
}
notifyItemRangeChanged(0, itemCount, bundleOf(Pair("selected", null)))
callBack.upCountView()
}
override fun getViewBinding(parent: ViewGroup): ItemReplaceRuleBinding {
return ItemReplaceRuleBinding.inflate(inflater, parent, false)
}
override fun onCurrentListChanged() {
callBack.upCountView()
}
override fun convert(
holder: ItemViewHolder,
binding: ItemReplaceRuleBinding,
item: DictRule,
payloads: MutableList<Any>
) {
binding.run {
val bundle = payloads.getOrNull(0) as? Bundle
if (bundle == null) {
root.setBackgroundColor(ColorUtils.withAlpha(context.backgroundColor, 0.5f))
cbName.text = item.name
swtEnabled.isChecked = item.enabled
cbName.isChecked = selected.contains(item)
} else {
bundle.keySet().map {
when (it) {
"selected" -> cbName.isChecked = selected.contains(item)
"upName" -> cbName.text = item.name
"enabled" -> swtEnabled.isChecked = item.enabled
}
}
}
}
}
override fun registerListener(holder: ItemViewHolder, binding: ItemReplaceRuleBinding) {
binding.apply {
swtEnabled.setOnCheckedChangeListener { buttonView, isChecked ->
if (buttonView.isPressed) {
getItem(holder.layoutPosition)?.let {
it.enabled = isChecked
callBack.update(it)
}
}
}
ivEdit.setOnClickListener {
getItem(holder.layoutPosition)?.let {
callBack.edit(it)
}
}
cbName.setOnClickListener {
getItem(holder.layoutPosition)?.let {
if (cbName.isChecked) {
selected.add(it)
} else {
selected.remove(it)
}
}
callBack.upCountView()
}
ivMenuMore.setOnClickListener {
showMenu(ivMenuMore, holder.layoutPosition)
}
}
}
private fun showMenu(view: View, position: Int) {
val item = getItem(position) ?: return
val popupMenu = PopupMenu(context, view)
popupMenu.inflate(R.menu.replace_rule_item)
popupMenu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.menu_top -> callBack.toTop(item)
R.id.menu_bottom -> callBack.toBottom(item)
R.id.menu_del -> callBack.delete(item)
}
true
}
popupMenu.show()
}
override fun swap(srcPosition: Int, targetPosition: Int): Boolean {
val srcItem = getItem(srcPosition)
val targetItem = getItem(targetPosition)
if (srcItem != null && targetItem != null) {
if (srcItem.sortNumber == targetItem.sortNumber) {
callBack.upOrder()
} else {
val srcOrder = srcItem.sortNumber
srcItem.sortNumber = targetItem.sortNumber
targetItem.sortNumber = srcOrder
movedItems.add(srcItem)
movedItems.add(targetItem)
}
}
swapItem(srcPosition, targetPosition)
return true
}
private val movedItems = linkedSetOf<DictRule>()
override fun onClearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
if (movedItems.isNotEmpty()) {
callBack.update(*movedItems.toTypedArray())
movedItems.clear()
}
}
val dragSelectCallback: DragSelectTouchHelper.Callback =
object : DragSelectTouchHelper.AdvanceCallback<DictRule>(Mode.ToggleAndReverse) {
override fun currentSelectedId(): MutableSet<DictRule> {
return selected
}
override fun getItemId(position: Int): DictRule {
return getItem(position)!!
}
override fun updateSelectState(position: Int, isSelected: Boolean): Boolean {
getItem(position)?.let {
if (isSelected) {
selected.add(it)
} else {
selected.remove(it)
}
notifyItemChanged(position, bundleOf(Pair("selected", null)))
callBack.upCountView()
return true
}
return false
}
}
interface CallBack {
fun update(vararg rule: DictRule)
fun delete(rule: DictRule)
fun edit(rule: DictRule)
fun toTop(rule: DictRule)
fun toBottom(rule: DictRule)
fun upOrder()
fun upCountView()
}
}

View File

@@ -2,5 +2,22 @@ package io.legado.app.ui.dict.rule
import android.app.Application
import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb
import io.legado.app.data.entities.DictRule
class DictRuleViewModel(application: Application) : BaseViewModel(application)
class DictRuleViewModel(application: Application) : BaseViewModel(application) {
fun upsert(vararg dictRule: DictRule) {
execute {
appDb.dictRuleDao.upsert(*dictRule)
}
}
fun delete(vararg dictRule: DictRule) {
execute {
appDb.dictRuleDao.delete(*dictRule)
}
}
}