From 8b1a7d36257db008e5fdd5029d551f72ca20159b Mon Sep 17 00:00:00 2001 From: hasibprince Date: Wed, 30 Nov 2022 13:38:27 +0600 Subject: [PATCH 01/12] show open source app instead of gplay --- .../e/apps/api/fused/FusedAPIImpl.kt | 34 ++++++++- .../e/apps/api/gplay/GPlayAPIImpl.kt | 73 +++++++++++++++++-- .../e/apps/api/gplay/GPlayAPIRepository.kt | 16 ++-- .../e/apps/search/SearchViewModel.kt | 14 +++- .../foundation/e/apps/FusedApiImplTest.kt | 6 +- 5 files changed, 124 insertions(+), 19 deletions(-) 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 35d71d088..84bc8033f 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 @@ -41,6 +41,7 @@ import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.home.Home import foundation.e.apps.api.cleanapk.data.search.Search +import foundation.e.apps.api.fdroid.FdroidApiInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedCategory import foundation.e.apps.api.fused.data.FusedHome @@ -74,6 +75,7 @@ class FusedAPIImpl @Inject constructor( private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, + private val fdroidApiInterface: FdroidApiInterface, @ApplicationContext private val context: Context ) { @@ -1047,7 +1049,7 @@ class FusedAPIImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { @@ -1186,15 +1188,41 @@ class FusedAPIImpl @Inject constructor( query: String, authData: AuthData ): LiveData, Boolean>> { - val searchResults = gPlayAPIRepository.getSearchResults(query, authData) + + suspend fun checkFdroidAppExistance(packageName: String): FusedApp? { + val response = fdroidApiInterface.getFdroidInfoForPackage(packageName) + if (response.isSuccessful) { + val fusedApp = getCleanApkPackageResult(packageName) + fusedApp?.updateSource() + return fusedApp + } + return null + } + + val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::checkFdroidAppExistance) return searchResults.map { + val gplayFusedApps = it.first.map { app -> app.transformToFusedApp() }.toMutableList() + replaceGplayApps(it, gplayFusedApps) + Pair( - it.first.map { app -> app.transformToFusedApp() }, + gplayFusedApps, it.second ) } } + private fun replaceGplayApps( + it: Triple, Boolean, List>, + gplayFusedApps: MutableList + ) { + it.third.forEach { fdroidApp -> + val indexOfFdroidApp = gplayFusedApps.indexOf(gplayFusedApps.find { foundFusedApp -> + foundFusedApp.package_name == fdroidApp.package_name + }) + gplayFusedApps[indexOfFdroidApp] = fdroidApp + } + } + /* * Home screen-related internal functions */ diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt index 66f7ec934..c4717c5f8 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt @@ -19,6 +19,7 @@ package foundation.e.apps.api.gplay import androidx.lifecycle.LiveData +import androidx.lifecycle.LiveDataScope import androidx.lifecycle.liveData import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App @@ -35,11 +36,14 @@ import com.aurora.gplayapi.helpers.PurchaseHelper import com.aurora.gplayapi.helpers.SearchHelper import com.aurora.gplayapi.helpers.StreamHelper import com.aurora.gplayapi.helpers.TopChartsHelper +import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.gplay.utils.GPlayHttpClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext +import timber.log.Timber import javax.inject.Inject +import kotlin.math.absoluteValue class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpClient) { @@ -56,7 +60,11 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli * Sends livedata of list of apps being loaded from search and a boolean * signifying if more data is to be loaded. */ - fun getSearchResults(query: String, authData: AuthData): LiveData, Boolean>> { + fun getSearchResults( + query: String, + authData: AuthData, + checkFdroidAppExistance: suspend (String) -> FusedApp? + ): LiveData, Boolean, List>> { /* * Send livedata to improve UI performance, so we don't have to wait for loading all results. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 @@ -70,7 +78,13 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli val searchHelper = SearchHelper(authData).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) - emit(Pair(searchBundle.appList, true)) + detectAvailableAppsInFdroid( + searchBundle, + checkFdroidAppExistance, + this@liveData, + searchBundle, + true + ) var nextSubBundleSet: MutableSet do { @@ -80,8 +94,13 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli searchBundle.apply { subBundles.clear() subBundles.addAll(newSearchBundle.subBundles) - appList.addAll(newSearchBundle.appList) - emit(Pair(searchBundle.appList, nextSubBundleSet.isNotEmpty())) + detectAvailableAppsInFdroid( + newSearchBundle, + checkFdroidAppExistance, + this@liveData, + this, + nextSubBundleSet.isNotEmpty() + ) } } } while (nextSubBundleSet.isNotEmpty()) @@ -89,6 +108,43 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli } } + private suspend fun detectAvailableAppsInFdroid( + newSearchBundle: SearchBundle, + checkFdroidAppExistance: suspend (String) -> FusedApp?, + liveDataScope: LiveDataScope, Boolean, List>>, + searchBundle: SearchBundle, + shouldShowLoader: Boolean + ) { + val range = 3 + var startIndex = 0 + val appListSize = newSearchBundle.appList.size + var lastIndex = if (appListSize < range) appListSize - 1 else range - 1 + + while (lastIndex < appListSize) { + val fdroidApps = mutableListOf() + for (i in startIndex..lastIndex) { + val app = newSearchBundle.appList[i] + val fdroidApp = checkFdroidAppExistance(app.packageName) + fdroidApp?.let { + fdroidApps.add(it) + } + + if (newSearchBundle != searchBundle) { + searchBundle.appList.add(app) + } + } + + liveDataScope.emit(Triple(searchBundle.appList, shouldShowLoader, fdroidApps)) + + val itemsLeft = ((appListSize - 1) - lastIndex) + if (itemsLeft < 1) { + return + } + startIndex += range + lastIndex += if (itemsLeft > range) range else itemsLeft + } + } + suspend fun getDownloadInfo( packageName: String, versionCode: Int, @@ -113,7 +169,14 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli val downloadData = mutableListOf() withContext(Dispatchers.IO) { val purchaseHelper = PurchaseHelper(authData).using(gPlayHttpClient) - downloadData.addAll(purchaseHelper.getOnDemandModule(packageName, moduleName, versionCode, offerType)) + downloadData.addAll( + purchaseHelper.getOnDemandModule( + packageName, + moduleName, + versionCode, + offerType + ) + ) } return downloadData } diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt index f8c735a7d..53e0de345 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt @@ -20,13 +20,9 @@ package foundation.e.apps.api.gplay import androidx.lifecycle.LiveData import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.Category -import com.aurora.gplayapi.data.models.File -import com.aurora.gplayapi.data.models.StreamBundle -import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.data.models.* import com.aurora.gplayapi.helpers.TopChartsHelper +import foundation.e.apps.api.fused.data.FusedApp import javax.inject.Inject class GPlayAPIRepository @Inject constructor(private val gPlayAPIImpl: GPlayAPIImpl) { @@ -35,8 +31,12 @@ class GPlayAPIRepository @Inject constructor(private val gPlayAPIImpl: GPlayAPII return gPlayAPIImpl.getSearchSuggestions(query, authData) } - fun getSearchResults(query: String, authData: AuthData): LiveData, Boolean>> { - return gPlayAPIImpl.getSearchResults(query, authData) + fun getSearchResults( + query: String, + authData: AuthData, + checkFdroidAppExistance: suspend (String) -> FusedApp? + ): LiveData, Boolean, List>> { + return gPlayAPIImpl.getSearchResults(query, authData, checkFdroidAppExistance) } suspend fun getOnDemandModule( diff --git a/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt b/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt index aa0f9697e..deab32583 100644 --- a/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt +++ b/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt @@ -19,6 +19,7 @@ package foundation.e.apps.search import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.SearchSuggestEntry @@ -43,11 +44,18 @@ class SearchViewModel @Inject constructor( val searchSuggest: MutableLiveData?> = MutableLiveData() val searchResult: MutableLiveData, Boolean>>> = MutableLiveData() + private var searchResultLiveData: LiveData, Boolean>>> = + MutableLiveData() fun getSearchSuggestions(query: String, gPlayAuth: AuthObject.GPlayAuth) { viewModelScope.launch(Dispatchers.IO) { if (gPlayAuth.result.isSuccess()) - searchSuggest.postValue(fusedAPIRepository.getSearchSuggestions(query, gPlayAuth.result.data!!)) + searchSuggest.postValue( + fusedAPIRepository.getSearchSuggestions( + query, + gPlayAuth.result.data!! + ) + ) } } @@ -82,7 +90,9 @@ class SearchViewModel @Inject constructor( */ fun getSearchResults(query: String, authData: AuthData, lifecycleOwner: LifecycleOwner) { viewModelScope.launch(Dispatchers.Main) { - fusedAPIRepository.getSearchResults(query, authData).observe(lifecycleOwner) { + searchResultLiveData.removeObservers(lifecycleOwner) + searchResultLiveData = fusedAPIRepository.getSearchResults(query, authData) + searchResultLiveData.observe(lifecycleOwner) { searchResult.postValue(it) if (!it.isSuccess()) { diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index ac6c7281d..ef380130d 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -811,7 +811,11 @@ class FusedApiImplTest { source = CleanAPKInterface.APP_SOURCE_ANY ) ).thenReturn(packageNameSearchResponse) - Mockito.`when`(gPlayAPIRepository.getSearchResults(eq("com.search.package"), eq(authData))) + Mockito.`when`(gPlayAPIRepository.getSearchResults( + eq("com.search.package"), + eq(authData), + ::checkFdroidAppExistance + )) .thenReturn(gplayLivedata) } -- GitLab From a21d0d355e2422d9a3736a955161a824984514b1 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Thu, 1 Dec 2022 21:45:04 +0600 Subject: [PATCH 02/12] warning message added in app detail page --- .../e/apps/api/fused/FusedAPIImpl.kt | 15 ++++++---- .../e/apps/api/fused/FusedAPIRepository.kt | 2 ++ .../e/apps/api/fused/data/FusedApp.kt | 3 +- .../e/apps/api/gplay/GPlayAPIImpl.kt | 5 ++-- .../e/apps/api/gplay/GPlayAPIRepository.kt | 7 ++++- .../e/apps/application/ApplicationFragment.kt | 18 +++++++++-- .../apps/application/ApplicationViewModel.kt | 2 ++ .../applicationlist/ApplicationDiffUtil.kt | 6 +++- .../ApplicationListRVAdapter.kt | 1 + .../main/res/drawable/ic_warning_black.xml | 10 +++++++ .../main/res/layout/fragment_application.xml | 30 +++++++++++++++++++ .../res/navigation/navigation_resource.xml | 4 +++ app/src/main/res/values/strings.xml | 4 +++ .../foundation/e/apps/FusedApiImplTest.kt | 12 ++++---- 14 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 app/src/main/res/drawable/ic_warning_black.xml 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 84bc8033f..2b8e273e2 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 @@ -1049,7 +1049,7 @@ class FusedAPIImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { @@ -1189,11 +1189,12 @@ class FusedAPIImpl @Inject constructor( authData: AuthData ): LiveData, Boolean>> { - suspend fun checkFdroidAppExistance(packageName: String): FusedApp? { + suspend fun checkFdroidAppExistance(packageName: String): FusedApp? { val response = fdroidApiInterface.getFdroidInfoForPackage(packageName) if (response.isSuccessful) { val fusedApp = getCleanApkPackageResult(packageName) fusedApp?.updateSource() + fusedApp?.isGplayReplaced = true return fusedApp } return null @@ -1216,9 +1217,11 @@ class FusedAPIImpl @Inject constructor( gplayFusedApps: MutableList ) { it.third.forEach { fdroidApp -> - val indexOfFdroidApp = gplayFusedApps.indexOf(gplayFusedApps.find { foundFusedApp -> - foundFusedApp.package_name == fdroidApp.package_name - }) + val indexOfFdroidApp = gplayFusedApps.indexOf( + gplayFusedApps.find { foundFusedApp -> + foundFusedApp.package_name == fdroidApp.package_name + } + ) gplayFusedApps[indexOfFdroidApp] = fdroidApp } } @@ -1499,4 +1502,6 @@ class FusedAPIImpl @Inject constructor( } return false } + + fun isOpenSourceSelected() = preferenceManagerModule.isOpenSourceSelected() } diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt index 270f65a9e..28000e635 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt @@ -476,4 +476,6 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII hasNextStreamCluster = false clusterPointer = 0 } + + fun isOpenSourceSelected() = fusedAPIImpl.isOpenSourceSelected() } diff --git a/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt b/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt index a8cf9cac2..4a12816f5 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/data/FusedApp.kt @@ -90,5 +90,6 @@ data class FusedApp( * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720 */ - var filterLevel: FilterLevel = FilterLevel.UNKNOWN + var filterLevel: FilterLevel = FilterLevel.UNKNOWN, + var isGplayReplaced: Boolean = false ) diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt index c4717c5f8..cf595e7b9 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt @@ -41,9 +41,7 @@ import foundation.e.apps.api.gplay.utils.GPlayHttpClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext -import timber.log.Timber import javax.inject.Inject -import kotlin.math.absoluteValue class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpClient) { @@ -116,8 +114,8 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli shouldShowLoader: Boolean ) { val range = 3 - var startIndex = 0 val appListSize = newSearchBundle.appList.size + var startIndex = 0 var lastIndex = if (appListSize < range) appListSize - 1 else range - 1 while (lastIndex < appListSize) { @@ -140,6 +138,7 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli if (itemsLeft < 1) { return } + startIndex += range lastIndex += if (itemsLeft > range) range else itemsLeft } diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt index 53e0de345..f9bfc3f4f 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt @@ -20,7 +20,12 @@ package foundation.e.apps.api.gplay import androidx.lifecycle.LiveData import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.* +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.Category +import com.aurora.gplayapi.data.models.File +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.helpers.TopChartsHelper import foundation.e.apps.api.fused.data.FusedApp import javax.inject.Inject diff --git a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt index bd4414dd6..62d3a62f6 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt @@ -205,9 +205,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { // Privacy widgets updatePrivacyPanel() - if (appInfoFetchViewModel.isAppInBlockedList(it)) { - binding.snackbarLayout.visibility = View.VISIBLE - } + showWarningMessage(it) fetchAppTracker(it) observeDownloadList() @@ -215,6 +213,20 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { stopLoadingUI() } + private fun showWarningMessage(it: FusedApp) { + if (appInfoFetchViewModel.isAppInBlockedList(it)) { + binding.snackbarLayout.visibility = View.VISIBLE + } else if (args.isGplayReplaced && !applicationViewModel.isOpenSourceSelected()) { + binding.duplicateAppCardview.visibility = View.VISIBLE + binding.duplicateAppCardview.setOnClickListener { + ApplicationDialogFragment( + title = getString(R.string.open_source_apps), + message = getString(R.string.duplicate_app_from_sources) + ).show(childFragmentManager, TAG) + } + } + } + private fun observeDownloadList() { mainActivityViewModel.downloadList.removeObservers(viewLifecycleOwner) mainActivityViewModel.downloadList.observe(viewLifecycleOwner) { list -> diff --git a/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt index 6366fdb28..d4e9b43c0 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationViewModel.kt @@ -181,4 +181,6 @@ class ApplicationViewModel @Inject constructor( ?: fusedAPIRepository.getFusedAppInstallationStatus(app) } } + + fun isOpenSourceSelected() = fusedAPIRepository.isOpenSourceSelected() } diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt index e1c2c3a65..987d0818e 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt @@ -19,6 +19,7 @@ package foundation.e.apps.applicationlist import androidx.recyclerview.widget.DiffUtil import foundation.e.apps.api.fused.data.FusedApp +import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL class ApplicationDiffUtil : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: FusedApp, newItem: FusedApp): Boolean { @@ -47,7 +48,10 @@ class ApplicationDiffUtil : DiffUtil.ItemCallback() { oldItem.shareUrl.contentEquals(newItem.shareUrl) && oldItem.source.contentEquals(newItem.source) && oldItem.status == newItem.status && - oldItem.trackers == newItem.trackers && + ( + (oldItem.trackers == LIST_OF_NULL && newItem.trackers.isEmpty()) || + oldItem.trackers == newItem.trackers + ) && oldItem.url.contentEquals(newItem.url) && oldItem.isFree == newItem.isFree && oldItem.is_pwa == newItem.is_pwa diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt index 786571b00..f056b13ac 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt @@ -218,6 +218,7 @@ class ApplicationListRVAdapter( searchApp.package_name, searchApp.origin, catText, + searchApp.isGplayReplaced ) } R.id.updatesFragment -> { diff --git a/app/src/main/res/drawable/ic_warning_black.xml b/app/src/main/res/drawable/ic_warning_black.xml new file mode 100644 index 000000000..39883ee9e --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_black.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_application.xml b/app/src/main/res/layout/fragment_application.xml index 7b4af2745..62958a2a3 100644 --- a/app/src/main/res/layout/fragment_application.xml +++ b/app/src/main/res/layout/fragment_application.xml @@ -89,6 +89,36 @@ + + + + + + + + + diff --git a/app/src/main/res/navigation/navigation_resource.xml b/app/src/main/res/navigation/navigation_resource.xml index 1c7d6c290..d15437ba1 100644 --- a/app/src/main/res/navigation/navigation_resource.xml +++ b/app/src/main/res/navigation/navigation_resource.xml @@ -109,6 +109,10 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 44b074070..1deed041e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -113,6 +113,10 @@ Something went wrong! Show more Cannot show Google Play app when only open source apps are allowed. + Why am I seeing the Open Source version? + Open Source apps + Some proprietary apps may also have an Open Source version. Whenever this happens App Lounge shows the Open Source version only, in order to avoid duplicates. + diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index ef380130d..242d7b0bd 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -811,11 +811,13 @@ class FusedApiImplTest { source = CleanAPKInterface.APP_SOURCE_ANY ) ).thenReturn(packageNameSearchResponse) - Mockito.`when`(gPlayAPIRepository.getSearchResults( - eq("com.search.package"), - eq(authData), - ::checkFdroidAppExistance - )) + Mockito.`when`( + gPlayAPIRepository.getSearchResults( + eq("com.search.package"), + eq(authData), + ::checkFdroidAppExistance + ) + ) .thenReturn(gplayLivedata) } -- GitLab From d3564690de3794193870f7a13d3d513cd8edce1a Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 2 Dec 2022 08:40:31 +0600 Subject: [PATCH 03/12] Fdroid web api call intoroduced --- .../e/apps/api/cleanapk/RetrofitModule.kt | 13 +++++++++++++ .../e/apps/api/fdroid/FdroidWebInterface.kt | 15 +++++++++++++++ .../foundation/e/apps/api/fused/FusedAPIImpl.kt | 7 ++++--- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt index 911f4affa..b03baa0b3 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt @@ -34,6 +34,7 @@ import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.ecloud.EcloudApiInterface import foundation.e.apps.api.exodus.ExodusTrackerApi import foundation.e.apps.api.fdroid.FdroidApiInterface +import foundation.e.apps.api.fdroid.FdroidWebInterface import okhttp3.Cache import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -117,6 +118,18 @@ object RetrofitModule { .create(FdroidApiInterface::class.java) } + @Singleton + @Provides + fun provideFdroidWebApi( + okHttpClient: OkHttpClient, + ): FdroidWebInterface { + return Retrofit.Builder() + .baseUrl(FdroidWebInterface.BASE_URL) + .client(okHttpClient) + .build() + .create(FdroidWebInterface::class.java) + } + @Singleton @Provides fun provideEcloudApi(okHttpClient: OkHttpClient, moshi: Moshi): EcloudApiInterface { diff --git a/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt new file mode 100644 index 000000000..c5b978199 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt @@ -0,0 +1,15 @@ +package foundation.e.apps.api.fdroid + +import okhttp3.ResponseBody +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Path + +interface FdroidWebInterface { + companion object { + const val BASE_URL = "https://f-droid.org/fr/packages/" + } + + @GET("https://f-droid.org/fr/packages/{packageName}") + suspend fun getFdroidApp(@Path("packageName") packageName: String): Response +} 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 2b8e273e2..9b936e106 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 @@ -41,7 +41,7 @@ import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.home.Home import foundation.e.apps.api.cleanapk.data.search.Search -import foundation.e.apps.api.fdroid.FdroidApiInterface +import foundation.e.apps.api.fdroid.FdroidWebInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedCategory import foundation.e.apps.api.fused.data.FusedHome @@ -75,7 +75,7 @@ class FusedAPIImpl @Inject constructor( private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, - private val fdroidApiInterface: FdroidApiInterface, + private val fdroidWebInterface: FdroidWebInterface, @ApplicationContext private val context: Context ) { @@ -1190,13 +1190,14 @@ class FusedAPIImpl @Inject constructor( ): LiveData, Boolean>> { suspend fun checkFdroidAppExistance(packageName: String): FusedApp? { - val response = fdroidApiInterface.getFdroidInfoForPackage(packageName) + val response = fdroidWebInterface.getFdroidApp(packageName) if (response.isSuccessful) { val fusedApp = getCleanApkPackageResult(packageName) fusedApp?.updateSource() fusedApp?.isGplayReplaced = true return fusedApp } + return null } -- GitLab From 07a5d8175c2f0326832c8bb7a4de65e8485b8622 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 12:59:58 +0530 Subject: [PATCH 04/12] [WIP] improve replacing and apps in GPlayAPIImpl --- .../e/apps/api/gplay/GPlayAPIImpl.kt | 97 +++++++++---------- .../e/apps/api/gplay/GPlayAPIRepository.kt | 6 +- 2 files changed, 48 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt index cf595e7b9..8344a2a70 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt @@ -61,8 +61,8 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli fun getSearchResults( query: String, authData: AuthData, - checkFdroidAppExistance: suspend (String) -> FusedApp? - ): LiveData, Boolean, List>> { + replaceWithFDroid: suspend (App) -> FusedApp, + ): LiveData, Boolean>> { /* * Send livedata to improve UI performance, so we don't have to wait for loading all results. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 @@ -76,13 +76,40 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli val searchHelper = SearchHelper(authData).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) - detectAvailableAppsInFdroid( - searchBundle, - checkFdroidAppExistance, - this@liveData, - searchBundle, - true - ) + val initialReplacedList = mutableListOf() + val INITIAL_LIMIT = 4 + + suspend fun emitReplacedList(searchBundle: SearchBundle, moreToEmit: Boolean) { + searchBundle.appList.forEach { + val replacedApp = replaceWithFDroid(it) + when { + initialReplacedList.size < INITIAL_LIMIT - 1 -> { + /* + * If initial limit is 4, add apps to list (without emitting) + * till 2 apps. + */ + initialReplacedList.add(replacedApp) + } + initialReplacedList.size == INITIAL_LIMIT - 1 -> { + /* + * If initial limit is 4, and we have reached till 3 apps, + * add the 4th app and emit the list. + */ + initialReplacedList.add(replacedApp) + emit(Pair(initialReplacedList, moreToEmit)) + } + initialReplacedList.size == INITIAL_LIMIT -> { + /* + * If initial limit is 4, and we have emitted 4 apps, + * for all rest of the apps, emit each app one by one. + */ + emit(Pair(listOf(replacedApp), moreToEmit)) + } + } + } + } + + emitReplacedList(searchBundle, true) var nextSubBundleSet: MutableSet do { @@ -92,55 +119,21 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli searchBundle.apply { subBundles.clear() subBundles.addAll(newSearchBundle.subBundles) - detectAvailableAppsInFdroid( - newSearchBundle, - checkFdroidAppExistance, - this@liveData, - this, - nextSubBundleSet.isNotEmpty() - ) + appList.addAll(newSearchBundle.appList) + emitReplacedList(searchBundle, nextSubBundleSet.isNotEmpty()) } } } while (nextSubBundleSet.isNotEmpty()) - } - } - } - private suspend fun detectAvailableAppsInFdroid( - newSearchBundle: SearchBundle, - checkFdroidAppExistance: suspend (String) -> FusedApp?, - liveDataScope: LiveDataScope, Boolean, List>>, - searchBundle: SearchBundle, - shouldShowLoader: Boolean - ) { - val range = 3 - val appListSize = newSearchBundle.appList.size - var startIndex = 0 - var lastIndex = if (appListSize < range) appListSize - 1 else range - 1 - - while (lastIndex < appListSize) { - val fdroidApps = mutableListOf() - for (i in startIndex..lastIndex) { - val app = newSearchBundle.appList[i] - val fdroidApp = checkFdroidAppExistance(app.packageName) - fdroidApp?.let { - fdroidApps.add(it) - } - - if (newSearchBundle != searchBundle) { - searchBundle.appList.add(app) + /* + * If initialReplacedList size is less than INITIAL_LIMIT, + * it means the results were very less and nothing has been emitted so far. + * Hence emit the list. + */ + if (initialReplacedList.size < INITIAL_LIMIT) { + emit(Pair(initialReplacedList, false)) } } - - liveDataScope.emit(Triple(searchBundle.appList, shouldShowLoader, fdroidApps)) - - val itemsLeft = ((appListSize - 1) - lastIndex) - if (itemsLeft < 1) { - return - } - - startIndex += range - lastIndex += if (itemsLeft > range) range else itemsLeft } } diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt index f9bfc3f4f..4475cb03a 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIRepository.kt @@ -39,9 +39,9 @@ class GPlayAPIRepository @Inject constructor(private val gPlayAPIImpl: GPlayAPII fun getSearchResults( query: String, authData: AuthData, - checkFdroidAppExistance: suspend (String) -> FusedApp? - ): LiveData, Boolean, List>> { - return gPlayAPIImpl.getSearchResults(query, authData, checkFdroidAppExistance) + replaceWithFDroid: suspend (App) -> FusedApp, + ): LiveData, Boolean>> { + return gPlayAPIImpl.getSearchResults(query, authData, replaceWithFDroid) } suspend fun getOnDemandModule( -- GitLab From c9a9f62df668f9ea4465699b3e39485a00b5f142 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 13:01:17 +0530 Subject: [PATCH 05/12] update FusedAPIImpl to remove unneeded code. --- .../e/apps/api/fused/FusedAPIImpl.kt | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) 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 9b936e106..97d31ee9f 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 @@ -1189,44 +1189,33 @@ class FusedAPIImpl @Inject constructor( authData: AuthData ): LiveData, Boolean>> { - suspend fun checkFdroidAppExistance(packageName: String): FusedApp? { - val response = fdroidWebInterface.getFdroidApp(packageName) + /* + * This function will replace a GPlay app with F-Droid app if exists, + * else will show the GPlay app itself. + */ + suspend fun replaceWithFDroid(gPlayApp: App): FusedApp { + val gPlayFusedApp = gPlayApp.transformToFusedApp() + val response = fdroidWebInterface.getFdroidApp(gPlayFusedApp.package_name) if (response.isSuccessful) { - val fusedApp = getCleanApkPackageResult(packageName) - fusedApp?.updateSource() - fusedApp?.isGplayReplaced = true - return fusedApp + val fdroidApp = getCleanApkPackageResult(gPlayFusedApp.package_name)?.apply { + updateSource() + isGplayReplaced = true + } + return fdroidApp ?: gPlayFusedApp } - return null + return gPlayFusedApp } - val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::checkFdroidAppExistance) + val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { - val gplayFusedApps = it.first.map { app -> app.transformToFusedApp() }.toMutableList() - replaceGplayApps(it, gplayFusedApps) - Pair( - gplayFusedApps, + it.first, it.second ) } } - private fun replaceGplayApps( - it: Triple, Boolean, List>, - gplayFusedApps: MutableList - ) { - it.third.forEach { fdroidApp -> - val indexOfFdroidApp = gplayFusedApps.indexOf( - gplayFusedApps.find { foundFusedApp -> - foundFusedApp.package_name == fdroidApp.package_name - } - ) - gplayFusedApps[indexOfFdroidApp] = fdroidApp - } - } - /* * Home screen-related internal functions */ -- GitLab From 4c8f273f437b201f39ce3c811cf002bcb6cce26e Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 13:18:22 +0530 Subject: [PATCH 06/12] prevent unnecessary accumulation in search bundle --- app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt index 8344a2a70..3381992fa 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt @@ -119,8 +119,7 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli searchBundle.apply { subBundles.clear() subBundles.addAll(newSearchBundle.subBundles) - appList.addAll(newSearchBundle.appList) - emitReplacedList(searchBundle, nextSubBundleSet.isNotEmpty()) + emitReplacedList(newSearchBundle, nextSubBundleSet.isNotEmpty()) } } } while (nextSubBundleSet.isNotEmpty()) -- GitLab From 03d08bc8f5672acc6ee514b33566d84bc3efb349 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 13:23:11 +0530 Subject: [PATCH 07/12] update test? --- app/src/test/java/foundation/e/apps/FusedApiImplTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index 242d7b0bd..7a2d614ee 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -815,7 +815,7 @@ class FusedApiImplTest { gPlayAPIRepository.getSearchResults( eq("com.search.package"), eq(authData), - ::checkFdroidAppExistance + ::replaceWithFDroid ) ) .thenReturn(gplayLivedata) -- GitLab From 2ceddb30f7e2181a5cb7f63338b1218f4335b4cc Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 2 Dec 2022 20:26:12 +0600 Subject: [PATCH 08/12] fixed: syntax error of FusedApiImplTest --- .../foundation/e/apps/FusedApiImplTest.kt | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index 7a2d614ee..646b84fad 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -20,6 +20,7 @@ package foundation.e.apps import android.content.Context import android.text.format.Formatter import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.App @@ -29,6 +30,7 @@ import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search +import foundation.e.apps.api.fdroid.FdroidWebInterface import foundation.e.apps.api.fused.FusedAPIImpl import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedHome @@ -88,6 +90,9 @@ class FusedApiImplTest { @Mock private lateinit var gPlayAPIRepository: GPlayAPIRepository + @Mock + private lateinit var fdroidWebInterface: FdroidWebInterface + private lateinit var preferenceManagerModule: FakePreferenceModule private lateinit var formatterMocked: MockedStatic @@ -107,6 +112,7 @@ class FusedApiImplTest { pkgManagerModule, pwaManagerModule, preferenceManagerModule, + fdroidWebInterface, context ) } @@ -759,9 +765,9 @@ class FusedApiImplTest { preferenceManagerModule.isPWASelectedFake = true preferenceManagerModule.isOpenSourceelectedFake = true preferenceManagerModule.isGplaySelectedFake = true - val gplayLivedata = MutableLiveData( + val gplayLivedata: LiveData, Boolean>> = MutableLiveData( Pair( - listOf(App("a.b.c"), App("c.d.e"), App("d.e.f"), App("d.e.g")), false + listOf(FusedApp("a.b.c"), FusedApp("c.d.e"), FusedApp("d.e.f"), FusedApp("d.e.g")), false ) ) @@ -780,7 +786,7 @@ class FusedApiImplTest { packageNameSearchResponse: Response?, authData: AuthData, gplayPackageResult: App, - gplayLivedata: MutableLiveData, Boolean>>, + gplayLivedata: LiveData, Boolean>>?, willThrowException: Boolean = false ) { Mockito.`when`(pwaManagerModule.getPwaStatus(any())).thenReturn(Status.UNAVAILABLE) @@ -811,11 +817,16 @@ class FusedApiImplTest { source = CleanAPKInterface.APP_SOURCE_ANY ) ).thenReturn(packageNameSearchResponse) + + suspend fun replaceWithFDroid(gPlayApp: App): FusedApp { + return FusedApp(gPlayApp.id.toString(), gPlayApp.packageName) + } + Mockito.`when`( gPlayAPIRepository.getSearchResults( eq("com.search.package"), eq(authData), - ::replaceWithFDroid + eq(::replaceWithFDroid) ) ) .thenReturn(gplayLivedata) @@ -852,7 +863,7 @@ class FusedApiImplTest { val gplayPackageResult = App("com.search.package") val gplayLivedata = - MutableLiveData(Pair(listOf(App("a.b.c"), App("c.d.e"), App("d.e.f")), false)) + MutableLiveData(Pair(listOf(FusedApp("a.b.c"), FusedApp("c.d.e"), FusedApp("d.e.f")), false)) setupMockingSearchApp( packageNameSearchResponse, AUTH_DATA, gplayPackageResult, gplayLivedata, true -- GitLab From 98c76e70f8c7364220194b1b3823572ece5b8215 Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 20:35:06 +0530 Subject: [PATCH 09/12] move emitReplacedList to class hierarchy. --- .../e/apps/api/gplay/GPlayAPIImpl.kt | 85 ++++++++++++------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt index 3381992fa..f68b6680e 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GPlayAPIImpl.kt @@ -79,37 +79,14 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli val initialReplacedList = mutableListOf() val INITIAL_LIMIT = 4 - suspend fun emitReplacedList(searchBundle: SearchBundle, moreToEmit: Boolean) { - searchBundle.appList.forEach { - val replacedApp = replaceWithFDroid(it) - when { - initialReplacedList.size < INITIAL_LIMIT - 1 -> { - /* - * If initial limit is 4, add apps to list (without emitting) - * till 2 apps. - */ - initialReplacedList.add(replacedApp) - } - initialReplacedList.size == INITIAL_LIMIT - 1 -> { - /* - * If initial limit is 4, and we have reached till 3 apps, - * add the 4th app and emit the list. - */ - initialReplacedList.add(replacedApp) - emit(Pair(initialReplacedList, moreToEmit)) - } - initialReplacedList.size == INITIAL_LIMIT -> { - /* - * If initial limit is 4, and we have emitted 4 apps, - * for all rest of the apps, emit each app one by one. - */ - emit(Pair(listOf(replacedApp), moreToEmit)) - } - } - } - } - - emitReplacedList(searchBundle, true) + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + replaceWithFDroid, + searchBundle, + true, + ) var nextSubBundleSet: MutableSet do { @@ -119,7 +96,14 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli searchBundle.apply { subBundles.clear() subBundles.addAll(newSearchBundle.subBundles) - emitReplacedList(newSearchBundle, nextSubBundleSet.isNotEmpty()) + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + replaceWithFDroid, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) } } } while (nextSubBundleSet.isNotEmpty()) @@ -136,6 +120,43 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli } } + private suspend fun emitReplacedList( + scope: LiveDataScope, Boolean>>, + accumulationList: MutableList, + accumulationLimit: Int, + replaceFunction: suspend (App) -> FusedApp, + searchBundle: SearchBundle, + moreToEmit: Boolean, + ) { + searchBundle.appList.forEach { + val replacedApp = replaceFunction(it) + when { + accumulationList.size < accumulationLimit - 1 -> { + /* + * If initial limit is 4, add apps to list (without emitting) + * till 2 apps. + */ + accumulationList.add(replacedApp) + } + accumulationList.size == accumulationLimit - 1 -> { + /* + * If initial limit is 4, and we have reached till 3 apps, + * add the 4th app and emit the list. + */ + accumulationList.add(replacedApp) + scope.emit(Pair(accumulationList, moreToEmit)) + } + accumulationList.size == accumulationLimit -> { + /* + * If initial limit is 4, and we have emitted 4 apps, + * for all rest of the apps, emit each app one by one. + */ + scope.emit(Pair(listOf(replacedApp), moreToEmit)) + } + } + } + } + suspend fun getDownloadInfo( packageName: String, versionCode: Int, -- GitLab From 196e83c4c6ce099b3a3b278bcc458d19d3d9a668 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 2 Dec 2022 21:25:35 +0600 Subject: [PATCH 10/12] moved checkFdroidExistance to class hiererchy fixed: usage of base url in fdroidwebapi --- .../e/apps/api/fdroid/FdroidWebInterface.kt | 2 +- .../e/apps/api/fused/FusedAPIImpl.kt | 37 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt index c5b978199..2281becd5 100644 --- a/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt +++ b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt @@ -10,6 +10,6 @@ interface FdroidWebInterface { const val BASE_URL = "https://f-droid.org/fr/packages/" } - @GET("https://f-droid.org/fr/packages/{packageName}") + @GET("{packageName}") suspend fun getFdroidApp(@Path("packageName") packageName: String): Response } 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 97d31ee9f..9657199e1 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 @@ -1188,25 +1188,6 @@ class FusedAPIImpl @Inject constructor( query: String, authData: AuthData ): LiveData, Boolean>> { - - /* - * This function will replace a GPlay app with F-Droid app if exists, - * else will show the GPlay app itself. - */ - suspend fun replaceWithFDroid(gPlayApp: App): FusedApp { - val gPlayFusedApp = gPlayApp.transformToFusedApp() - val response = fdroidWebInterface.getFdroidApp(gPlayFusedApp.package_name) - if (response.isSuccessful) { - val fdroidApp = getCleanApkPackageResult(gPlayFusedApp.package_name)?.apply { - updateSource() - isGplayReplaced = true - } - return fdroidApp ?: gPlayFusedApp - } - - return gPlayFusedApp - } - val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { Pair( @@ -1216,6 +1197,24 @@ class FusedAPIImpl @Inject constructor( } } + /* + * This function will replace a GPlay app with F-Droid app if exists, + * else will show the GPlay app itself. + */ + private suspend fun replaceWithFDroid(gPlayApp: App): FusedApp { + val gPlayFusedApp = gPlayApp.transformToFusedApp() + val response = fdroidWebInterface.getFdroidApp(gPlayFusedApp.package_name) + if (response.isSuccessful) { + val fdroidApp = getCleanApkPackageResult(gPlayFusedApp.package_name)?.apply { + updateSource() + isGplayReplaced = true + } + return fdroidApp ?: gPlayFusedApp + } + + return gPlayFusedApp + } + /* * Home screen-related internal functions */ -- GitLab From a31cf245fb3eb1b63baa5a5dba51db7abf91e5a6 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 2 Dec 2022 21:27:41 +0600 Subject: [PATCH 11/12] fixed indentation of ApplicationDiffUtil --- .../applicationlist/ApplicationDiffUtil.kt | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt index 987d0818e..583c38d44 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationDiffUtil.kt @@ -28,32 +28,29 @@ class ApplicationDiffUtil : DiffUtil.ItemCallback() { override fun areContentsTheSame(oldItem: FusedApp, newItem: FusedApp): Boolean { return oldItem._id == newItem._id && - oldItem.appSize.contentEquals(newItem.appSize) && - oldItem.author.contentEquals(newItem.author) && - oldItem.category.contentEquals(newItem.category) && - oldItem.description.contentEquals(newItem.description) && - oldItem.icon_image_path.contentEquals(newItem.icon_image_path) && - oldItem.last_modified.contentEquals(newItem.last_modified) && - oldItem.latest_version_code == newItem.latest_version_code && - oldItem.latest_version_number.contentEquals(newItem.latest_version_number) && - oldItem.licence.contentEquals(newItem.licence) && - oldItem.appSize.contentEquals(newItem.appSize) && - oldItem.name.contentEquals(newItem.name) && - oldItem.offer_type == newItem.offer_type && - oldItem.origin == newItem.origin && - oldItem.other_images_path == newItem.other_images_path && - oldItem.package_name.contentEquals(newItem.package_name) && - oldItem.perms == newItem.perms && - oldItem.ratings == newItem.ratings && - oldItem.shareUrl.contentEquals(newItem.shareUrl) && - oldItem.source.contentEquals(newItem.source) && - oldItem.status == newItem.status && - ( - (oldItem.trackers == LIST_OF_NULL && newItem.trackers.isEmpty()) || - oldItem.trackers == newItem.trackers - ) && - oldItem.url.contentEquals(newItem.url) && - oldItem.isFree == newItem.isFree && - oldItem.is_pwa == newItem.is_pwa + oldItem.appSize.contentEquals(newItem.appSize) && + oldItem.author.contentEquals(newItem.author) && + oldItem.category.contentEquals(newItem.category) && + oldItem.description.contentEquals(newItem.description) && + oldItem.icon_image_path.contentEquals(newItem.icon_image_path) && + oldItem.last_modified.contentEquals(newItem.last_modified) && + oldItem.latest_version_code == newItem.latest_version_code && + oldItem.latest_version_number.contentEquals(newItem.latest_version_number) && + oldItem.licence.contentEquals(newItem.licence) && + oldItem.appSize.contentEquals(newItem.appSize) && + oldItem.name.contentEquals(newItem.name) && + oldItem.offer_type == newItem.offer_type && + oldItem.origin == newItem.origin && + oldItem.other_images_path == newItem.other_images_path && + oldItem.package_name.contentEquals(newItem.package_name) && + oldItem.perms == newItem.perms && + oldItem.ratings == newItem.ratings && + oldItem.shareUrl.contentEquals(newItem.shareUrl) && + oldItem.source.contentEquals(newItem.source) && + oldItem.status == newItem.status && + ((oldItem.trackers == LIST_OF_NULL && newItem.trackers.isEmpty()) || oldItem.trackers == newItem.trackers) && + oldItem.url.contentEquals(newItem.url) && + oldItem.isFree == newItem.isFree && + oldItem.is_pwa == newItem.is_pwa } } -- GitLab From 277eb4fe775daffdbceb717df581de53fc62f07a Mon Sep 17 00:00:00 2001 From: Sayantan Roychowdhury Date: Fri, 2 Dec 2022 22:18:18 +0530 Subject: [PATCH 12/12] Add copyright --- .../e/apps/api/fdroid/FdroidWebInterface.kt | 17 +++++++++++++++++ app/src/main/res/drawable/ic_warning_black.xml | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt index 2281becd5..14047877e 100644 --- a/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt +++ b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2019-2022 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package foundation.e.apps.api.fdroid import okhttp3.ResponseBody diff --git a/app/src/main/res/drawable/ic_warning_black.xml b/app/src/main/res/drawable/ic_warning_black.xml index 39883ee9e..90f73c77a 100644 --- a/app/src/main/res/drawable/ic_warning_black.xml +++ b/app/src/main/res/drawable/ic_warning_black.xml @@ -1,3 +1,20 @@ +