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 911f4affafafcb9dd4068df2a555a539738f4f5a..b03baa0b3916ed7aafc3bed8819b1403633fbd8a 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 0000000000000000000000000000000000000000..14047877eb3c6f2321109ad0ccbe380ae0e297e2 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/fdroid/FdroidWebInterface.kt @@ -0,0 +1,32 @@ +/* + * 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 +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("{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 35d71d0889653d5b6fa8f9a1b7e2442817225e7a..9657199e1c0637b9c8e0ae0deb598e049d627c29 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.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 @@ -74,6 +75,7 @@ class FusedAPIImpl @Inject constructor( private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, + private val fdroidWebInterface: FdroidWebInterface, @ApplicationContext private val context: Context ) { @@ -1186,15 +1188,33 @@ class FusedAPIImpl @Inject constructor( query: String, authData: AuthData ): LiveData, Boolean>> { - val searchResults = gPlayAPIRepository.getSearchResults(query, authData) + val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { Pair( - it.first.map { app -> app.transformToFusedApp() }, + it.first, it.second ) } } + /* + * 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 */ @@ -1471,4 +1491,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 270f65a9e98f77da1f7df45965295f70f544f347..28000e6351b6dbbda18ec8edc08830fd0a1a08da 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 a8cf9cac2e1bda62acd88a8093cd4f68a4218651..4a12816f5bc8f79949ab14bcf67cc84287607371 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 66f7ec934259e73e5984accab95f21e150e1a92a..f68b6680e00c32401ce5f2af7472c169c82a84b9 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,6 +36,7 @@ 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 @@ -56,7 +58,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, + 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 @@ -70,7 +76,17 @@ class GPlayAPIImpl @Inject constructor(private val gPlayHttpClient: GPlayHttpCli val searchHelper = SearchHelper(authData).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) - emit(Pair(searchBundle.appList, true)) + val initialReplacedList = mutableListOf() + val INITIAL_LIMIT = 4 + + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + replaceWithFDroid, + searchBundle, + true, + ) var nextSubBundleSet: MutableSet do { @@ -80,11 +96,63 @@ 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())) + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + replaceWithFDroid, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) } } } while (nextSubBundleSet.isNotEmpty()) + + /* + * 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)) + } + } + } + } + + 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)) + } } } } @@ -113,7 +181,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 f8c735a7d7249d3dfd4d9e14af3768fc1a76c141..4475cb03acf7135b2d9c3fbe5ad1bdfc9b7d9121 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 @@ -27,6 +27,7 @@ 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 class GPlayAPIRepository @Inject constructor(private val gPlayAPIImpl: GPlayAPIImpl) { @@ -35,8 +36,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, + replaceWithFDroid: suspend (App) -> FusedApp, + ): LiveData, Boolean>> { + return gPlayAPIImpl.getSearchResults(query, authData, replaceWithFDroid) } suspend fun getOnDemandModule( 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 bd4414dd6c298cfaabb7bc66ed0d6b910559dd40..62d3a62f66a87740781cda0be7317db3f1d940b9 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 6366fdb286d560717c80adb63474cf5d4ae50fea..d4e9b43c0bb30f0fecd7352cf65e7925420a6b06 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 e1c2c3a65b37847884d17476bd7de5bfba3911a7..583c38d44d60b0b2f65a359e60e4757d37c282f9 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 { @@ -27,29 +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 == 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 } } 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 786571b00fa892944e030e3816a3893bf3012bfa..f056b13acbe11cf59e2933ea35d3c6467f212108 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/java/foundation/e/apps/search/SearchViewModel.kt b/app/src/main/java/foundation/e/apps/search/SearchViewModel.kt index aa0f9697ec08812597453ce9af00d7fdf3afdbe3..deab32583a5e2295681b2ffaf90263a778674deb 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/main/res/drawable/ic_warning_black.xml b/app/src/main/res/drawable/ic_warning_black.xml new file mode 100644 index 0000000000000000000000000000000000000000..90f73c77a9025cc09270fe38ac662151add5e564 --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_black.xml @@ -0,0 +1,27 @@ + + + + diff --git a/app/src/main/res/layout/fragment_application.xml b/app/src/main/res/layout/fragment_application.xml index 7b4af2745de4ec0751064521845a56a7f77761ba..62958a2a393623ae3426cf99da30b138ada0be89 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 1c7d6c2909746eeb125cb49186d5ac943fc2ad3b..d15437ba1ca82f16b18c93c0e91ab554b094f628 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 44b0740706f7059cdd594b38d95382fc7cf4e946..1deed041e66a81039ace74e10774b6bbc7bd4542 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 ac6c7281d654b2bdc23352173ccf01a72020bed6..646b84fad6f0c241f16dde4fb2f5687d13aac5f4 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,7 +817,18 @@ class FusedApiImplTest { source = CleanAPKInterface.APP_SOURCE_ANY ) ).thenReturn(packageNameSearchResponse) - Mockito.`when`(gPlayAPIRepository.getSearchResults(eq("com.search.package"), eq(authData))) + + suspend fun replaceWithFDroid(gPlayApp: App): FusedApp { + return FusedApp(gPlayApp.id.toString(), gPlayApp.packageName) + } + + Mockito.`when`( + gPlayAPIRepository.getSearchResults( + eq("com.search.package"), + eq(authData), + eq(::replaceWithFDroid) + ) + ) .thenReturn(gplayLivedata) } @@ -846,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