diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml
index 7813ffbf56cdf7620ed388b92bb03a51518819cc..21ad79f516a33adfd9001d3d42594fe136bff908 100644
--- a/app/detekt-baseline.xml
+++ b/app/detekt-baseline.xml
@@ -169,33 +169,20 @@
TooGenericExceptionThrown:AnonymousLoginManager.kt$AnonymousLoginManager$throw Exception( "Error fetching Anonymous credentials\n" + "Network code: ${response.code}\n" + "Success: ${response.isSuccessful}" + response.errorString.run { if (isNotBlank()) "\nError message: $this" else "" } )
TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception("Validation network code: ${response.code}")
TooGenericExceptionThrown:PlayStoreLoginWrapper.kt$PlayStoreLoginWrapper$throw Exception(error)
- TooManyFunctions:AppInstallProcessor.kt$AppInstallProcessor
- TooManyFunctions:AppPrivacyInfoRepositoryImpl.kt$AppPrivacyInfoRepositoryImpl : IAppPrivacyInfoRepository
TooManyFunctions:ApplicationApi.kt$ApplicationApi
TooManyFunctions:ApplicationApiImpl.kt$ApplicationApiImpl : ApplicationApi
- TooManyFunctions:ApplicationFragment.kt$ApplicationFragment : TimeoutFragment
TooManyFunctions:ApplicationListFragment.kt$ApplicationListFragment : TimeoutFragmentApplicationInstaller
- TooManyFunctions:ApplicationListRVAdapter.kt$ApplicationListRVAdapter : ListAdapter
TooManyFunctions:ApplicationRepository.kt$ApplicationRepository
- TooManyFunctions:DownloadManager.kt$DownloadManager
TooManyFunctions:FusedManagerImpl.kt$FusedManagerImpl : IFusedManager
TooManyFunctions:FusedManagerRepository.kt$FusedManagerRepository
- TooManyFunctions:GPlayHttpClient.kt$GPlayHttpClient : IHttpClient
- TooManyFunctions:HomeChildRVAdapter.kt$HomeChildRVAdapter : ListAdapter
TooManyFunctions:HomeFragment.kt$HomeFragment : TimeoutFragmentApplicationInstaller
TooManyFunctions:IFusedManager.kt$IFusedManager
TooManyFunctions:LoginData.kt$LoginData
- TooManyFunctions:MainActivity.kt$MainActivity : AppCompatActivity
TooManyFunctions:MainActivityViewModel.kt$MainActivityViewModel : ViewModel
TooManyFunctions:PkgManagerModule.kt$PkgManagerModule
- TooManyFunctions:PlayStoreAuthenticator.kt$PlayStoreAuthenticator : StoreAuthenticatorAuthDataValidator
- TooManyFunctions:PlayStoreRepositoryImpl.kt$PlayStoreRepositoryImpl : PlayStoreRepository
- TooManyFunctions:RetrofitModule.kt$RetrofitModule
TooManyFunctions:SearchFragment.kt$SearchFragment : TimeoutFragmentOnQueryTextListenerOnSuggestionListenerApplicationInstaller
TooManyFunctions:TimeoutFragment.kt$TimeoutFragment : Fragment
TooManyFunctions:UpdatesFragment.kt$UpdatesFragment : TimeoutFragmentApplicationInstaller
- TooManyFunctions:UpdatesManagerImpl.kt$UpdatesManagerImpl
- TooManyFunctions:UpdatesWorker.kt$UpdatesWorker : CoroutineWorker
UnusedParameter:SearchViewModel.kt$SearchViewModel$lifecycleOwner: LifecycleOwner
diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt
index 3b47a38dc0803b47e8608837a3fe825a246befeb..e6434f15782ccbff117210a2bb341ffece272e18 100644
--- a/app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt
@@ -62,71 +62,4 @@ interface ApplicationApi {
suspend fun getOSSDownloadInfo(id: String, version: String?): Response
- /*
- * Function to search cleanapk using package name.
- * Will be used to handle f-droid deeplink.
- *
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5509
- */
- suspend fun getCleanapkAppDetails(packageName: String): Pair
-
- suspend fun getApplicationDetails(
- packageNameList: List,
- authData: AuthData,
- origin: Origin
- ): Pair, ResultStatus>
-
- /**
- * Filter out apps which are restricted, whose details cannot be fetched.
- * If an app is restricted, we do try to fetch the app details inside a
- * try-catch block. If that fails, we remove the app, else we keep it even
- * if it is restricted.
- *
- * Popular example: "com.skype.m2"
- *
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5174
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2]
- */
- suspend fun filterRestrictedGPlayApps(
- authData: AuthData,
- appList: List,
- ): ResultSupreme>
-
- /**
- * Get different filter levels.
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720
- */
- suspend fun getAppFilterLevel(application: Application, authData: AuthData?): FilterLevel
-
- /*
- * Similar to above method but uses Aurora OSS data class "App".
- */
- suspend fun getAppFilterLevel(app: App, authData: AuthData): FilterLevel
-
- suspend fun getApplicationDetails(
- id: String,
- packageName: String,
- authData: AuthData,
- origin: Origin
- ): Pair
-
- /**
- * Get fused app installation status.
- * Applicable for both native apps and PWAs.
- *
- * Recommended to use this instead of [PkgManagerModule.getPackageStatus].
- */
- fun getFusedAppInstallationStatus(application: Application): Status
-
- /**
- * @return returns true if there is changes in data, otherwise false
- */
- fun isAnyFusedAppUpdated(
- newApplications: List,
- oldApplications: List
- ): Boolean
-
- fun isAnyAppInstallStatusChanged(currentList: List): Boolean
- fun isOpenSourceSelected(): Boolean
-
}
diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt
index 60340803d1631cd5da7ed07650b73ea1b1c6da1c..fdd6ab9284d1e45748013aa550bdbe70d5c4c6db 100644
--- a/app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt
@@ -19,71 +19,52 @@
package foundation.e.apps.data.application
import android.content.Context
-import android.text.format.Formatter
-import com.aurora.gplayapi.Constants
import com.aurora.gplayapi.SearchSuggestEntry
import com.aurora.gplayapi.data.models.App
-import com.aurora.gplayapi.data.models.Artwork
import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.SearchBundle
-import com.aurora.gplayapi.data.models.StreamCluster
import dagger.hilt.android.qualifiers.ApplicationContext
-import foundation.e.apps.R
import foundation.e.apps.data.ResultSupreme
import foundation.e.apps.data.application.ApplicationApi.Companion.APP_TYPE_ANY
import foundation.e.apps.data.application.ApplicationApi.Companion.APP_TYPE_OPEN
import foundation.e.apps.data.application.ApplicationApi.Companion.APP_TYPE_PWA
import foundation.e.apps.data.application.data.Application
-import foundation.e.apps.data.application.data.Category
import foundation.e.apps.data.application.data.Home
-import foundation.e.apps.data.application.data.Ratings
-import foundation.e.apps.data.application.utils.CategoryType
-import foundation.e.apps.data.application.utils.CategoryUtils
+import foundation.e.apps.data.application.utils.toApplication
import foundation.e.apps.data.cleanapk.CleanApkDownloadInfoFetcher
-import foundation.e.apps.data.cleanapk.data.categories.Categories
-import foundation.e.apps.data.cleanapk.data.search.Search
import foundation.e.apps.data.cleanapk.repositories.CleanApkRepository
-import foundation.e.apps.data.enums.AppTag
-import foundation.e.apps.data.enums.FilterLevel
import foundation.e.apps.data.enums.Origin
import foundation.e.apps.data.enums.ResultStatus
-import foundation.e.apps.data.enums.Status
-import foundation.e.apps.data.enums.Type
-import foundation.e.apps.data.enums.isUnFiltered
import foundation.e.apps.data.fusedDownload.models.FusedDownload
import foundation.e.apps.data.handleNetworkResult
import foundation.e.apps.data.login.AuthObject
import foundation.e.apps.data.playstore.PlayStoreRepository
import foundation.e.apps.data.preference.PreferenceManagerModule
-import foundation.e.apps.install.pkg.PWAManagerModule
-import foundation.e.apps.install.pkg.PkgManagerModule
-import foundation.e.apps.ui.applicationlist.ApplicationDiffUtil
import foundation.e.apps.utils.eventBus.AppEvent
import foundation.e.apps.utils.eventBus.EventBus
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
-import retrofit2.Response
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
-import com.aurora.gplayapi.data.models.Category as GplayapiCategory
-import foundation.e.apps.data.cleanapk.data.app.Application as CleanApkApplication
typealias FusedHomeDeferred = Deferred>>
@Singleton
class ApplicationApiImpl @Inject constructor(
- private val pkgManagerModule: PkgManagerModule,
- private val pwaManagerModule: PWAManagerModule,
+ private val appsApi: AppsApi,
private val preferenceManagerModule: PreferenceManagerModule,
@Named("gplayRepository") private val gplayRepository: PlayStoreRepository,
@Named("cleanApkAppsRepository") private val cleanApkAppsRepository: CleanApkRepository,
@Named("cleanApkPWARepository") private val cleanApkPWARepository: CleanApkRepository,
- @ApplicationContext private val context: Context
+ private val applicationDataManager: ApplicationDataManager
) : ApplicationApi {
+ @Inject
+ @ApplicationContext lateinit var context: Context
+
companion object {
private const val KEYWORD_TEST_SEARCH = "facebook"
}
@@ -108,11 +89,6 @@ class ApplicationApiImpl @Inject constructor(
query: String,
authData: AuthData
): ResultSupreme, Boolean>> {
- /*
- * Returning livedata to improve performance, so that we do not have to wait forever
- * for all results to be fetched from network before showing them.
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171
- */
val packageSpecificResults = ArrayList()
var finalSearchResult: ResultSupreme, Boolean>> = ResultSupreme.Error()
@@ -150,9 +126,9 @@ class ApplicationApiImpl @Inject constructor(
val apps =
cleanApkPWARepository.getSearchResult(query).body()?.apps
apps?.forEach {
- it.updateStatus()
+ applicationDataManager.updateStatus(it)
it.updateType()
- it.updateSource()
+ it.updateSource(context)
pwaApps.add(it)
}
}
@@ -287,7 +263,7 @@ class ApplicationApiImpl @Inject constructor(
authData: AuthData,
): Application? {
try {
- getApplicationDetails(query, query, authData, Origin.GPLAY).let {
+ appsApi.getApplicationDetails(query, query, authData, Origin.GPLAY).let {
if (it.second == ResultStatus.OK && it.first.package_name.isNotEmpty()) {
return it.first
}
@@ -383,252 +359,6 @@ class ApplicationApiImpl @Inject constructor(
override suspend fun getOSSDownloadInfo(id: String, version: String?) =
(cleanApkAppsRepository as CleanApkDownloadInfoFetcher).getDownloadInfo(id, version)
- /*
- * Function to search cleanapk using package name.
- * Will be used to handle f-droid deeplink.
- *
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5509
- */
- override suspend fun getCleanapkAppDetails(packageName: String): Pair {
- var application = Application()
- val result = handleNetworkResult {
- val result = cleanApkAppsRepository.getSearchResult(
- packageName,
- "package_name"
- ).body()
-
- if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) {
- application =
- (cleanApkAppsRepository.getAppDetails(result.apps[0]._id) as Response).body()?.app
- ?: Application()
- }
- application.updateFilterLevel(null)
- }
- return Pair(application, result.getResultStatus())
- }
-
- // Warning - GPlay results may not have proper geo-restriction information.
- override suspend fun getApplicationDetails(
- packageNameList: List,
- authData: AuthData,
- origin: Origin
- ): Pair, ResultStatus> {
- val list = mutableListOf()
-
- val response: Pair, ResultStatus> =
- if (origin == Origin.CLEANAPK) {
- getAppDetailsListFromCleanapk(packageNameList)
- } else {
- getAppDetailsListFromGPlay(packageNameList, authData)
- }
-
- response.first.forEach {
- if (it.package_name.isNotBlank()) {
- it.updateStatus()
- it.updateType()
- list.add(it)
- }
- }
-
- return Pair(list, response.second)
- }
-
- /*
- * Get app details of a list of apps from cleanapk.
- * Returns list of FusedApp and ResultStatus - which will reflect timeout if even one app fails.
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5413
- */
- private suspend fun getAppDetailsListFromCleanapk(
- packageNameList: List,
- ): Pair, ResultStatus> {
- var status = ResultStatus.OK
- val applicationList = mutableListOf()
-
- /*
- * Fetch result of each cleanapk search with separate timeout,
- * i.e. check timeout for individual package query.
- */
- for (packageName in packageNameList) {
- val result = handleNetworkResult {
- cleanApkAppsRepository.getSearchResult(
- packageName,
- "package_name"
- ).body()?.run {
- if (apps.isNotEmpty() && numberOfResults == 1) {
- applicationList.add(
- apps[0].apply {
- updateFilterLevel(null)
- }
- )
- }
- }
- }
-
- status = result.getResultStatus()
-
- /*
- * If status is not ok, immediately return.
- */
- if (status != ResultStatus.OK) {
- return Pair(applicationList, status)
- }
- }
-
- return Pair(applicationList, status)
- }
-
- /*
- * Get app details of a list of apps from Google Play store.
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5413
- */
- private suspend fun getAppDetailsListFromGPlay(
- packageNameList: List,
- authData: AuthData,
- ): Pair, ResultStatus> {
- val applicationList = mutableListOf()
-
- /*
- * Old code moved from getApplicationDetails()
- */
- val result = handleNetworkResult {
- gplayRepository.getAppsDetails(packageNameList).forEach { app ->
- /*
- * Some apps are restricted to locations. Example "com.skype.m2".
- * For restricted apps, check if it is possible to get their specific app info.
- *
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5174
- */
- val filter = getAppFilterLevel(app, authData)
- if (filter.isUnFiltered()) {
- applicationList.add(
- app.transformToFusedApp().apply {
- filterLevel = filter
- }
- )
- }
- }
- }
-
- return Pair(applicationList, result.getResultStatus())
- }
-
- /**
- * Filter out apps which are restricted, whose details cannot be fetched.
- * If an app is restricted, we do try to fetch the app details inside a
- * try-catch block. If that fails, we remove the app, else we keep it even
- * if it is restricted.
- *
- * Popular example: "com.skype.m2"
- *
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5174
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2]
- */
- override suspend fun filterRestrictedGPlayApps(
- authData: AuthData,
- appList: List,
- ): ResultSupreme> {
- val filteredApplications = mutableListOf()
- return handleNetworkResult {
- appList.forEach {
- val filter = getAppFilterLevel(it, authData)
- if (filter.isUnFiltered()) {
- filteredApplications.add(
- it.transformToFusedApp().apply {
- this.filterLevel = filter
- }
- )
- }
- }
- filteredApplications
- }
- }
-
- /**
- * Get different filter levels.
- * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5720
- */
- override suspend fun getAppFilterLevel(application: Application, authData: AuthData?): FilterLevel {
- return when {
- application.package_name.isBlank() -> FilterLevel.UNKNOWN
- !application.isFree && application.price.isBlank() -> FilterLevel.UI
- application.origin == Origin.CLEANAPK -> FilterLevel.NONE
- !isRestricted(application) -> FilterLevel.NONE
- authData == null -> FilterLevel.UNKNOWN // cannot determine for gplay app
- !isApplicationVisible(application) -> FilterLevel.DATA
- application.originalSize == 0L -> FilterLevel.UI
- !isDownloadable(application) -> FilterLevel.UI
- else -> FilterLevel.NONE
- }
- }
-
- /**
- * Some apps are simply not visible.
- * Example: com.skype.m2
- */
- private suspend fun isApplicationVisible(application: Application): Boolean {
- return kotlin.runCatching { gplayRepository.getAppDetails(application.package_name) }.isSuccess
- }
-
- /**
- * Some apps are visible but not downloadable.
- * Example: com.riotgames.league.wildrift
- */
- private suspend fun isDownloadable(application: Application): Boolean {
- return kotlin.runCatching {
- gplayRepository.getDownloadInfo(
- application.package_name,
- application.latest_version_code,
- application.offer_type,
- )
- }.isSuccess
- }
-
- private fun isRestricted(application: Application): Boolean {
- return application.restriction != Constants.Restriction.NOT_RESTRICTED
- }
-
- /*
- * Similar to above method but uses Aurora OSS data class "App".
- */
- override suspend fun getAppFilterLevel(app: App, authData: AuthData): FilterLevel {
- return getAppFilterLevel(app.transformToFusedApp(), authData)
- }
-
- /*
- * Handy method to run on an instance of FusedApp to update its filter level.
- */
- suspend fun Application.updateFilterLevel(authData: AuthData?) {
- this.filterLevel = getAppFilterLevel(this, authData)
- }
-
- override suspend fun getApplicationDetails(
- id: String,
- packageName: String,
- authData: AuthData,
- origin: Origin
- ): Pair {
-
- var response: Application? = null
-
- val result = handleNetworkResult {
- response = if (origin == Origin.CLEANAPK) {
- (cleanApkAppsRepository.getAppDetails(id) as Response).body()?.app
- } else {
- val app = gplayRepository.getAppDetails(packageName) as App?
- app?.transformToFusedApp()
- }
- response?.let {
- it.updateStatus()
- it.updateType()
- it.updateSource()
- it.updateFilterLevel(authData)
- }
- response
- }
-
- return Pair(result.data ?: Application(), result.getResultStatus())
- }
-
/*
* Search-related internal functions
*/
@@ -641,9 +371,9 @@ class ApplicationApiImpl @Inject constructor(
cleanApkAppsRepository.getSearchResult(keyword).body()?.apps
response?.forEach {
- it.updateStatus()
+ applicationDataManager.updateStatus(it)
it.updateType()
- it.updateSource()
+ it.updateSource(context)
list.add(it)
}
return list
@@ -691,11 +421,11 @@ class ApplicationApiImpl @Inject constructor(
* else will show the GPlay app itself.
*/
private suspend fun replaceWithFDroid(gPlayApp: App): Application {
- val gPlayFusedApp = gPlayApp.transformToFusedApp()
+ val gPlayFusedApp = gPlayApp.toApplication(context)
val response = cleanApkAppsRepository.getAppDetails(gPlayApp.packageName)
if (response != null) {
val fdroidApp = getCleanApkPackageResult(gPlayFusedApp.package_name)?.apply {
- updateSource()
+ this.updateSource(context)
isGplayReplaced = true
}
return fdroidApp ?: gPlayFusedApp
@@ -711,120 +441,4 @@ class ApplicationApiImpl @Inject constructor(
)
}
}
-
- /*
- * FusedApp-related internal extensions and functions
- */
-
- private fun App.transformToFusedApp(): Application {
- val app = Application(
- _id = this.id.toString(),
- author = this.developerName,
- category = this.categoryName,
- description = this.description,
- perms = this.permissions,
- icon_image_path = this.iconArtwork.url,
- last_modified = this.updatedOn,
- latest_version_code = this.versionCode,
- latest_version_number = this.versionName,
- name = this.displayName,
- other_images_path = this.screenshots.transformToList(),
- package_name = this.packageName,
- ratings = Ratings(
- usageQualityScore =
- this.labeledRating.run {
- if (isNotEmpty()) {
- this.replace(",", ".").toDoubleOrNull() ?: -1.0
- } else -1.0
- }
- ),
- offer_type = this.offerType,
- origin = Origin.GPLAY,
- shareUrl = this.shareUrl,
- originalSize = this.size,
- appSize = Formatter.formatFileSize(context, this.size),
- isFree = this.isFree,
- price = this.price,
- restriction = this.restriction,
- )
- app.updateStatus()
- return app
- }
-
- /**
- * Get fused app installation status.
- * Applicable for both native apps and PWAs.
- *
- * Recommended to use this instead of [PkgManagerModule.getPackageStatus].
- */
- override fun getFusedAppInstallationStatus(application: Application): Status {
- return if (application.is_pwa) {
- pwaManagerModule.getPwaStatus(application)
- } else {
- pkgManagerModule.getPackageStatus(application.package_name, application.latest_version_code)
- }
- }
-
- private fun Application.updateStatus() {
- if (this.status != Status.INSTALLATION_ISSUE) {
- this.status = getFusedAppInstallationStatus(this)
- }
- }
-
- private fun Application.updateType() {
- this.type = if (this.is_pwa) Type.PWA else Type.NATIVE
- }
-
- private fun Application.updateSource() {
- this.apply {
- source = if (origin == Origin.CLEANAPK && is_pwa) context.getString(R.string.pwa)
- else if (origin == Origin.CLEANAPK) context.getString(R.string.open_source)
- else ""
- }
- }
-
- private fun MutableList.transformToList(): List {
- val list = mutableListOf()
- this.forEach {
- list.add(it.url)
- }
- return list
- }
-
- /**
- * @return returns true if there is changes in data, otherwise false
- */
- override fun isAnyFusedAppUpdated(
- newApplications: List,
- oldApplications: List
- ): Boolean {
- val fusedAppDiffUtil = ApplicationDiffUtil()
- if (newApplications.size != oldApplications.size) {
- return true
- }
-
- newApplications.forEach {
- val indexOfNewFusedApp = newApplications.indexOf(it)
- if (!fusedAppDiffUtil.areContentsTheSame(it, oldApplications[indexOfNewFusedApp])) {
- return true
- }
- }
- return false
- }
-
- override fun isAnyAppInstallStatusChanged(currentList: List): Boolean {
- currentList.forEach {
- if (it.status == Status.INSTALLATION_ISSUE) {
- return@forEach
- }
- val currentAppStatus =
- getFusedAppInstallationStatus(it)
- if (it.status != currentAppStatus) {
- return true
- }
- }
- return false
- }
-
- override fun isOpenSourceSelected() = preferenceManagerModule.isOpenSourceSelected()
}
diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt
index 81f5d3d8cedb4e4a879749f9ec813cd346987d0b..24f2ac55a78b9ecda5b147263b3faf209922f531 100644
--- a/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt
@@ -40,7 +40,8 @@ import javax.inject.Singleton
class ApplicationRepository @Inject constructor(
private val applicationAPIImpl: ApplicationApi,
private val homeApi: HomeApi,
- private val categoryApi: CategoryApi
+ private val categoryApi: CategoryApi,
+ private val appsApi: AppsApi,
) {
suspend fun getHomeScreenData(authData: AuthData): LiveData>> {
@@ -56,11 +57,11 @@ class ApplicationRepository @Inject constructor(
authData: AuthData,
origin: Origin
): Pair, ResultStatus> {
- return applicationAPIImpl.getApplicationDetails(packageNameList, authData, origin)
+ return appsApi.getApplicationDetails(packageNameList, authData, origin)
}
suspend fun getAppFilterLevel(application: Application, authData: AuthData?): FilterLevel {
- return applicationAPIImpl.getAppFilterLevel(application, authData)
+ return appsApi.getAppFilterLevel(application, authData)
}
suspend fun getApplicationDetails(
@@ -69,11 +70,11 @@ class ApplicationRepository @Inject constructor(
authData: AuthData,
origin: Origin
): Pair {
- return applicationAPIImpl.getApplicationDetails(id, packageName, authData, origin)
+ return appsApi.getApplicationDetails(id, packageName, authData, origin)
}
suspend fun getCleanapkAppDetails(packageName: String): Pair {
- return applicationAPIImpl.getCleanapkAppDetails(packageName)
+ return appsApi.getCleanapkAppDetails(packageName)
}
suspend fun updateFusedDownloadWithDownloadingInfo(
@@ -136,16 +137,16 @@ class ApplicationRepository @Inject constructor(
}
fun getFusedAppInstallationStatus(application: Application): Status {
- return applicationAPIImpl.getFusedAppInstallationStatus(application)
+ return appsApi.getFusedAppInstallationStatus(application)
}
fun isAnyFusedAppUpdated(
newApplications: List,
oldApplications: List
- ) = applicationAPIImpl.isAnyFusedAppUpdated(newApplications, oldApplications)
+ ) = appsApi.isAnyFusedAppUpdated(newApplications, oldApplications)
fun isAnyAppInstallStatusChanged(currentList: List) =
- applicationAPIImpl.isAnyAppInstallStatusChanged(currentList)
+ appsApi.isAnyAppInstallStatusChanged(currentList)
- fun isOpenSourceSelected() = applicationAPIImpl.isOpenSourceSelected()
+ fun isOpenSourceSelected() = appsApi.isOpenSourceSelected()
}
diff --git a/app/src/main/java/foundation/e/apps/data/application/AppsApi.kt b/app/src/main/java/foundation/e/apps/data/application/AppsApi.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8e3f0491dc30ef4fba674ef84a12d5d411a659d5
--- /dev/null
+++ b/app/src/main/java/foundation/e/apps/data/application/AppsApi.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright MURENA SAS 2023
+ * Apps Quickly and easily install Android apps onto your device!
+ *
+ * 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.data.application
+
+import com.aurora.gplayapi.data.models.AuthData
+import foundation.e.apps.data.application.data.Application
+import foundation.e.apps.data.enums.FilterLevel
+import foundation.e.apps.data.enums.Origin
+import foundation.e.apps.data.enums.ResultStatus
+import foundation.e.apps.data.enums.Status
+
+interface AppsApi {
+
+ /*
+ * Function to search cleanapk using package name.
+ * Will be used to handle f-droid deeplink.
+ */
+ suspend fun getCleanapkAppDetails(packageName: String): Pair
+
+ suspend fun getApplicationDetails(
+ packageNameList: List,
+ authData: AuthData,
+ origin: Origin
+ ): Pair, ResultStatus>
+
+ suspend fun getApplicationDetails(
+ id: String,
+ packageName: String,
+ authData: AuthData,
+ origin: Origin
+ ): Pair
+
+ /**
+ * Get fused app installation status.
+ * Applicable for both native apps and PWAs.
+ *
+ * Recommended to use this instead of [PkgManagerModule.getPackageStatus].
+ */
+ fun getFusedAppInstallationStatus(application: Application): Status
+
+ suspend fun getAppFilterLevel(application: Application, authData: AuthData?): FilterLevel
+
+ /**
+ * @return returns true if there is changes in data, otherwise false
+ */
+ fun isAnyFusedAppUpdated(
+ newApplications: List,
+ oldApplications: List
+ ): Boolean
+
+ fun isAnyAppInstallStatusChanged(currentList: List): Boolean
+ fun isOpenSourceSelected(): Boolean
+}
diff --git a/app/src/main/java/foundation/e/apps/data/application/AppsApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/AppsApiImpl.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ea2b781ef88a01d4810a1e0092101e8468ef16b6
--- /dev/null
+++ b/app/src/main/java/foundation/e/apps/data/application/AppsApiImpl.kt
@@ -0,0 +1,274 @@
+/*
+ * Copyright MURENA SAS 2023
+ * Apps Quickly and easily install Android apps onto your device!
+ *
+ * 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.data.application
+
+import android.content.Context
+import com.aurora.gplayapi.data.models.App
+import com.aurora.gplayapi.data.models.AuthData
+import dagger.hilt.android.qualifiers.ApplicationContext
+import foundation.e.apps.data.application.data.Application
+import foundation.e.apps.data.cleanapk.data.app.Application as CleanApkApplication
+import foundation.e.apps.data.application.utils.toApplication
+import foundation.e.apps.data.cleanapk.data.search.Search
+import foundation.e.apps.data.cleanapk.repositories.CleanApkRepository
+import foundation.e.apps.data.enums.FilterLevel
+import foundation.e.apps.data.enums.Origin
+import foundation.e.apps.data.enums.ResultStatus
+import foundation.e.apps.data.enums.Status
+import foundation.e.apps.data.enums.isUnFiltered
+import foundation.e.apps.data.handleNetworkResult
+import foundation.e.apps.data.playstore.PlayStoreRepository
+import foundation.e.apps.data.preference.PreferenceManagerModule
+import foundation.e.apps.ui.applicationlist.ApplicationDiffUtil
+import retrofit2.Response
+import javax.inject.Inject
+import javax.inject.Named
+
+class AppsApiImpl @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val preferenceManagerModule: PreferenceManagerModule,
+ @Named("gplayRepository") private val gplayRepository: PlayStoreRepository,
+ @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: CleanApkRepository,
+ private val applicationDataManager: ApplicationDataManager
+) : AppsApi {
+
+ companion object {
+ private const val KEY_SEARCH_PACKAGE_NAME = "package_name"
+ }
+
+ override suspend fun getCleanapkAppDetails(packageName: String): Pair {
+ var application = Application()
+ val result = handleNetworkResult {
+ val result = cleanApkAppsRepository.getSearchResult(
+ packageName,
+ KEY_SEARCH_PACKAGE_NAME
+ ).body()
+
+ if (result?.hasSingleResult() == true) {
+ application =
+ (cleanApkAppsRepository.getAppDetails(result.apps[0]._id) as Response)
+ .body()?.app ?: Application()
+ }
+
+ application.updateFilterLevel(null)
+ }
+
+ return Pair(application, result.getResultStatus())
+ }
+
+ /*
+ * Handy method to run on an instance of FusedApp to update its filter level.
+ */
+ private suspend fun Application.updateFilterLevel(authData: AuthData?) {
+ this.filterLevel = applicationDataManager.getAppFilterLevel(this, authData)
+ }
+
+ override suspend fun getApplicationDetails(
+ packageNameList: List,
+ authData: AuthData,
+ origin: Origin
+ ): Pair, ResultStatus> {
+ val list = mutableListOf()
+
+ val response: Pair, ResultStatus> =
+ if (origin == Origin.CLEANAPK) {
+ getAppDetailsListFromCleanApk(packageNameList)
+ } else {
+ getAppDetailsListFromGPlay(packageNameList, authData)
+ }
+
+ response.first.forEach {
+ if (it.package_name.isNotBlank()) {
+ applicationDataManager.updateStatus(it)
+ it.updateType()
+ list.add(it)
+ }
+ }
+
+ return Pair(list, response.second)
+ }
+
+ /*
+ * Get app details of a list of apps from cleanapk.
+ * Returns list of FusedApp and ResultStatus - which will reflect error if even one app fails.
+ * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5413
+ */
+ private suspend fun getAppDetailsListFromCleanApk(
+ packageNameList: List,
+ ): Pair, ResultStatus> {
+ var status = ResultStatus.OK
+ val applicationList = mutableListOf()
+
+ for (packageName in packageNameList) {
+ val result = getCleanApkSearchResultByPackageName(packageName, applicationList)
+ status = result.getResultStatus()
+
+ if (status != ResultStatus.OK) {
+ return Pair(applicationList, status)
+ }
+ }
+
+ return Pair(applicationList, status)
+ }
+
+ private suspend fun getAppDetailsListFromGPlay(
+ packageNameList: List,
+ authData: AuthData,
+ ): Pair, ResultStatus> {
+ val applicationList = mutableListOf()
+
+ val result = handleNetworkResult {
+ gplayRepository.getAppsDetails(packageNameList).forEach { app ->
+ handleFilteredApps(app, authData, applicationList)
+ }
+ }
+
+ return Pair(applicationList, result.getResultStatus())
+ }
+
+ /*
+ * Some apps are restricted to locations. Example "com.skype.m2".
+ * For restricted apps, check if it is possible to get their specific app info.
+ *
+ * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5174
+ */
+ private suspend fun handleFilteredApps(
+ app: App,
+ authData: AuthData,
+ applicationList: MutableList
+ ) {
+ val filter = applicationDataManager.getAppFilterLevel(app.toApplication(context), authData)
+ if (filter.isUnFiltered()) {
+ applicationList.add(
+ app.toApplication(context).apply {
+ filterLevel = filter
+ }
+ )
+ }
+ }
+
+ private suspend fun getCleanApkSearchResultByPackageName(
+ packageName: String,
+ applicationList: MutableList
+ ) = handleNetworkResult {
+ cleanApkAppsRepository.getSearchResult(
+ packageName,
+ KEY_SEARCH_PACKAGE_NAME
+ ).body()?.run {
+ handleCleanApkSearch(applicationList)
+ }
+ }
+
+ private suspend fun Search.handleCleanApkSearch(
+ applicationList: MutableList
+ ) {
+ if (hasSingleResult()) {
+ applicationList.add(
+ apps[0].apply {
+ updateFilterLevel(null)
+ }
+ )
+ }
+ }
+
+ private fun Search.hasSingleResult() =
+ apps.isNotEmpty() && numberOfResults == 1
+
+ override suspend fun getApplicationDetails(
+ id: String,
+ packageName: String,
+ authData: AuthData,
+ origin: Origin
+ ): Pair {
+ var application: Application?
+
+ val result = handleNetworkResult {
+ application = if (origin == Origin.CLEANAPK) {
+ (cleanApkAppsRepository.getAppDetails(id) as Response).body()?.app
+ } else {
+ val app = gplayRepository.getAppDetails(packageName) as App?
+ app?.toApplication(context)
+ }
+
+ application?.let {
+ applicationDataManager.updateStatus(it)
+ it.updateType()
+ it.updateSource(context)
+ it.updateFilterLevel(authData)
+ }
+ application
+ }
+
+ return Pair(result.data ?: Application(), result.getResultStatus())
+ }
+
+ override fun getFusedAppInstallationStatus(application: Application): Status {
+ return applicationDataManager.getFusedAppInstallationStatus(application)
+ }
+
+ override suspend fun getAppFilterLevel(
+ application: Application,
+ authData: AuthData?
+ ): FilterLevel {
+ return applicationDataManager.getAppFilterLevel(application, authData)
+ }
+
+ override fun isAnyFusedAppUpdated(
+ newApplications: List,
+ oldApplications: List
+ ): Boolean {
+ if (newApplications.size != oldApplications.size) {
+ return true
+ }
+
+ return areApplicationsChanged(newApplications, oldApplications)
+ }
+
+ private fun areApplicationsChanged(
+ newApplications: List,
+ oldApplications: List
+ ): Boolean {
+ val fusedAppDiffUtil = ApplicationDiffUtil()
+ newApplications.forEach {
+ val indexOfNewFusedApp = newApplications.indexOf(it)
+ if (!fusedAppDiffUtil.areContentsTheSame(it, oldApplications[indexOfNewFusedApp])) {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ override fun isAnyAppInstallStatusChanged(currentList: List): Boolean {
+ currentList.forEach {
+ if (it.status == Status.INSTALLATION_ISSUE) {
+ return@forEach
+ }
+
+ val currentAppStatus = getFusedAppInstallationStatus(it)
+ if (it.status != currentAppStatus) {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ override fun isOpenSourceSelected() = preferenceManagerModule.isOpenSourceSelected()
+}
diff --git a/app/src/main/java/foundation/e/apps/data/application/CategoryApiImpl.kt b/app/src/main/java/foundation/e/apps/data/application/CategoryApiImpl.kt
index 733f7e07a61acd5eff83350b6d42003ce9165a59..e222d724208b86548498a3374c3809bca461690b 100644
--- a/app/src/main/java/foundation/e/apps/data/application/CategoryApiImpl.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/CategoryApiImpl.kt
@@ -64,33 +64,27 @@ class CategoryApiImpl @Inject constructor(
categoriesList: MutableList,
type: CategoryType,
): ResultStatus {
- var categoryResult: ResultStatus = ResultStatus.OK
-
- /** Here, `categoryResult` is updated by fetchCategoryResult()
- And `fetchCategoryResult()` returns the result of categoryResult based
- on current categoryResu lt, if currentCategoryResult != ResultStatus.OK,
- fetchCategoryResult() doesn't return the latest result to preserve the error.*/
+ val categoryResults: MutableList = mutableListOf()
if (preferenceManagerModule.isOpenSourceSelected()) {
- categoryResult = fetchCategoryResult(categoriesList, type, Source.OPEN, categoryResult)
+ categoryResults.add(fetchCategoryResult(categoriesList, type, Source.OPEN))
}
if (preferenceManagerModule.isPWASelected()) {
- categoryResult = fetchCategoryResult(categoriesList, type, Source.PWA, categoryResult)
+ categoryResults.add(fetchCategoryResult(categoriesList, type, Source.PWA))
}
if (preferenceManagerModule.isGplaySelected()) {
- categoryResult = fetchCategoryResult(categoriesList, type, Source.GPLAY, categoryResult)
+ categoryResults.add(fetchCategoryResult(categoriesList, type, Source.GPLAY))
}
- return categoryResult
+ return categoryResults.find { it != ResultStatus.OK } ?: ResultStatus.OK
}
private suspend fun fetchCategoryResult(
categoriesList: MutableList,
type: CategoryType,
- source: Source,
- currentCategoryResult: ResultStatus
+ source: Source
): ResultStatus {
val categoryResult = when (source) {
Source.OPEN -> {
@@ -110,8 +104,7 @@ class CategoryApiImpl @Inject constructor(
categoriesList.addAll(it.first)
}
- return if (currentCategoryResult == ResultStatus.OK)
- categoryResult.second else currentCategoryResult
+ return categoryResult.second
}
private suspend fun fetchGplayCategories(
diff --git a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt
index 7b42d7e71ae69723d3e0c22d362c60dc54286d5b..ba7836bcc60e1eb561b73113c21e03837dee9f25 100644
--- a/app/src/main/java/foundation/e/apps/data/application/data/Application.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/data/Application.kt
@@ -18,7 +18,9 @@
package foundation.e.apps.data.application.data
+import android.content.Context
import com.aurora.gplayapi.Constants.Restriction
+import foundation.e.apps.R
import foundation.e.apps.data.enums.FilterLevel
import foundation.e.apps.data.enums.Origin
import foundation.e.apps.data.enums.Status
@@ -97,4 +99,12 @@ data class Application(
fun updateType() {
this.type = if (this.is_pwa) Type.PWA else Type.NATIVE
}
+
+ fun updateSource(context: Context) {
+ this.apply {
+ source = if (origin != Origin.CLEANAPK) ""
+ else if (is_pwa) context.getString(R.string.pwa)
+ else context.getString(R.string.open_source)
+ }
+ }
}
diff --git a/app/src/main/java/foundation/e/apps/data/application/utils/GplayApiExtensions.kt b/app/src/main/java/foundation/e/apps/data/application/utils/GplayApiExtensions.kt
index 404c7384d2dd013ef0f7f60645d49d904a8096b8..be26c5669b9ad838ef0353104bd290fb94fb07e2 100644
--- a/app/src/main/java/foundation/e/apps/data/application/utils/GplayApiExtensions.kt
+++ b/app/src/main/java/foundation/e/apps/data/application/utils/GplayApiExtensions.kt
@@ -23,7 +23,7 @@ import android.text.format.Formatter
import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Artwork
import com.aurora.gplayapi.data.models.Category
-import foundation.e.apps.data.application.data.Category as AppLoungeCategroy
+import foundation.e.apps.data.application.data.Category as AppLoungeCategory
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.data.Ratings
import foundation.e.apps.data.enums.Origin
@@ -62,9 +62,9 @@ fun App.toApplication(context: Context): Application {
return app
}
-fun Category.toCategory(): AppLoungeCategroy {
+fun Category.toCategory(): AppLoungeCategory {
val id = this.browseUrl.substringAfter("cat=").substringBefore("&c=")
- return AppLoungeCategroy(
+ return AppLoungeCategory(
id = id.lowercase(),
title = this.title,
browseUrl = this.browseUrl,
diff --git a/app/src/main/java/foundation/e/apps/di/DataModule.kt b/app/src/main/java/foundation/e/apps/di/DataModule.kt
index 0dfccd751157fd2a882f63434d2da2391bbb960f..0d51d6e5796e898ff418234d026a0cdfe38558cf 100644
--- a/app/src/main/java/foundation/e/apps/di/DataModule.kt
+++ b/app/src/main/java/foundation/e/apps/di/DataModule.kt
@@ -22,6 +22,8 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
+import foundation.e.apps.data.application.AppsApi
+import foundation.e.apps.data.application.AppsApiImpl
import foundation.e.apps.data.application.CategoryApi
import foundation.e.apps.data.application.CategoryApiImpl
import foundation.e.apps.data.application.HomeApi
@@ -39,4 +41,8 @@ interface DataModule {
@Singleton
@Binds
fun getCategoryApi(categoryApiImpl: CategoryApiImpl): CategoryApi
+
+ @Singleton
+ @Binds
+ fun getAppsApi(appsApiImpl: AppsApiImpl): AppsApi
}
diff --git a/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt b/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ff72d8c191201a194f6d70bb20a2b44875eceea1
--- /dev/null
+++ b/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt
@@ -0,0 +1,489 @@
+/*
+ * Copyright MURENA SAS 2023
+ * Apps Quickly and easily install Android apps onto your device!
+ *
+ * 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.apps
+
+import android.content.Context
+import android.text.format.Formatter
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.aurora.gplayapi.Constants
+import com.aurora.gplayapi.data.models.App
+import com.aurora.gplayapi.data.models.AuthData
+import foundation.e.apps.FakePreferenceModule
+import foundation.e.apps.data.cleanapk.repositories.CleanApkRepository
+import foundation.e.apps.data.enums.FilterLevel
+import foundation.e.apps.data.enums.Origin
+import foundation.e.apps.data.enums.Status
+import foundation.e.apps.data.application.ApplicationDataManager
+import foundation.e.apps.data.application.AppsApi
+import foundation.e.apps.data.application.AppsApiImpl
+import foundation.e.apps.data.application.data.Application
+import foundation.e.apps.data.playstore.PlayStoreRepository
+import foundation.e.apps.install.pkg.PWAManagerModule
+import foundation.e.apps.install.pkg.PkgManagerModule
+import foundation.e.apps.util.MainCoroutineRule
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockedStatic
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class AppsApiTest {
+
+ // Run tasks synchronously
+ @Rule
+ @JvmField
+ val instantExecutorRule = InstantTaskExecutorRule()
+
+ // Sets the main coroutines dispatcher to a TestCoroutineScope for unit testing.
+ @ExperimentalCoroutinesApi
+ @get:Rule
+ var mainCoroutineRule = MainCoroutineRule()
+
+ @Mock
+ private lateinit var pwaManagerModule: PWAManagerModule
+
+ @Mock
+ private lateinit var pkgManagerModule: PkgManagerModule
+
+ @Mock
+ private lateinit var context: Context
+
+ @Mock
+ private lateinit var cleanApkAppsRepository: CleanApkRepository
+
+ @Mock
+ private lateinit var gPlayAPIRepository: PlayStoreRepository
+
+ private lateinit var appsApi: AppsApi
+
+ private lateinit var applicationDataManager: ApplicationDataManager
+
+ private lateinit var preferenceManagerModule: FakePreferenceModule
+
+ private lateinit var formatterMocked: MockedStatic
+
+ companion object {
+ private val AUTH_DATA = AuthData("e@e.email", "AtadyMsIAtadyM")
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.openMocks(this)
+ formatterMocked = Mockito.mockStatic(Formatter::class.java)
+ preferenceManagerModule = FakePreferenceModule(context)
+ applicationDataManager =
+ ApplicationDataManager(gPlayAPIRepository, pkgManagerModule, pwaManagerModule)
+
+ appsApi = AppsApiImpl(
+ context,
+ preferenceManagerModule,
+ gPlayAPIRepository,
+ cleanApkAppsRepository,
+ applicationDataManager,
+ )
+ }
+
+ @After
+ fun after() {
+ formatterMocked.close()
+ }
+
+ @Test
+ fun `is any app updated when new list is empty`() {
+ val oldAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.UNAVAILABLE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone"
+ ),
+ Application(
+ _id = "112",
+ status = Status.INSTALLED,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo"
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree"
+ )
+ )
+
+ val newAppList = mutableListOf()
+ val isFusedAppUpdated = appsApi.isAnyFusedAppUpdated(newAppList, oldAppList)
+ assertTrue("isAnyAppUpdated", isFusedAppUpdated)
+ }
+
+ @Test
+ fun `is any app updated when both list are empty`() {
+ val isFusedAppUpdated = appsApi.isAnyFusedAppUpdated(listOf(), listOf())
+ assertFalse("isAnyAppUpdated", isFusedAppUpdated)
+ }
+
+ @Test
+ fun `is any app updated when any app is uninstalled`() {
+ val oldAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.UNAVAILABLE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone"
+ ),
+ Application(
+ _id = "112",
+ status = Status.INSTALLED,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo"
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree"
+ )
+ )
+
+ val newAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.UNAVAILABLE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone"
+ ),
+ Application(
+ _id = "112",
+ status = Status.UNAVAILABLE,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo"
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree"
+ )
+ )
+
+ val isFusedAppUpdated = appsApi.isAnyFusedAppUpdated(newAppList, oldAppList)
+ assertTrue("isAnyFusedAppUpdated", isFusedAppUpdated)
+ }
+
+ @Test
+ fun `has any app install status changed when changed`() {
+ val oldAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.UNAVAILABLE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "112",
+ status = Status.INSTALLED,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123
+ )
+ )
+
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+
+ val isAppStatusUpdated = appsApi.isAnyAppInstallStatusChanged(oldAppList)
+ assertTrue("hasInstallStatusUpdated", isAppStatusUpdated)
+ }
+
+ @Test
+ fun `has any app install status changed when not changed`() {
+ val oldAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.UNAVAILABLE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "112",
+ status = Status.INSTALLED,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123
+ )
+ )
+
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
+ .thenReturn(
+ Status.INSTALLED
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+
+ val isAppStatusUpdated = appsApi.isAnyAppInstallStatusChanged(oldAppList)
+ assertFalse("hasInstallStatusUpdated", isAppStatusUpdated)
+ }
+
+ @Test
+ fun `has any app install status changed when installation_issue`() {
+ val oldAppList = mutableListOf(
+ Application(
+ _id = "111",
+ status = Status.INSTALLATION_ISSUE,
+ name = "Demo One",
+ package_name = "foundation.e.demoone",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "112",
+ status = Status.INSTALLED,
+ name = "Demo Two",
+ package_name = "foundation.e.demotwo",
+ latest_version_code = 123
+ ),
+ Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123
+ )
+ )
+
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
+ .thenReturn(
+ Status.INSTALLED
+ )
+ Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
+ .thenReturn(
+ Status.UNAVAILABLE
+ )
+
+ val isAppStatusUpdated = appsApi.isAnyAppInstallStatusChanged(oldAppList)
+ assertFalse("hasInstallStatusUpdated", isAppStatusUpdated)
+ }
+
+
+ @Test
+ fun getFusedAppInstallationStatusWhenPWA() {
+ val application = Application(
+ _id = "113",
+ status = Status.UNAVAILABLE,
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123,
+ is_pwa = true
+ )
+
+ Mockito.`when`(pwaManagerModule.getPwaStatus(application)).thenReturn(application.status)
+
+ val installationStatus = appsApi.getFusedAppInstallationStatus(application)
+ assertEquals("getFusedAppInstallationStatusWhenPWA", application.status, installationStatus)
+ }
+
+ @Test
+ fun getFusedAppInstallationStatus() {
+ val application = Application(
+ _id = "113",
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123,
+ )
+
+ Mockito.`when`(
+ pkgManagerModule.getPackageStatus(
+ application.package_name, application.latest_version_code
+ )
+ ).thenReturn(Status.INSTALLED)
+
+ val installationStatus = appsApi.getFusedAppInstallationStatus(application)
+ assertEquals("getFusedAppInstallationStatusWhenPWA", Status.INSTALLED, installationStatus)
+ }
+
+ @Test
+ fun `getAppFilterLevel when package name is empty`() = runTest {
+ val application = Application(
+ _id = "113",
+ name = "Demo Three",
+ package_name = "",
+ latest_version_code = 123,
+ )
+
+ val filterLevel = appsApi.getAppFilterLevel(application, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.UNKNOWN, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is CleanApk`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest()
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
+ }
+
+ private fun getFusedAppForFilterLevelTest(isFree: Boolean = true) = Application(
+ _id = "113",
+ name = "Demo Three",
+ package_name = "foundation.e.demothree",
+ latest_version_code = 123,
+ origin = Origin.CLEANAPK,
+ originalSize = -1,
+ isFree = isFree,
+ price = ""
+ )
+
+ @Test
+ fun `getAppFilterLevel when Authdata is NULL`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest()
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, null)
+ assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is restricted and paid and no price`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest(false).apply {
+ this.origin = Origin.GPLAY
+ this.restriction = Constants.Restriction.UNKNOWN
+ }
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is not_restricted and paid and no price`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest(false).apply {
+ this.origin = Origin.GPLAY
+ this.restriction = Constants.Restriction.NOT_RESTRICTED
+ }
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is restricted and getAppDetails and getDownloadDetails returns success`() =
+ runTest {
+ val fusedApp = getFusedAppForFilterLevelTest().apply {
+ this.origin = Origin.GPLAY
+ this.restriction = Constants.Restriction.UNKNOWN
+ }
+
+ Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
+ .thenReturn(App(fusedApp.package_name))
+
+ Mockito.`when`(
+ gPlayAPIRepository.getDownloadInfo(
+ fusedApp.package_name,
+ fusedApp.latest_version_code,
+ fusedApp.offer_type,
+ )
+ ).thenReturn(listOf())
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is restricted and getAppDetails throws exception`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest().apply {
+ this.origin = Origin.GPLAY
+ this.restriction = Constants.Restriction.UNKNOWN
+ }
+
+ Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
+ .thenThrow(RuntimeException())
+
+ Mockito.`when`(
+ gPlayAPIRepository.getDownloadInfo(
+ fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type
+ )
+ ).thenReturn(listOf())
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.DATA, filterLevel)
+ }
+
+ @Test
+ fun `getAppFilterLevel when app is restricted and getDownoadInfo throws exception`() = runTest {
+ val fusedApp = getFusedAppForFilterLevelTest().apply {
+ this.origin = Origin.GPLAY
+ this.restriction = Constants.Restriction.UNKNOWN
+ }
+
+ Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
+ .thenReturn(App(fusedApp.package_name))
+
+ Mockito.`when`(
+ gPlayAPIRepository.getDownloadInfo(
+ fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type
+ )
+ ).thenThrow(RuntimeException())
+
+ val filterLevel = appsApi.getAppFilterLevel(fusedApp, AUTH_DATA)
+ assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
+ }
+}
diff --git a/app/src/test/java/foundation/e/apps/fused/ApplicationApiImplTest.kt b/app/src/test/java/foundation/e/apps/fused/ApplicationApiImplTest.kt
index 39092ecef5963622cd2f62a1b6ee9d040ffd12d6..b29ece50a07ea52340507dbc5c7c1ae11dd0510b 100644
--- a/app/src/test/java/foundation/e/apps/fused/ApplicationApiImplTest.kt
+++ b/app/src/test/java/foundation/e/apps/fused/ApplicationApiImplTest.kt
@@ -35,6 +35,9 @@ import foundation.e.apps.data.enums.Origin
import foundation.e.apps.data.enums.ResultStatus
import foundation.e.apps.data.enums.Status
import foundation.e.apps.data.application.ApplicationApiImpl
+import foundation.e.apps.data.application.ApplicationDataManager
+import foundation.e.apps.data.application.AppsApi
+import foundation.e.apps.data.application.AppsApiImpl
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.utils.CategoryType
import foundation.e.apps.data.playstore.PlayStoreRepository
@@ -99,6 +102,10 @@ class ApplicationApiImplTest {
@Mock
private lateinit var gPlayAPIRepository: PlayStoreRepository
+ private lateinit var appsApi: AppsApi
+
+ private lateinit var applicationDataManager: ApplicationDataManager
+
private lateinit var preferenceManagerModule: FakePreferenceModule
private lateinit var formatterMocked: MockedStatic
@@ -112,14 +119,24 @@ class ApplicationApiImplTest {
MockitoAnnotations.openMocks(this)
formatterMocked = Mockito.mockStatic(Formatter::class.java)
preferenceManagerModule = FakePreferenceModule(context)
+ applicationDataManager =
+ ApplicationDataManager(gPlayAPIRepository, pkgManagerModule, pwaManagerModule)
+
+ appsApi = AppsApiImpl(
+ context,
+ preferenceManagerModule,
+ gPlayAPIRepository,
+ cleanApkAppsRepository,
+ applicationDataManager,
+ )
+
fusedAPIImpl = ApplicationApiImpl(
- pkgManagerModule,
- pwaManagerModule,
+ appsApi,
preferenceManagerModule,
gPlayAPIRepository,
cleanApkAppsRepository,
cleanApkPWARepository,
- context
+ applicationDataManager
)
}
@@ -128,275 +145,6 @@ class ApplicationApiImplTest {
formatterMocked.close()
}
- @Test
- fun `is any app updated when new list is empty`() {
- val oldAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.UNAVAILABLE,
- name = "Demo One",
- package_name = "foundation.e.demoone"
- ),
- Application(
- _id = "112",
- status = Status.INSTALLED,
- name = "Demo Two",
- package_name = "foundation.e.demotwo"
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree"
- )
- )
-
- val newAppList = mutableListOf()
- val isFusedAppUpdated = fusedAPIImpl.isAnyFusedAppUpdated(newAppList, oldAppList)
- assertTrue("isAnyAppUpdated", isFusedAppUpdated)
- }
-
- @Test
- fun `is any app updated when both list are empty`() {
- val isFusedAppUpdated = fusedAPIImpl.isAnyFusedAppUpdated(listOf(), listOf())
- assertFalse("isAnyAppUpdated", isFusedAppUpdated)
- }
-
- @Test
- fun `is any app updated when any app is uninstalled`() {
- val oldAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.UNAVAILABLE,
- name = "Demo One",
- package_name = "foundation.e.demoone"
- ),
- Application(
- _id = "112",
- status = Status.INSTALLED,
- name = "Demo Two",
- package_name = "foundation.e.demotwo"
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree"
- )
- )
-
- val newAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.UNAVAILABLE,
- name = "Demo One",
- package_name = "foundation.e.demoone"
- ),
- Application(
- _id = "112",
- status = Status.UNAVAILABLE,
- name = "Demo Two",
- package_name = "foundation.e.demotwo"
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree"
- )
- )
-
- val isFusedAppUpdated = fusedAPIImpl.isAnyFusedAppUpdated(newAppList, oldAppList)
- assertTrue("isAnyFusedAppUpdated", isFusedAppUpdated)
- }
-
- @Test
- fun `has any app install status changed when changed`() {
- val oldAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.UNAVAILABLE,
- name = "Demo One",
- package_name = "foundation.e.demoone",
- latest_version_code = 123
- ),
- Application(
- _id = "112",
- status = Status.INSTALLED,
- name = "Demo Two",
- package_name = "foundation.e.demotwo",
- latest_version_code = 123
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree",
- latest_version_code = 123
- )
- )
-
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
-
- val isAppStatusUpdated = fusedAPIImpl.isAnyAppInstallStatusChanged(oldAppList)
- assertTrue("hasInstallStatusUpdated", isAppStatusUpdated)
- }
-
- @Test
- fun `has any app install status changed when not changed`() {
- val oldAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.UNAVAILABLE,
- name = "Demo One",
- package_name = "foundation.e.demoone",
- latest_version_code = 123
- ),
- Application(
- _id = "112",
- status = Status.INSTALLED,
- name = "Demo Two",
- package_name = "foundation.e.demotwo",
- latest_version_code = 123
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree",
- latest_version_code = 123
- )
- )
-
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
- .thenReturn(
- Status.INSTALLED
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
-
- val isAppStatusUpdated = fusedAPIImpl.isAnyAppInstallStatusChanged(oldAppList)
- assertFalse("hasInstallStatusUpdated", isAppStatusUpdated)
- }
-
- @Test
- fun `has any app install status changed when installation_issue`() {
- val oldAppList = mutableListOf(
- Application(
- _id = "111",
- status = Status.INSTALLATION_ISSUE,
- name = "Demo One",
- package_name = "foundation.e.demoone",
- latest_version_code = 123
- ),
- Application(
- _id = "112",
- status = Status.INSTALLED,
- name = "Demo Two",
- package_name = "foundation.e.demotwo",
- latest_version_code = 123
- ),
- Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree",
- latest_version_code = 123
- )
- )
-
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demoone"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demotwo"), eq(123)))
- .thenReturn(
- Status.INSTALLED
- )
- Mockito.`when`(pkgManagerModule.getPackageStatus(eq("foundation.e.demothree"), eq(123)))
- .thenReturn(
- Status.UNAVAILABLE
- )
-
- val isAppStatusUpdated = fusedAPIImpl.isAnyAppInstallStatusChanged(oldAppList)
- assertFalse("hasInstallStatusUpdated", isAppStatusUpdated)
- }
-
-
- @Test
- fun getFusedAppInstallationStatusWhenPWA() {
- val application = Application(
- _id = "113",
- status = Status.UNAVAILABLE,
- name = "Demo Three",
- package_name = "foundation.e.demothree",
- latest_version_code = 123,
- is_pwa = true
- )
-
- Mockito.`when`(pwaManagerModule.getPwaStatus(application)).thenReturn(application.status)
-
- val installationStatus = fusedAPIImpl.getFusedAppInstallationStatus(application)
- assertEquals("getFusedAppInstallationStatusWhenPWA", application.status, installationStatus)
- }
-
- @Test
- fun getFusedAppInstallationStatus() {
- val application = Application(
- _id = "113",
- name = "Demo Three",
- package_name = "foundation.e.demothree",
- latest_version_code = 123,
- )
-
- Mockito.`when`(
- pkgManagerModule.getPackageStatus(
- application.package_name, application.latest_version_code
- )
- ).thenReturn(Status.INSTALLED)
-
- val installationStatus = fusedAPIImpl.getFusedAppInstallationStatus(application)
- assertEquals("getFusedAppInstallationStatusWhenPWA", Status.INSTALLED, installationStatus)
- }
-
- @Test
- fun `getAppFilterLevel when package name is empty`() = runTest {
- val application = Application(
- _id = "113",
- name = "Demo Three",
- package_name = "",
- latest_version_code = 123,
- )
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(application, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.UNKNOWN, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is CleanApk`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest()
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
- }
-
private fun getFusedAppForFilterLevelTest(isFree: Boolean = true) = Application(
_id = "113",
name = "Demo Three",
@@ -408,99 +156,6 @@ class ApplicationApiImplTest {
price = ""
)
- @Test
- fun `getAppFilterLevel when Authdata is NULL`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest()
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, null)
- assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is restricted and paid and no price`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest(false).apply {
- this.origin = Origin.GPLAY
- this.restriction = Constants.Restriction.UNKNOWN
- }
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is not_restricted and paid and no price`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest(false).apply {
- this.origin = Origin.GPLAY
- this.restriction = Constants.Restriction.NOT_RESTRICTED
- }
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is restricted and getAppDetails and getDownloadDetails returns success`() =
- runTest {
- val fusedApp = getFusedAppForFilterLevelTest().apply {
- this.origin = Origin.GPLAY
- this.restriction = Constants.Restriction.UNKNOWN
- }
-
- Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
- .thenReturn(App(fusedApp.package_name))
-
- Mockito.`when`(
- gPlayAPIRepository.getDownloadInfo(
- fusedApp.package_name,
- fusedApp.latest_version_code,
- fusedApp.offer_type,
- )
- ).thenReturn(listOf())
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.NONE, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is restricted and getAppDetails throws exception`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest().apply {
- this.origin = Origin.GPLAY
- this.restriction = Constants.Restriction.UNKNOWN
- }
-
- Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
- .thenThrow(RuntimeException())
-
- Mockito.`when`(
- gPlayAPIRepository.getDownloadInfo(
- fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type
- )
- ).thenReturn(listOf())
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.DATA, filterLevel)
- }
-
- @Test
- fun `getAppFilterLevel when app is restricted and getDownoadInfo throws exception`() = runTest {
- val fusedApp = getFusedAppForFilterLevelTest().apply {
- this.origin = Origin.GPLAY
- this.restriction = Constants.Restriction.UNKNOWN
- }
-
- Mockito.`when`(gPlayAPIRepository.getAppDetails(fusedApp.package_name))
- .thenReturn(App(fusedApp.package_name))
-
- Mockito.`when`(
- gPlayAPIRepository.getDownloadInfo(
- fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type
- )
- ).thenThrow(RuntimeException())
-
- val filterLevel = fusedAPIImpl.getAppFilterLevel(fusedApp, AUTH_DATA)
- assertEquals("getAppFilterLevel", FilterLevel.UI, filterLevel)
- }
-
@Ignore("Dependencies are not mockable")
@Test
fun `getSearchResult When all sources are selected`() = runTest {
@@ -647,7 +302,8 @@ class ApplicationApiImplTest {
fun testSearchResultWhenDataIsLimited() = runTest {
preferenceManagerModule.isGplaySelectedFake = true
formatterMocked.`when` { Formatter.formatFileSize(any(), any()) }.thenReturn("15MB")
- Mockito.`when`(gPlayAPIRepository.getSearchResult(anyString(), eq(null))).thenReturn(Pair(emptyList(), mutableSetOf()))
+ Mockito.`when`(gPlayAPIRepository.getSearchResult(anyString(), eq(null)))
+ .thenReturn(Pair(emptyList(), mutableSetOf()))
Mockito.`when`(cleanApkAppsRepository.getAppDetails(any())).thenReturn(null)
var isEventBusTriggered = false
diff --git a/app/src/test/java/foundation/e/apps/fused/ApplicationApiRepositoryTest.kt b/app/src/test/java/foundation/e/apps/fused/ApplicationApiRepositoryTest.kt
index 85fa1333bc5ed4292ca45156d8f733196c505306..3d59ee61d1d5155c81f6e115493a1b23a63af9a8 100644
--- a/app/src/test/java/foundation/e/apps/fused/ApplicationApiRepositoryTest.kt
+++ b/app/src/test/java/foundation/e/apps/fused/ApplicationApiRepositoryTest.kt
@@ -19,6 +19,7 @@ package foundation.e.apps.fused
import foundation.e.apps.data.application.ApplicationRepository
import foundation.e.apps.data.application.ApplicationApiImpl
+import foundation.e.apps.data.application.AppsApi
import foundation.e.apps.data.application.CategoryApi
import foundation.e.apps.data.application.HomeApi
import org.junit.Assert.assertTrue
@@ -33,27 +34,32 @@ class ApplicationApiRepositoryTest {
private lateinit var applicationRepository: ApplicationRepository
@Mock
private lateinit var fusedAPIImpl: ApplicationApiImpl
+
@Mock
private lateinit var homeApi: HomeApi
+
@Mock
private lateinit var categoryApi: CategoryApi
+ @Mock
+ private lateinit var appsApi: AppsApi
+
@Before
fun setup() {
MockitoAnnotations.openMocks(this)
- applicationRepository = ApplicationRepository(fusedAPIImpl, homeApi, categoryApi)
+ applicationRepository = ApplicationRepository(fusedAPIImpl, homeApi, categoryApi, appsApi)
}
@Test
fun isAnyAppUpdated_ReturnsTrue() {
- Mockito.`when`(fusedAPIImpl.isAnyFusedAppUpdated(any(), any())).thenReturn(true)
+ Mockito.`when`(appsApi.isAnyFusedAppUpdated(any(), any())).thenReturn(true)
val isAnyAppUpdated = applicationRepository.isAnyFusedAppUpdated(listOf(), listOf())
assertTrue("isAnyAppUpdated", isAnyAppUpdated)
}
@Test
fun isAnyInstallStatusChanged_ReturnsTrue() {
- Mockito.`when`(fusedAPIImpl.isAnyAppInstallStatusChanged(any())).thenReturn(true)
+ Mockito.`when`(appsApi.isAnyAppInstallStatusChanged(any())).thenReturn(true)
val isAnyAppUpdated = applicationRepository.isAnyAppInstallStatusChanged(listOf())
assertTrue("isAnyAppUpdated", isAnyAppUpdated)
}
diff --git a/detekt.yml b/detekt.yml
index 4f6148616b2b1866640658a943d951c6bebe75fc..773174aa03128a8507e97a7662dc88e59963a973 100644
--- a/detekt.yml
+++ b/detekt.yml
@@ -13,3 +13,9 @@ style:
ForbiddenComment:
active: false
+
+# Complexity rules
+complexity:
+
+ TooManyFunctions:
+ ignorePrivate: true