From b2d10c17b49d90eb7b088317d9c6b2ae6a7d9616 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Wed, 6 May 2026 04:33:29 +0530 Subject: [PATCH] pager: do not skip next batch if current batch yields no valid apps --- .../java/com/aurora/store/data/PageResult.kt | 11 +++++++++++ .../store/data/paging/GenericPagingSource.kt | 13 +++++++------ .../store/viewmodel/all/InstalledViewModel.kt | 16 ++++++---------- .../viewmodel/browse/StreamBrowseViewModel.kt | 4 +++- .../store/viewmodel/details/ReviewViewModel.kt | 4 +++- .../store/viewmodel/search/SearchViewModel.kt | 4 +++- 6 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/aurora/store/data/PageResult.kt diff --git a/app/src/main/java/com/aurora/store/data/PageResult.kt b/app/src/main/java/com/aurora/store/data/PageResult.kt new file mode 100644 index 000000000..280735b5b --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/PageResult.kt @@ -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( + val items: List, + val hasMore: Boolean = items.isNotEmpty() +) diff --git a/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt b/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt index 42cf27838..768592bb3 100644 --- a/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt +++ b/app/src/main/java/com/aurora/store/data/paging/GenericPagingSource.kt @@ -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( - private val block: suspend (Int) -> List + private val block: suspend (Int) -> PageResult ) : PagingSource() { companion object { @@ -54,7 +55,7 @@ class GenericPagingSource( fun manualPager( pageSize: Int = DEFAULT_PAGE_SIZE, enablePlaceholders: Boolean = true, - data: suspend (Int) -> List + data: suspend (Int) -> PageResult ): Pager = Pager( config = PagingConfig(enablePlaceholders = enablePlaceholders, pageSize = pageSize), pagingSourceFactory = { GenericPagingSource(data) } @@ -65,12 +66,12 @@ class GenericPagingSource( 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) { diff --git a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt index 0a0f7493f..0867e30be 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/all/InstalledViewModel.kt @@ -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(), hasMore = false) + val items = webAppDetailsHelper.getAppDetails(chunk.map { it.packageName }) + PageResult(items, hasMore = page < pagedPackages.size) }.flow.distinctUntilChanged() .cachedIn(viewModelScope) .onEach { _apps.value = it } diff --git a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt index c38526b54..347c1dbb6 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/browse/StreamBrowseViewModel.kt @@ -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 } diff --git a/app/src/main/java/com/aurora/store/viewmodel/details/ReviewViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/details/ReviewViewModel.kt index 8f588bdba..100bb8448 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/details/ReviewViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/details/ReviewViewModel.kt @@ -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 } diff --git a/app/src/main/java/com/aurora/store/viewmodel/search/SearchViewModel.kt b/app/src/main/java/com/aurora/store/viewmodel/search/SearchViewModel.kt index 96c8dfd1e..d39b92ee8 100644 --- a/app/src/main/java/com/aurora/store/viewmodel/search/SearchViewModel.kt +++ b/app/src/main/java/com/aurora/store/viewmodel/search/SearchViewModel.kt @@ -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 }