Refactor RecyclerView adapters

This commit is contained in:
Matéo Duparc 2022-04-09 20:13:39 +02:00
parent 4de5b41102
commit f541504e07
Signed by untrusted user: hardcoresushi
GPG Key ID: AFE384344A45E13A
3 changed files with 111 additions and 120 deletions

View File

@ -22,7 +22,6 @@ import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
import kotlin.collections.HashSet
class ExplorerElementAdapter( class ExplorerElementAdapter(
val activity: AppCompatActivity, val activity: AppCompatActivity,
@ -30,7 +29,7 @@ class ExplorerElementAdapter(
val onExplorerElementClick: (Int) -> Unit, val onExplorerElementClick: (Int) -> Unit,
val onExplorerElementLongClick: (Int) -> Unit, val onExplorerElementLongClick: (Int) -> Unit,
val thumbnailMaxSize: Long, val thumbnailMaxSize: Long,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : SelectableAdapter<ExplorerElement>() {
val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault()) val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
var explorerElements = listOf<ExplorerElement>() var explorerElements = listOf<ExplorerElement>()
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@ -39,7 +38,6 @@ class ExplorerElementAdapter(
thumbnailsCache?.evictAll() thumbnailsCache?.evictAll()
notifyDataSetChanged() notifyDataSetChanged()
} }
var selectedItems: MutableSet<Int> = HashSet()
var isUsingListLayout = true var isUsingListLayout = true
private var thumbnailsCache: LruCache<String, Bitmap>? = null private var thumbnailsCache: LruCache<String, Bitmap>? = null
@ -49,56 +47,32 @@ class ExplorerElementAdapter(
} }
} }
override fun getItemCount(): Int { override fun getItems(): List<ExplorerElement> {
return explorerElements.size return explorerElements
} }
private fun toggleSelection(position: Int): Boolean { override fun toggleSelection(position: Int): Boolean {
if (!explorerElements[position].isParentFolder) { return if (!explorerElements[position].isParentFolder) {
if (selectedItems.contains(position)) { super.toggleSelection(position)
selectedItems.remove(position)
} else {
selectedItems.add(position)
return true
}
}
return false
}
private fun onItemClick(position: Int): Boolean {
onExplorerElementClick(position)
if (selectedItems.isNotEmpty()) {
return toggleSelection(position)
}
return false
}
private fun onItemLongClick(position: Int): Boolean {
onExplorerElementLongClick(position)
return toggleSelection(position)
}
fun selectAll() {
for (i in explorerElements.indices) {
if (!selectedItems.contains(i) && !explorerElements[i].isParentFolder) {
selectedItems.add(i)
notifyItemChanged(i)
}
}
}
fun unSelectAll(notifyChange: Boolean) {
if (notifyChange) {
val whatWasSelected = selectedItems
selectedItems = HashSet()
whatWasSelected.forEach {
notifyItemChanged(it)
}
} else { } else {
selectedItems.clear() false
} }
} }
override fun onItemClick(position: Int): Boolean {
onExplorerElementClick(position)
return super.onItemClick(position)
}
override fun onItemLongClick(position: Int): Boolean {
onExplorerElementLongClick(position)
return super.onItemLongClick(position)
}
override fun isSelectable(position: Int): Boolean {
return !explorerElements[position].isParentFolder
}
open class ExplorerElementViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { open class ExplorerElementViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textElementName by lazy { private val textElementName by lazy {
itemView.findViewById<TextView>(R.id.text_element_name) itemView.findViewById<TextView>(R.id.text_element_name)
@ -116,21 +90,9 @@ class ExplorerElementAdapter(
itemView.findViewById(R.id.selectable_container) itemView.findViewById(R.id.selectable_container)
} }
protected fun setBackground(isSelected: Boolean) {
itemView.setBackgroundResource(if (isSelected) { R.color.itemSelected } else { 0 })
}
open fun bind(explorerElement: ExplorerElement, position: Int) { open fun bind(explorerElement: ExplorerElement, position: Int) {
textElementName.text = explorerElement.name textElementName.text = explorerElement.name
(bindingAdapter as ExplorerElementAdapter?)?.let { adapter -> (bindingAdapter as ExplorerElementAdapter?)?.setSelectable(selectableContainer, itemView, position)
selectableContainer.setOnClickListener {
setBackground(adapter.onItemClick(position))
}
selectableContainer.setOnLongClickListener {
setBackground(adapter.onItemLongClick(position))
true
}
}
} }
} }
@ -141,7 +103,6 @@ class ExplorerElementAdapter(
(bindingAdapter as ExplorerElementAdapter?)?.let { (bindingAdapter as ExplorerElementAdapter?)?.let {
textElementMtime.text = it.dateFormat.format(explorerElement.mTime) textElementMtime.text = it.dateFormat.format(explorerElement.mTime)
} }
setBackground(isSelected)
} }
} }

View File

