0

I'm currently trying to implement a list using paging 3. My current implementation allows me to load a list of data, choose a filter option but the screen is not automatically refreshing at the moment with the filtered list. It's only doing so at the start of a new screen. How could I force the screen to update automatically after a user input.

My viewModel:

class NewsArticleListViewModel : BaseViewModel() {
    companion object {
        private const val pageSize = 20
    }

    val preferences: SupportPreferences by instance()
    private val viewStateLiveData = MutableLiveData<ViewState<Any>>()

    private val getNewsListUseCase: GetNewsArticleListUseCase by instance()

     private lateinit var dataSource: NewsArticleListPagingSource

    private lateinit var brand: String
    private var searchText = ""

    val newsParamsLiveData = MutableLiveData<NewsArticleListPagingSource.Params>()


    val news = Pager(
        config = PagingConfig(pageSize = pageSize, enablePlaceholders = true),
        pagingSourceFactory = { NewsArticleListPagingSource(getNewsListUseCase, generateParams(), pageSize, viewStateLiveData)
        }, initialKey = 1
    ).liveData.cachedIn(viewModelScope)


//    val news = newsParamsLiveData.switchMap { params ->
//        Pager(
//            PagingConfig(
//                pageSize = pageSize,
//                enablePlaceholders = true),
//            pagingSourceFactory = { NewsArticleListPagingSource(getNewsListUseCase, params, pageSize, viewStateLiveData)}
//            ).liveData.cachedIn(viewModelScope)
//    }

    fun viewState(): LiveData<ViewState<Any>> = viewStateLiveData

    fun initialize(brand: String) {
        this.brand = brand
        dataSource = NewsArticleListPagingSource(getNewsListUseCase, generateParams(), pageSize, viewStateLiveData)
    }


    fun updateNewsSort(sortFilter: NewsFilter) {
        if (preferences.newsArticlesSortKey.value == sortFilter) return
        preferences.newsArticlesSortKey.value = sortFilter
        dataSource.invalidate()
    }
    fun refresh(){
        dataSource.invalidate()
    }
    fun search(value: String) {
        if (value != searchText) {
            searchText = value
        }
    }


    fun updateSelectedAuthor(selectedAuthor: NewsFilter) {
        val defaultValue = preferences.newsSelectedAuthor.defaultValue
        if (preferences.newsSelectedAuthor.value == selectedAuthor) {
            // deselect current selection
            if (selectedAuthor == defaultValue) return
            preferences.newsSelectedAuthor.value = defaultValue
        } else {
            preferences.newsSelectedAuthor.value = selectedAuthor
        }
    }

    fun updateSelectedCategory(selectedCategory: NewsFilter) {
        val defaultValue = preferences.newsSelectedCategory.defaultValue
        if (preferences.newsSelectedCategory.value == selectedCategory) {
            // deselect current selection
            if (selectedCategory == defaultValue) return
            preferences.newsSelectedCategory.value = defaultValue
        } else {
            preferences.newsSelectedCategory.value = selectedCategory
        }
    }


    private fun generateParams(): NewsArticleListPagingSource.Params {
        return NewsArticleListPagingSource.Params(
                brand = brand,
                isTrending = preferences.newsArticlesSortKey.value.filterValue == NewsArticleListView.SortKey.TRENDING.name,
                author = if (preferences.newsSelectedAuthor.value == preferences.newsSelectedAuthor.defaultValue) null else preferences.newsSelectedAuthor.value.filterValue,
                category = if (preferences.newsSelectedCategory.value == preferences.newsSelectedCategory.defaultValue) null else preferences.newsSelectedCategory.value.filterValue,
                search = searchText
        )
    }
}

My paging source

