All Downloads are FREE. Search and download functionalities are using the official Maven repository.

androidMain.tech.skot.view.GenericAdapter.kt Maven / Gradle / Ivy

There is a newer version: 1.2.9
Show newest version
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