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!
UPDATE thanks to @Shadow I've rewritten it to implement searching using a mediator live data but im still stuck on filtering
init {
val combinedValues =
MediatorLiveData<Pair<String?, MutableSet<String>?>?>().apply {
addSource(search) {
value = Pair(it, filters.value)
}
addSource(filters) {
value = Pair(search.value, it)
}
}
searchPokemon = Transformations.switchMap(combinedValues) { pair ->
val search = pair?.first
val filters = pair?.second
if (search != null && filters != null) {
searchAndFilterPokemonPager(search)
} else null
}
}
@SuppressLint("DefaultLocale")
private fun searchAndFilterPokemonPager(search: String): LiveData<PagingData<PokemonWithTypesAndSpecies>> {
return Pager(
config = PagingConfig(
pageSize = 50,
enablePlaceholders = false,
maxSize = 200
)
){
searchAllPokemonWithPaging(search)
}.liveData.cachedIn(viewModelScope)
}
@SuppressLint("DefaultLocale")
private fun searchAllPokemonWithPaging(search: String): PagingSource<Int, PokemonWithTypesAndSpecies> {
return repository.searchPokemonWithTypesAndSpeciesWithPaging(search)
}