HumanLearning2021/HumanLearningApp

View on GitHub
app/src/main/java/com/github/HumanLearning2021/HumanLearningApp/view/dataset_list_fragment/DatasetListRecyclerViewAdapter.kt

Summary

Maintainability
A
0 mins
Test Coverage
A
98%
package com.github.HumanLearning2021.HumanLearningApp.view.dataset_list_fragment

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.recyclerview.widget.RecyclerView
import com.github.HumanLearning2021.HumanLearningApp.R
import com.github.HumanLearning2021.HumanLearningApp.model.DatabaseManagement
import com.github.HumanLearning2021.HumanLearningApp.model.Dataset
import com.github.HumanLearning2021.HumanLearningApp.model.ImageDisplayer
import kotlinx.coroutines.launch
import java.util.*

class DatasetListRecyclerViewAdapter(
    private val imageDisplayer: ImageDisplayer,
    private val lifecycleScope: LifecycleCoroutineScope,
    private val dbMgt: DatabaseManagement,
    private val itemClickedCallback: (Dataset) -> Unit
) : RecyclerView.Adapter<DatasetListRecyclerViewAdapter.ListItemViewHolder>(), Filterable {

    companion object {
        /**
         * Defines the number of categories shown on one ListItemViewHolder
         */
        const val NB_REPRESENTATIVES_SHOWN = 3
    }

    private lateinit var datasetList: List<Dataset>
    private lateinit var originalDatasetList: List<Dataset>

    init {
        lifecycleScope.launch {
            datasetList = dbMgt.getDatasets().toList()
            originalDatasetList = datasetList
            notifyDataSetChanged()
        }
    }

    /**
     * Gets called when a new view holder is needed
     * (for example when the user scrolls to reveal more items)
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.fragment_dataset_list_elt, parent, false)
        return ListItemViewHolder(view)
    }

    /**
     * Gets called to allow the ViewHolder to be bound to its data, given its position
     */
    override fun onBindViewHolder(holder: ListItemViewHolder, position: Int) {
        if (::datasetList.isInitialized) {
            val ds = datasetList[position]
            holder.itemView.apply {
                findViewById<TextView>(R.id.textView_datasetList_elt_text).text = ds.name
                setRepresentativePictures(this, ds)

                // bind the dataset so that the holder can call `itemClickedCallback`
                // with the appropriate dataset
                holder.bindDataset(ds)
            }
        }
    }

    private fun setRepresentativePictures(view: View, ds: Dataset) {
        val catList = ds.categories.toList()
        if (catList.size >= NB_REPRESENTATIVES_SHOWN) {
            lifecycleScope.launch {
                val repr0 = dbMgt.getRepresentativePicture(catList[0].id)
                val repr1 = dbMgt.getRepresentativePicture(catList[1].id)
                val repr2 = dbMgt.getRepresentativePicture(catList[2].id)

                with(view) {
                    with(imageDisplayer) {
                        repr0?.displayOn(findViewById(R.id.imageView_datasetList_elt_im0))
                        repr1?.displayOn(findViewById(R.id.imageView_datasetList_elt_im1))
                        repr2?.displayOn(findViewById(R.id.imageView_datasetList_elt_im2))
                    }
                }
            }
        }
    }

    override fun getItemCount(): Int =
        if (::datasetList.isInitialized) {
            datasetList.size
        } else {
            0
        }

    inner class ListItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bindDataset(ds: Dataset) {
            itemView.setOnClickListener { itemClickedCallback(ds) }
        }
    }

    override fun getFilter(): Filter {
        /** type-erasure countermeasure */
        class ListOfDatasets(val value: List<Dataset>)
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                val filterPattern = constraint.toString().toLowerCase(Locale.getDefault()).trim()
                val filteredList = originalDatasetList.filter {
                    it.name.toLowerCase(Locale.getDefault()).startsWith(filterPattern)
                }
                return FilterResults().apply { values = ListOfDatasets(filteredList) }
            }

            override fun publishResults(constraint: CharSequence?, results: FilterResults) {
                datasetList = (results.values as ListOfDatasets).value
                notifyDataSetChanged()
            }
        }
    }
}