compose: dev: Fix searching for apps by publisher

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2025-06-28 13:48:16 +08:00
parent d353115ae7
commit fe6c62851b
2 changed files with 57 additions and 1 deletions

View File

@@ -65,7 +65,7 @@ fun DevProfileScreen(
) {
val apps = viewModel.apps.collectAsLazyPagingItems()
LaunchedEffect(key1 = Unit) { viewModel.search("pub:$publisherId") }
LaunchedEffect(key1 = Unit) { viewModel.newSearch("pub:$publisherId") }
ScreenContent(
apps = apps,

View File

@@ -24,6 +24,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamCluster
@@ -32,11 +33,15 @@ import com.aurora.gplayapi.helpers.contracts.SearchContract
import com.aurora.gplayapi.helpers.web.WebSearchHelper
import com.aurora.store.AppStreamStash
import com.aurora.store.data.model.ViewState
import com.aurora.store.data.paging.GenericPagingSource.Companion.createPager
import com.aurora.store.data.providers.AuthProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@@ -63,6 +68,57 @@ class SearchResultViewModel @Inject constructor(
private val stashMutex = Mutex()
fun newSearch(query: String) {
var nextBundleUrl: String? = null
val nextStreamUrls = mutableSetOf<String>()
fun Collection<StreamCluster>.flatClusters(): List<App> {
return this.flatMap { streamCluster ->
if (streamCluster.hasNext()) {
nextStreamUrls.add(streamCluster.clusterNextPageUrl)
}
streamCluster.clusterAppList
}.distinctBy { app -> app.packageName }
}
createPager { page ->
try {
when (page) {
1 -> contract.searchResults(query)
.also { nextBundleUrl = it.streamNextPageUrl }
.streamClusters.values
.flatClusters()
else -> {
when {
nextStreamUrls.isNotEmpty() -> {
nextStreamUrls.map { nextPageStreamUrl ->
contract.nextStreamCluster(query, nextPageStreamUrl)
}.also { nextStreamUrls.clear() }.flatClusters()
}
!nextBundleUrl.isNullOrBlank() -> {
contract.nextStreamBundle(query, nextBundleUrl!!)
.also { nextBundleUrl = it.streamNextPageUrl }
.streamClusters.values
.flatClusters()
}
else -> emptyList()
}
emptyList()
}
}
} catch (exception: Exception) {
Log.e(TAG, "Failed to search results for $query", exception)
emptyList()
}
}.flow.distinctUntilChanged()
.cachedIn(viewModelScope)
.onEach { _apps.value = it }
.launchIn(viewModelScope)
}
@Synchronized
fun search(query: String) {
viewModelScope.launch(Dispatchers.IO) {