myinnos / AlphabetIndex-Fast-Scroll-RecyclerView

A Powerful AlphabetIndex FastScroller Library for Android's RecyclerView!
https://myinnos.github.io/AlphabetIndex-Fast-Scroll-RecyclerView/
Apache License 2.0
603 stars 114 forks source link

Does not work with list adapter or after the list is updated #89

Open sachdeva-tagic opened 1 year ago

sachdeva-tagic commented 1 year ago

Hello. I am trying to find a way by which it could work with a list adapter or with a regular recycler adapter but updating the mappings when list content is updated. currently the mappings remain the same and it causes a crash. can you help?

Here is my list adapter file :

class Adp: ListAdapter<String,CityVH>(DIFFER), SectionIndexer {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = CityVH(ItemRvBinding.inflate(LayoutInflater.from(parent.context),parent,false))

    override fun onBindViewHolder(holder: CityVH, position: Int) {
       holder.bind(getItem(position)?:"")
    }

    private val sideCharToMainDataPositionMap = hashMapOf<Char,Int>()

    override fun getSections(): Array<String> {
        logger("getSections() called")
        val sideScrollerEntries = getSectionEntries()
        prepareMapping(sideScrollerEntries)
        return sideScrollerEntries.map { it.toString() }.toTypedArray()
    }

    private fun prepareMapping(sideScrollerEntries: Array<Char>) {
        logger("prepareMapping() called with: sideScrollerEntries = ${sideScrollerEntries.contentToString()}")

        val uniqueCharsAndIndices =  currentList
            .mapIndexed { index, s -> s.first() to index } //take 1st char of each entry and its associated position
            .distinctBy { it.first }// filter out all the duplicates
        val uniqueChars: List<Char> = uniqueCharsAndIndices.map { it.first }
        val uniqueCharIndices = uniqueCharsAndIndices.map { it.second }

        logger("uniqueCharsAndIndices: $uniqueCharsAndIndices")
        if (uniqueCharIndices.isEmpty()) return
        sideCharToMainDataPositionMap.clear()
        var lastCharIdx = uniqueCharIndices.first()
        sideScrollerEntries.forEach {
            if (it in uniqueChars) {
                val assocIdx = uniqueChars.indexOf(it)
                val assocUniqueCharPlacementIdx = uniqueCharIndices[assocIdx]
                sideCharToMainDataPositionMap[it] = assocUniqueCharPlacementIdx
                lastCharIdx = assocUniqueCharPlacementIdx
            } else {
                sideCharToMainDataPositionMap[it] = lastCharIdx
            }
        }
        logger("sideCharToMainDataPositionMap: $sideCharToMainDataPositionMap")

    }
    private fun getSectionEntries():Array<Char>{
        logger( "getSectionEntries() called. currentList=$currentList")
        val all =  ALL_CHARS.map { it }.toTypedArray()
        val onlyAvailable = currentList.map { it.first() }.distinct().toTypedArray()
        return onlyAvailable
    }

    override fun getPositionForSection(charIndex: Int): Int {
        val char = getSectionEntries().getOrNull(charIndex)
        val assocRecyclerPosition = sideCharToMainDataPositionMap[char] ?:0
        logger("getPositionForSection() called with: charIndex = $charIndex | assoc char=$char |assocRecyclerPosition=$assocRecyclerPosition")
        return assocRecyclerPosition
    }

    override fun getSectionForPosition(position: Int): Int {
        logger( "getSectionForPosition() called with: position = $position and returned 0")
        return 0
    }

    companion object{
        private const val ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#"

        private val DIFFER = object :DiffUtil.ItemCallback<String>(){
            override fun areItemsTheSame(oldItem: String, newItem: String) = oldItem == newItem
            override fun areContentsTheSame(oldItem: String, newItem: String) = oldItem.contentEquals(newItem)
        }
        fun logger(s:String){
            Log.e("ALPHA", s )
        }
    }
}