class NewsArticleListPagingSource(
    private val getNewsArticleListUseCase: GetNewsArticleListUseCase,
    private val queryParams: Params,
    private val pageSize: Int,
    private val viewStateLiveData: MutableLiveData<ViewState<Any>>
): PagingSource<Int, NewsArticleData>() {

    var totalPages = 0


    var currentPagingSource: NewsArticleListPagingSource? = null

    override fun getRefreshKey(state: PagingState<Int, NewsArticleData>): Int? {
        return state.anchorPosition?.let { anchorPosition ->
            state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
                ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, NewsArticleData> {
       val pageIndex = params.key ?: 1
        var result = listOf<NewsArticleData>()
        return try {

            getNewsArticleListUseCase.invoke(GetNewsArticleListUseCase.Params(
                queryParams.brand,
                pageIndex,
                queryParams.category,
                queryParams.tag,
                queryParams.isTrending,
                queryParams.isFeatured,
                queryParams.author,
                queryParams.search,
                queryParams.sort,
                pageSize
            )).collect {
              result = it.data
                totalPages = it.totalPages ?: 10
            }
              LoadResult.Page(
                 data = result,
                 prevKey = if (pageIndex == 1) null else pageIndex -1,
                 nextKey = if (pageIndex >= totalPages) null else pageIndex + 1
             )
        } catch (e: Exception) {
             viewStateLiveData.value = ViewState.Error(true, e)
             return LoadResult.Error(e)
        }
    }

    fun updateParams() {
        currentPagingSource?.invalidate()
    }
    data class Params(
        val brand: String,
        val category: String? = null,
        val tag: String? = null,
        val isTrending: Boolean = true,
        val isFeatured: Boolean? = null,
        val author: String? = null,
        val search: String? = null,
        val sort: String? = null
    )
}

My controller:

package au.com.punters.support.android.news.list

import au.com.punters.support.android.content.GetNewsArticleListQuery
import au.com.punters.support.android.data.injection.SupportModules
import au.com.punters.support.android.news.model.NewsArticleData
import au.com.punters.support.android.news.rows.RowNewsArticle
import au.com.punters.support.android.news.rows.RowNewsFilters
import au.com.punters.support.android.preferences.SupportPreferences
import au.com.punters.support.android.view.rows.RowDivider
import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController
import com.airbnb.epoxy.paging3.PagingDataEpoxyController
import org.kodein.di.Kodein
import org.kodein.di.KodeinAware
import org.kodein.di.generic.instance

open class NewsArticlePagedListController(protected val listener: NewsArticleListListener)
    : PagingDataEpoxyController<NewsArticleData>(), KodeinAware {

    override val kodein: Kodein = SupportModules.instance

    private val preference: SupportPreferences by instance()

    override fun buildItemModel(currentPosition: Int, item: NewsArticleData?): EpoxyModel<*> {

        if (item == null) return RowDivider(currentPosition.toString() + "placeholder")

        return createRowNewsArticle(item)
    }

    open fun createRowNewsArticle(item: NewsArticleData): EpoxyModel<*> {
        return RowNewsArticle(item,
            { listener.isNewsRestricted(item) },
            { listener.onNewArticleSelected(item, false) })
    }

    override fun addModels(models: List<EpoxyModel<*>>) {
        preference.newsSelectedCategory.value
        RowNewsFilters(
                currentSorting = preference.newsArticlesSortKey.value.displayName,
                currentAuthor = preference.newsSelectedAuthor.value.displayName,
                currentCategory = preference.newsSelectedCategory.value.displayName,
                onSortClick = { listener.onSortClicked() },
                onAuthorClick = { listener.onAuthorFilterClicked() },
                onCategoryClick = { listener.onCategoryFilterClicked() },
                onSearchTextChanged = { text -> listener.onSearchTextChanged(text) },
                onSearchButtonClicked = { listener.onSearchButtonClicked() }
        ).addTo(this)
        super.addModels(models)
    }
}

and my paging data is being observed in the fragment

   viewModel.news.observe(viewLifecycleOwner) {
            lifecycleScope.launch {
                newsArticlePagedListController.submitData(it)
            }
        }

I have tried calling dataSource.invalidate() within the updateSelectAuthor(), search() and updateSelectedCategory but nothing changes. Also tried creating a MutableLiveData of the params which are the values that change and assign it to a switchMap within the construction of the pager but no list will show up.

NewCoder19
  • 11
  • 4

0 Answers0