Wednesday, 9 December 2020

Android Paging 3 how to filter, sort and search my data

I'm trying to implement paging I'm using Room and it took me ages to realize that its all done for me 😆 but what I need to do is be able to filter search and sort my data. I want to keep it as LiveData for now I can swap to flow later. I had this method to filter search and sort and it worked perfectly,

    @SuppressLint("DefaultLocale")
    private fun searchAndFilterPokemon(): LiveData<List<PokemonWithTypesAndSpecies>> {
        return Transformations.switchMap(search) { search ->
            val allPokemon = repository.searchPokemonWithTypesAndSpecies(search)
            Transformations.switchMap(filters) { filters ->
                val pokemon = when {
                    filters.isNullOrEmpty() -> allPokemon
                    else -> {
                        Transformations.switchMap(allPokemon) { pokemonList ->
                            val filteredList = pokemonList.filter { pokemon ->
                                pokemon.matches = 0
                                val filter = filterTypes(pokemon, filters)
                                filter
                            }
                            maybeSortList(filters, filteredList)
                        }
                    }
                }
                pokemon
            }
        }
    }

It have a few switchmaps here, the first is responding to search updating

    var search: MutableLiveData<String> = getSearchState()

the second is responding to filters updating

    val filters: MutableLiveData<MutableSet<String>> = getCurrentFiltersState()

and the third is watching the searched list updating, it then calls filterTypes and maybeSortList which are small methods for filtering and sorting

    @SuppressLint("DefaultLocale")
    private fun filterTypes(
        pokemon: PokemonWithTypesAndSpecies,
        filters: MutableSet<String>
    ): Boolean {
        var match = false
        for (filter in filters) {
            for (type in pokemon.types) {
                if (type.name.toLowerCase() == filter.toLowerCase()) {
                    val matches = pokemon.matches.plus(1)
                    pokemon.apply {
                        this.matches = matches
                    }
                    match = true
                }
            }
        }
        return match
    }

    private fun maybeSortList(
        filters: MutableSet<String>,
        filteredList: List<PokemonWithTypesAndSpecies>
    ): MutableLiveData<List<PokemonWithTypesAndSpecies>> {
        return if (filters.size > 1)
            MutableLiveData(filteredList.sortedByDescending {
                Log.d("VM", "SORTING ${it.pokemon.name} ${it.matches}")
                it.matches
            })
        else MutableLiveData(filteredList)
    }

as mentioned I want to migrate these to paging 3 and am having difficulty doing it Ive changed my repository and dao to return a PagingSource and I just want to change my view model to return the PagingData as a live data, so far I have this

@SuppressLint("DefaultLocale")
private fun searchAndFilterPokemonPager(): LiveData<PagingData<PokemonWithTypesAndSpecies>> {
    val pager =  Pager(
        config = PagingConfig(
            pageSize = 50,
            enablePlaceholders = false,
            maxSize = 200
        )
    ){
        searchAndFilterPokemonWithPaging()
    }.liveData.cachedIn(viewModelScope)

    Transformations.switchMap(filters){
        MutableLiveData<String>()
    }

    return Transformations.switchMap(search) {search ->
        val searchedPokemon =
            MutableLiveData<PagingData<PokemonWithTypesAndSpecies>>(pager.value?.filter { it.pokemon.name.contains(search) })
        Transformations.switchMap(filters) { filters ->
            val pokemon = when {
                filters.isNullOrEmpty() -> searchedPokemon
                else -> {
                    Transformations.switchMap(searchedPokemon) { pokemonList ->
                        val filteredList = pokemonList.filter { pokemon ->
                            pokemon.matches = 0
                            val filter = filterTypes(pokemon, filters)
                            filter
                        }
                        maybeSortList(filters, filteredList = filteredList)
                    }
                }
            }
            pokemon
        }
    }
}

but the switchmap is giving me an error that

Type inference failed: Cannot infer type parameter Y in 

fun <X : Any!, Y : Any!> switchMap
(
    source: LiveData<X!>,
    switchMapFunction: (input: X!) → LiveData<Y!>!
 )

which I think I understand but am not sure how to fix it, also the filter and sort methods won't work anymore and I cant see any good method replacements for it with the PageData, it has a filter but not a sort? any help appreciated : LiveData<Y!



from Android Paging 3 how to filter, sort and search my data

No comments:

Post a Comment