kunfei 3 лет назад
Родитель
Сommit
723da1f1d0

+ 5 - 0
app/src/main/java/io/legado/app/data/dao/DictRuleDao.kt

@@ -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)
 

+ 96 - 1
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleActivity.kt

@@ -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)
 
+    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")
+    }
+
+
 }

+ 226 - 0
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleAdapter.kt

@@ -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()
+    }
+}

+ 18 - 1
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleViewModel.kt

@@ -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)
+        }
+    }
+
+}