diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/SearchPagingSource.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/SearchPagingSource.kt index 11146005..c0f3988e 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/SearchPagingSource.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/paging/SearchPagingSource.kt @@ -14,6 +14,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.PAGE_SIZE import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.STARTING_PAGE_INDEX +import dev.msfjarvis.claw.api.LobstersSearchApi import dev.msfjarvis.claw.core.injection.IODispatcher import dev.msfjarvis.claw.model.LobstersPost import java.io.IOException @@ -21,15 +22,16 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext /** - * Duplicate of [LobstersPagingSource] with an additional optimization to not continue loading - * further pages if nothing is found in the current one. This is required to prevent the app from - * hammering the search endpoint with up to 70 consecutive requests for the search results of a - * blank query. + * Specialized variant of [LobstersPagingSource] to prevent hammering the Lobsters search endpoint + * with unnecessary requests. Rather than abstract out the API call this paging source takes in the + * relevant parameters to short-circuit when there is no query specified in order to avoid calling + * the API at all. */ class SearchPagingSource @AssistedInject constructor( - @Assisted private val remoteFetcher: RemoteFetcher, + private val searchApi: LobstersSearchApi, + @Assisted private val queryProvider: () -> String, @IODispatcher private val ioDispatcher: CoroutineDispatcher, ) : PagingSource() { override fun getRefreshKey(state: PagingState): Int? { @@ -39,8 +41,14 @@ constructor( } override suspend fun load(params: LoadParams): LoadResult { + val searchQuery = queryProvider() + // If there is no query, we don't need to call the API at all. + if (searchQuery.isEmpty()) { + return LoadResult.Page(itemsBefore = 0, data = emptyList(), prevKey = null, nextKey = null) + } val page = params.key ?: STARTING_PAGE_INDEX - return when (val result = withContext(ioDispatcher) { remoteFetcher.getItemsAtPage(page) }) { + val result = withContext(ioDispatcher) { searchApi.searchPosts(searchQuery, page) } + return when (result) { is ApiResult.Success -> { // Optimization: prevent fetching more pages if we found no items, this means // there is no active search query. @@ -62,6 +70,6 @@ constructor( @AssistedFactory interface Factory { - fun create(remoteFetcher: RemoteFetcher): SearchPagingSource + fun create(queryProvider: () -> String): SearchPagingSource } } diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt index 6d9a57d4..4b6c6d30 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/viewmodel/ClawViewModel.kt @@ -27,7 +27,6 @@ import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.PAGE_SIZ import dev.msfjarvis.claw.android.paging.LobstersPagingSource.Companion.STARTING_PAGE_INDEX import dev.msfjarvis.claw.android.paging.SearchPagingSource import dev.msfjarvis.claw.api.LobstersApi -import dev.msfjarvis.claw.api.LobstersSearchApi import dev.msfjarvis.claw.core.injection.IODispatcher import dev.msfjarvis.claw.core.injection.MainDispatcher import dev.msfjarvis.claw.database.local.SavedPost @@ -57,7 +56,6 @@ class ClawViewModel @Inject constructor( private val api: LobstersApi, - private val searchApi: LobstersSearchApi, private val commentsRepository: CommentsRepository, private val readPostsRepository: ReadPostsRepository, private val savedPostsRepository: SavedPostsRepository, @@ -79,7 +77,7 @@ constructor( } private val searchResultsPager = Pager(PagingConfig(pageSize = PAGE_SIZE), initialKey = STARTING_PAGE_INDEX) { - searchPagingSourceFactory.create { searchApi.searchPosts(searchQuery, it) } + searchPagingSourceFactory.create { searchQuery } } val hottestPosts