pager: do not skip next batch if current batch yields no valid apps
This commit is contained in:
11
app/src/main/java/com/aurora/store/data/PageResult.kt
Normal file
11
app/src/main/java/com/aurora/store/data/PageResult.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Aurora OSS
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.aurora.store.data
|
||||
|
||||
data class PageResult<T>(
|
||||
val items: List<T>,
|
||||
val hasMore: Boolean = items.isNotEmpty()
|
||||
)
|
||||
@@ -10,6 +10,7 @@ import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingSource.LoadResult.Page.Companion.COUNT_UNDEFINED
|
||||
import androidx.paging.PagingState
|
||||
import com.aurora.store.data.PageResult
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.pager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -23,7 +24,7 @@ import kotlinx.coroutines.withContext
|
||||
* @param block Data to load into the pager
|
||||
*/
|
||||
class GenericPagingSource<T : Any>(
|
||||
private val block: suspend (Int) -> List<T>
|
||||
private val block: suspend (Int) -> PageResult<T>
|
||||
) : PagingSource<Int, T>() {
|
||||
|
||||
companion object {
|
||||
@@ -54,7 +55,7 @@ class GenericPagingSource<T : Any>(
|
||||
fun <T : Any> manualPager(
|
||||
pageSize: Int = DEFAULT_PAGE_SIZE,
|
||||
enablePlaceholders: Boolean = true,
|
||||
data: suspend (Int) -> List<T>
|
||||
data: suspend (Int) -> PageResult<T>
|
||||
): Pager<Int, T> = Pager(
|
||||
config = PagingConfig(enablePlaceholders = enablePlaceholders, pageSize = pageSize),
|
||||
pagingSourceFactory = { GenericPagingSource(data) }
|
||||
@@ -65,12 +66,12 @@ class GenericPagingSource<T : Any>(
|
||||
val page = params.key ?: 1
|
||||
return try {
|
||||
withContext(Dispatchers.IO) {
|
||||
val data = block(page)
|
||||
val result = block(page)
|
||||
LoadResult.Page(
|
||||
data = data,
|
||||
data = result.items,
|
||||
prevKey = if (page == 1) null else page - 1,
|
||||
nextKey = if (data.isEmpty()) null else page + 1,
|
||||
itemsAfter = if (data.isEmpty()) 0 else COUNT_UNDEFINED
|
||||
nextKey = if (result.hasMore) page + 1 else null,
|
||||
itemsAfter = if (result.hasMore) COUNT_UNDEFINED else 0
|
||||
)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
|
||||
@@ -20,14 +20,13 @@
|
||||
package com.aurora.store.viewmodel.all
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import com.aurora.extensions.TAG
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.helpers.web.WebAppDetailsHelper
|
||||
import com.aurora.store.data.PageResult
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager
|
||||
import com.aurora.store.data.providers.BlacklistProvider
|
||||
import com.aurora.store.util.PackageUtil
|
||||
@@ -63,14 +62,11 @@ class InstalledViewModel @Inject constructor(
|
||||
.chunked(20)
|
||||
|
||||
manualPager { page ->
|
||||
try {
|
||||
// page is 1-indexed, but list is 0-indexed
|
||||
val chunk = pagedPackages.getOrNull(page - 1) ?: return@manualPager emptyList()
|
||||
webAppDetailsHelper.getAppDetails(chunk.map { it.packageName })
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to fetch apps", exception)
|
||||
emptyList()
|
||||
}
|
||||
// page is 1-indexed, but list is 0-indexed
|
||||
val chunk = pagedPackages.getOrNull(page - 1)
|
||||
?: return@manualPager PageResult(emptyList<App>(), hasMore = false)
|
||||
val items = webAppDetailsHelper.getAppDetails(chunk.map { it.packageName })
|
||||
PageResult(items, hasMore = page < pagedPackages.size)
|
||||
}.flow.distinctUntilChanged()
|
||||
.cachedIn(viewModelScope)
|
||||
.onEach { _apps.value = it }
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.aurora.extensions.TAG
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.web.WebStreamHelper
|
||||
import com.aurora.store.data.PageResult
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
@@ -61,7 +62,7 @@ class StreamBrowseViewModel @AssistedInject constructor(
|
||||
var nextPageUrl: String = streamCluster.clusterNextPageUrl
|
||||
|
||||
manualPager { page ->
|
||||
try {
|
||||
val items = try {
|
||||
when (page) {
|
||||
1 -> streamCluster.clusterAppList
|
||||
|
||||
@@ -79,6 +80,7 @@ class StreamBrowseViewModel @AssistedInject constructor(
|
||||
Log.e(TAG, "Failed to fetch apps for $page: $nextPageUrl", exception)
|
||||
emptyList()
|
||||
}
|
||||
PageResult(items)
|
||||
}.flow.distinctUntilChanged()
|
||||
.cachedIn(viewModelScope)
|
||||
.onEach { _apps.value = it }
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.paging.cachedIn
|
||||
import com.aurora.extensions.TAG
|
||||
import com.aurora.gplayapi.data.models.Review
|
||||
import com.aurora.gplayapi.helpers.ReviewsHelper
|
||||
import com.aurora.store.data.PageResult
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
@@ -46,7 +47,7 @@ class ReviewViewModel @AssistedInject constructor(
|
||||
var reviewsNextPageUrl: String? = null
|
||||
|
||||
manualPager { page ->
|
||||
try {
|
||||
val items = try {
|
||||
when (page) {
|
||||
1 -> reviewsHelper.getReviews(packageName, filter).also {
|
||||
reviewsNextPageUrl = it.nextPageUrl
|
||||
@@ -66,6 +67,7 @@ class ReviewViewModel @AssistedInject constructor(
|
||||
Log.e(TAG, "Failed to fetch reviews for $page: $reviewsNextPageUrl", exception)
|
||||
emptyList()
|
||||
}
|
||||
PageResult(items)
|
||||
}.flow.distinctUntilChanged()
|
||||
.cachedIn(viewModelScope)
|
||||
.onEach { _reviews.value = it }
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.aurora.gplayapi.data.models.StreamCluster
|
||||
import com.aurora.gplayapi.helpers.SearchHelper
|
||||
import com.aurora.gplayapi.helpers.contracts.SearchContract
|
||||
import com.aurora.gplayapi.helpers.web.WebSearchHelper
|
||||
import com.aurora.store.data.PageResult
|
||||
import com.aurora.store.data.model.SearchFilter
|
||||
import com.aurora.store.data.paging.GenericPagingSource.Companion.manualPager
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
@@ -80,7 +81,7 @@ class SearchViewModel @Inject constructor(
|
||||
}.distinctBy { app -> app.packageName }
|
||||
|
||||
manualPager { page ->
|
||||
try {
|
||||
val items = try {
|
||||
when (page) {
|
||||
1 -> contract.searchResults(query)
|
||||
.also { nextBundleUrl = it.streamNextPageUrl }
|
||||
@@ -110,6 +111,7 @@ class SearchViewModel @Inject constructor(
|
||||
Log.e(TAG, "Failed to search results for $query", exception)
|
||||
emptyList()
|
||||
}
|
||||
PageResult(items)
|
||||
}.flow.distinctUntilChanged()
|
||||
.cachedIn(viewModelScope)
|
||||
.onEach { _apps.value = it }
|
||||
|
||||
Reference in New Issue
Block a user