@ -0,0 +1,76 @@
package sushi.hardcore.droidfs.adapters
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import sushi.hardcore.droidfs.R
abstract class SelectableAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var selectedItems: MutableSet<Int> = HashSet()
protected abstract fun getItems(): List<T>
override fun getItemCount(): Int {
return getItems().size
}
protected open fun toggleSelection(position: Int): Boolean {
return if (selectedItems.contains(position)) {
selectedItems.remove(position)
false
} else {
selectedItems.add(position)
true
}
}
protected open fun onItemClick(position: Int): Boolean {
if (selectedItems.isNotEmpty()) {
return toggleSelection(position)
}
return false
}
protected open fun onItemLongClick(position: Int): Boolean {
return toggleSelection(position)
}
protected open fun isSelectable(position: Int): Boolean {
return true
}
fun selectAll() {
for (i in getItems().indices) {
if (!selectedItems.contains(i) && isSelectable(i)) {
selectedItems.add(i)
notifyItemChanged(i)
}
}
}
fun unSelectAll(notifyChange: Boolean) {
if (notifyChange) {
val whatWasSelected = selectedItems
selectedItems = HashSet()
whatWasSelected.forEach {
notifyItemChanged(it)
}
} else {
selectedItems.clear()
}
}
private fun setBackground(rootView: View, isSelected: Boolean) {
rootView.setBackgroundResource(if (isSelected) R.color.itemSelected else 0)
}
protected fun setSelectable(element: View, rootView: View, position: Int) {
element.setOnClickListener {
setBackground(rootView, onItemClick(position))
}
element.setOnLongClickListener {
setBackground(rootView, onItemLongClick(position))
true
}
setBackground(rootView, selectedItems.contains(position))
}
}

View File

@ -19,15 +19,18 @@ class VolumeAdapter(
private val showReadOnly: Boolean, private val showReadOnly: Boolean,
private val onVolumeItemClick: (Volume, Int) -> Unit, private val onVolumeItemClick: (Volume, Int) -> Unit,
private val onVolumeItemLongClick: () -> Unit, private val onVolumeItemLongClick: () -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : SelectableAdapter<Volume>() {
private val inflater: LayoutInflater = LayoutInflater.from(context) private val inflater: LayoutInflater = LayoutInflater.from(context)
lateinit var volumes: List<Volume> lateinit var volumes: List<Volume>
var selectedItems: MutableSet<Int> = HashSet()
init { init {
reloadVolumes() reloadVolumes()
} }
override fun getItems(): List<Volume> {
return volumes
}
private fun reloadVolumes() { private fun reloadVolumes() {
volumes = if (showReadOnly) { volumes = if (showReadOnly) {
volumeDatabase.getVolumes() volumeDatabase.getVolumes()
@ -36,28 +39,19 @@ class VolumeAdapter(
} }
} }
private fun toggleSelection(position: Int): Boolean { override fun onItemClick(position: Int): Boolean {
return if (selectedItems.contains(position)) {
selectedItems.remove(position)
false
} else {
selectedItems.add(position)
true
}
}
private fun onItemClick(position: Int): Boolean {
onVolumeItemClick(volumes[position], position) onVolumeItemClick(volumes[position], position)
if (allowSelection && selectedItems.isNotEmpty()) { return if (allowSelection) {
return toggleSelection(position) super.onItemClick(position)
} else {
false
} }
return false
} }
private fun onItemLongClick(position: Int): Boolean { override fun onItemLongClick(position: Int): Boolean {
onVolumeItemLongClick() onVolumeItemLongClick()
return if (allowSelection) return if (allowSelection)
toggleSelection(position) super.onItemLongClick(position)
else else
false false
} }
@ -67,27 +61,6 @@ class VolumeAdapter(
notifyItemChanged(position) notifyItemChanged(position)
} }
fun selectAll() {
for (i in volumes.indices) {
if (!selectedItems.contains(i)) {
selectedItems.add(i)
notifyItemChanged(i)
}
}
}
fun unSelectAll(notifyChange: Boolean) {
if (notifyChange) {
val whatWasSelected = selectedItems
selectedItems = HashSet()
whatWasSelected.forEach {
notifyItemChanged(it)
}
} else {
selectedItems.clear()
}
}
fun refresh() { fun refresh() {
reloadVolumes() reloadVolumes()
unSelectAll(true) unSelectAll(true)
@ -95,10 +68,6 @@ class VolumeAdapter(
inner class VolumeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class VolumeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private fun setBackground(isSelected: Boolean) {
itemView.setBackgroundResource(if (isSelected) R.color.itemSelected else 0)
}
fun bind(position: Int) { fun bind(position: Int) {
val volume = volumes[position] val volume = volumes[position]
itemView.findViewById<TextView>(R.id.text_volume_name).text = volume.shortName itemView.findViewById<TextView>(R.id.text_volume_name).text = volume.shortName
@ -123,18 +92,7 @@ class VolumeAdapter(
visibility = View.VISIBLE visibility = View.VISIBLE
} }
} }
(bindingAdapter as VolumeAdapter?)?.let { adapter -> setSelectable(itemView.findViewById<LinearLayout>(R.id.selectable_container), itemView, layoutPosition)
itemView.findViewById<LinearLayout>(R.id.selectable_container).apply {
setOnClickListener {
setBackground(adapter.onItemClick(layoutPosition))
}
setOnLongClickListener {
setBackground(adapter.onItemLongClick(layoutPosition))
true
}
}
}
setBackground(selectedItems.contains(position))
} }
} }
@ -146,8 +104,4 @@ class VolumeAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as VolumeViewHolder).bind(position) (holder as VolumeViewHolder).bind(position)
} }
override fun getItemCount(): Int {
return volumes.size
}
} }