diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index aac88fa671f1c58045a75cdaa3d332c3e1694884..cf6d4ac2796d40be71605d7e6ffc789ba82c539d 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -30,6 +30,7 @@ import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R +import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories @@ -205,9 +206,36 @@ class FusedAPIImpl @Inject constructor( * @return A list of nullable [FusedApp] */ suspend fun getSearchResults(query: String, authData: AuthData): Pair, ResultStatus> { - val fusedResponse = mutableListOf() + val fusedResponse = ArrayList() + val packageSpecificResults = ArrayList() val status = runCodeBlockWithTimeout({ + + try { + if (preferenceManagerModule.preferredApplicationType() == APP_TYPE_ANY) { + try { + /* + * Surrounding with try-catch because if query is not a package name, + * then GPlay throws an error. + */ + getApplicationDetails(query, query, authData, Origin.GPLAY).let { + if (it.second == ResultStatus.OK) { + packageSpecificResults.add(it.first) + } + } + } catch (_: Exception) {} + } + getCleanapkSearchResult(query).let { + /* Cleanapk always returns something, it is never null. + * If nothing is found, it returns a blank FusedApp() object. + * Blank result to be filtered out. + */ + if (it.isSuccess() && it.data!!.package_name.isNotBlank()) { + packageSpecificResults.add(it.data!!) + } + } + } catch (_: Exception) {} + when (preferenceManagerModule.preferredApplicationType()) { APP_TYPE_ANY -> { fusedResponse.addAll(getCleanAPKSearchResults(query)) @@ -227,7 +255,41 @@ class FusedAPIImpl @Inject constructor( } } }) - return Pair(fusedResponse.distinctBy { it.package_name }, status) + + /* + * The list packageSpecificResults may contain apps with duplicate package names. + * Example, "org.telegram.messenger" will result in "Telegram" app from Play Store + * and "Telegram FOSS" from F-droid. We show both of them at the top. + * + * But for the other keyword related search results, we do not allow duplicate package names. + * We also filter out apps which are already present in packageSpecificResults list. + */ + val filteredResults = fusedResponse.distinctBy { it.package_name } + .filter { packageSpecificResults.isEmpty() || it.package_name != query } + + return Pair(packageSpecificResults + filteredResults, status) + } + + /* + * Method to search cleanapk based on package name. + * This is to be only used for showing an entry in search results list. + * DO NOT use this to show info on ApplicationFragment as it will not have all the required + * information to show for an app. + * + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/2629 + */ + private suspend fun getCleanapkSearchResult(packageName: String): ResultSupreme { + var fusedApp = FusedApp() + val status = runCodeBlockWithTimeout({ + val result = cleanAPKRepository.searchApps( + keyword = packageName, + by = "package_name" + ).body() + if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { + fusedApp = result.apps[0] + } + }) + return ResultSupreme.create(status, fusedApp) } suspend fun getSearchSuggestions(query: String, authData: AuthData): List {