Created
June 30, 2020 10:44
-
-
Save mrahimygk/529f8ffc29274bf257c9a5fd27f8ca70 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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