Skip to content

Instantly share code, notes, and snippets.

@mrahimygk
Created June 30, 2020 10:44
Show Gist options
  • Save mrahimygk/529f8ffc29274bf257c9a5fd27f8ca70 to your computer and use it in GitHub Desktop.
Save mrahimygk/529f8ffc29274bf257c9a5fd27f8ca70 to your computer and use it in GitHub Desktop.
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.*
/**
* By extending this base adapter you have to provide 2 predicate parameters:
*
* @param itemSimilarity: a predicate to check for item similarity.
* ```
{ oldItem, newItem -> oldItem.id == newItem.id },
```
* @param contentSimilarity: a predicate to check for content similarity.
* ```
{ oldItem, newItem -> oldItem == newItem }
```
*
*/
abstract class BaseAdapter<T>(
private val itemSimilarity: (T, T) -> Boolean,
private val contentSimilarity: (T, T) -> Boolean) : ListAdapter<T, BaseAdapter<T>.DataBindingViewHolder>(object : DiffUtil.ItemCallback<T>() {
override fun areContentsTheSame(oldItem: T, newItem: T) = contentSimilarity.invoke(oldItem, newItem)
override fun areItemsTheSame(oldItem: T, newItem: T) = itemSimilarity.invoke(oldItem, newItem)
}) {
var onItemClicked: ((item: T, view: View, position: Int) -> Unit)? = null
var onItemLongClicked: ((item: T, view: View, position: Int) -> Boolean)? = null
var onItemSelected: ((position: Int) -> Unit)? = null
var onClearSelections: (() -> Unit)? = null
var onSelectAll: ((list: IntRange) -> Unit)? = null
val selectedItems = mutableListOf<Int>()
var isInSelectMode = false
set(value) {
field = value
notifyDataSetChanged()
}
private val scope = CoroutineScope(Dispatchers.Main)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = DataBindingViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
viewType,
parent,
false
)
)
override fun onBindViewHolder(holder: DataBindingViewHolder, position: Int) =
holder.bind(getItem(position), position, position in selectedItems)
@LayoutRes
abstract override fun getItemViewType(position: Int): Int
fun clearAllSelectedItems() {
val currentItems = selectedItems.toList()
selectedItems.clear()
onClearSelections?.invoke()
scope.launch {
currentItems.forEach {
delay(2)
notifyItemChanged(it)
}
}
}
fun selectAll() = currentList.indices.let {
onSelectAll?.invoke(it)
selectedItems.addAll(it)
scope.launch {
it.forEach {
delay(2)
notifyItemChanged(it)
}
}
}
inner class DataBindingViewHolder(private val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: T, position: Int, isSelected: Boolean) {
binding.apply {
setVariable(BR.item, item)
executePendingBindings()
root.apply {
if (!isInSelectMode) {
root.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
} else {
if (isSelected) root.setBackgroundColor(ContextCompat.getColor(context, R.color.fine_red))
else root.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
}
setOnClickListener {
/**
* Does not select mock items
*/
if (isInSelectMode) {
onItemSelected?.invoke(adapterPosition)
if (isSelected) {
selectedItems.remove(adapterPosition)
notifyItemChanged(position)
} else {
selectedItems.add(adapterPosition)
notifyItemChanged(position)
}
} else onItemClicked?.invoke(item, this, adapterPosition)
}
setOnLongClickListener {
return@setOnLongClickListener onItemLongClicked?.invoke(item, this, adapterPosition)
?: return@setOnLongClickListener true
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment