0

I'm trying to insert separators to my list using the paging 3 compose library however, insertSeparators doesn't seem to indicate when we are at the beginning or end. My expectations are that before will be null at the beginning while after will be null at the end of the list. But it's never null thus hard to know when we are at the beginning or end. Here is the code:

    private val filterPreferences =
        MutableStateFlow(HomePreferences.FilterPreferences())
    
    val games: Flow<PagingData<GameModel>> = filterPreferences.flatMapLatest {
        useCase.execute(it)
    }.map { pagingData ->
        pagingData.map { GameModel.GameItem(it) }
    }.map {
        it.insertSeparators {before,after->
            if (after == null) {
                return@insertSeparators null
            }
            if (before == null) {
                Log.i(TAG, "before is null: ") // never reach here
                return@insertSeparators GameModel.SeparatorItem("title")
            }
            if(condition) {
                 GameModel.SeparatorItem("title")
          }
                else null     
        }
    }
        .cachedIn(viewModelScope)

GamesUseCase

class GamesUseCase @Inject constructor(
    private val executionThread: PostExecutionThread,
    private val repo: GamesRepo,
) : FlowUseCase<HomePreferences, PagingData<Game>>() {

    override val dispatcher: CoroutineDispatcher
        get() = executionThread.io

    override fun execute(params: HomePreferences?): Flow<PagingData<Game>> {
        val preferences = params as HomePreferences.FilterPreferences
        preferences.apply {
            return repo.fetchGames(query,
                parentPlatforms,
                platforms,
                stores,
                developers,
                genres,
                tags)
        }
    }
}

FlowUseCase

abstract class FlowUseCase<in Params, out T>() {

    abstract val dispatcher: CoroutineDispatcher

    abstract fun execute(params: Params? = null): Flow<T>

    operator fun invoke(params: Params? = null) = execute(params).flowOn(dispatcher)
}

Here is the dependency :

  object Pagination {
        object Version {
            const val pagingCompose = "1.0.0-alpha14"
        }
        const val pagingCompose = "androidx.paging:paging-compose:${Version.pagingCompose}"
    }
Jarnojr
  • 543
  • 1
  • 7
  • 18

1 Answers1

0

I'm assuming that filterPreferences gives you Flow of some preference and useCase.execute returns Flow<PagingData<Model>>, correct?

I believe that the problem is in usage of flatMapLatest - it mixes page events of multiple useCase.execute calls together.

You should do something like this:

val games: Flow<Flow<PagingData<GameModel>>> = filterPreferences.mapLatest {
  useCase.execute(it)
}.mapLatest {
  it.map { pagingData -> pagingData.map { GameModel.GameItem(it) } }
}.mapLatest {
  it.map { pagingData ->
    pagingData.insertSeparators { before, after -> ... }
  } // .cachedIn(viewModelScope)
}

This same structure works for us very well. I'm only not sure how cachedIn will work here, we are using a different caching mechanism, but you can try.

Jan Bína
  • 3,447
  • 14
  • 16
  • Thank you for the answer. I have updated my question and added the use case as well and yes, It gives me `Flow>`. I have removed `flatMapLatest` from the code but the result is still the same. Maybe there is a bug in the library. – Jarnojr Feb 01 '22 at 22:36
  • Hmm, weird. So you get correct (`before`, `after`) values for all the data - like (1st, 2nd), (2nd, 3rd), (3rd, 4th), ... but never (null, 1st) or (last, null), do I understand it correctly? – Jan Bína Feb 02 '22 at 00:43
  • Yes, you are correct. I just put a log statement in `insertSeparators` right before `if(after == null)` check and the result : `before = The Legend of Zelda: Ocarina of Time after = Soulcalibur (1998)` `before = Soulcalibur (1998) after = Soulcalibur` so `before` and `after` values are correct but never null. – Jarnojr Feb 02 '22 at 01:03
  • Ok, thats weird then and might be actually a bug in the library. But as I said, very similar setup with same library version works for me. I tried this example which resembles your problem without any api/db dependencies right now and it worked as expected too: https://pastebin.com/jVSCvFhY Maybe you can try it as well and if it works, modify it gradually to find out whats causing the problem, if it does not, report a bug. – Jan Bína Feb 02 '22 at 13:04
  • 1
    Ok bro, thank you so much for your effort and time. I will be working on it. – Jarnojr Feb 02 '22 at 17:39