androidMain.tech.skot.view.GenericAdapter.kt Maven / Gradle / Ivy
package tech.skot.view
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
open class GenericAdapter(vararg possibleDefs: ItemDef, private val noDiff:Boolean = false) : RecyclerView.Adapter() {
var items: List- = emptyList()
set(value) {
if (value != field) {
if (noDiff || value.isEmpty()) {
field = value
notifyDataSetChanged()
} else {
val diffCallBack = DiffCallBack(field, value)
field = value
DiffUtil.calculateDiff(diffCallBack, true).dispatchUpdatesTo(this@GenericAdapter)
}
}
}
class DiffCallBack(private val oldList: List
- , private val newList: List
- ) : DiffUtil.Callback() {
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.def == newItem.def && oldItem.computeItemId() == newItem.computeItemId()
}
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.def == newItem.def &&
oldItem.computeItemId() == newItem.computeItemId() &&
if (oldItem is ValorisedItem<*>) {
oldItem.data == (newItem as ValorisedItem<*>).data
} else {
true
}
}
}
interface Item {
val def: ItemDef
fun bind(itemView: View, position: Int)
fun computeItemId(): Any?
}
interface ItemDef {
val idLayout: Int
val initialize: (View.() -> Unit)?
}
class FixItemDef(override val idLayout: Int, override val initialize: (View.() -> Unit)? = null) : ItemDef
class FixItem(override val def: FixItemDef) : Item {
override fun bind(itemView: View, position: Int) {
}
override fun computeItemId() = null
}
open class WithDataItemDef
(override val idLayout: Int, override val initialize: (View.() -> Unit)? = null, val buildOnSwipe: ((data: D) -> (() -> Unit)?)? = null, val computeId: ((data: D) -> Any)? = null, val bindDataWithIndex: (View.(data: D, index: Int) -> Any)? = null, val bindData: View.(data: D) -> Unit) : ItemDef {
fun addTo(viewGroup: ViewGroup, data: D) {
val view = LayoutInflater.from(viewGroup.context).inflate(idLayout, viewGroup, false)
view.bindData(data)
viewGroup.addView(view)
}
fun addTo(viewGroup: ViewGroup, datas: List) {
for (data in datas) {
addTo(viewGroup, data)
}
}
}
class ValorisedItem(override val def: WithDataItemDef, val data: D) : Item {
override fun computeItemId() =
def.computeId?.invoke(data) ?: data
var onSwipe: (() -> Unit)? = null
override fun bind(itemView: View, position: Int) {
def.bindData.invoke(itemView, data)
def.bindDataWithIndex?.invoke(itemView, data, position)
onSwipe = def.buildOnSwipe?.invoke(data)
}
}
private val mapTypeItemDef: Map = possibleDefs.mapIndexed { index, def -> index to def }.toMap()
private val mapItemDefType: Map = possibleDefs.mapIndexed { index, def -> def to index }.toMap()
override fun getItemViewType(position: Int) = mapItemDefType[items[position].def]!!
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = Holder(mapTypeItemDef[viewType]!!, parent)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: Holder, position: Int) {
val item = items[position]
item.bind(holder.itemView, position)
}
inner class Holder(val item: ItemDef, parent: ViewGroup) : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(item.idLayout, parent, false)) {
init {
item.initialize?.invoke(itemView)
}
var id: String? = null
}
}
operator fun GenericAdapter.Item.plus(element: GenericAdapter.Item?): List =
listOfNotNull(this, element)
operator fun GenericAdapter.Item.plus(elements: List?): List =
if (elements != null) {
val result = ArrayList()
result.add(this)
result.addAll(elements)
result
} else {
listOf(this)
}
operator fun List.plus(element: GenericAdapter.Item?): List =
if (element != null) {
val result = ArrayList()
result.addAll(this)
result.add(element)
result
} else {
this
}
operator fun List.plus(elements: List?): List =
if (elements != null) {
val result = ArrayList()
result.addAll(this)
result.addAll(elements)
result
} else {
this
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy