diff --git a/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt b/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt index 877d74bb86797f5a84254f675e956594f4410532..e48d717e25a477f3459abfea77c194f9deb65fb2 100644 --- a/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt +++ b/app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt @@ -21,12 +21,13 @@ package foundation.e.apps.data.application import com.aurora.gplayapi.Constants import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.application.data.Home +import foundation.e.apps.data.application.utils.AppVisibilityResolver import foundation.e.apps.data.enums.FilterLevel import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.Status -import foundation.e.apps.data.playstore.PlayStoreRepository import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.pkg.PwaManager +import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @@ -34,7 +35,7 @@ import javax.inject.Singleton class ApplicationDataManager @Inject constructor( private val appLoungePackageManager: AppLoungePackageManager, private val pwaManager: PwaManager, - private val playStoreRepository: PlayStoreRepository + private val visibilityFetcher: AppVisibilityResolver, ) { suspend fun updateFilterLevel(application: Application) { application.filterLevel = getAppFilterLevel(application) @@ -56,6 +57,7 @@ class ApplicationDataManager @Inject constructor( } suspend fun getAppFilterLevel(application: Application): FilterLevel { + Timber.i("getAppFilterLevel: $application") return when { application.package_name.isBlank() -> FilterLevel.UNKNOWN !application.isFree && application.price.isBlank() -> FilterLevel.UI @@ -72,12 +74,8 @@ class ApplicationDataManager @Inject constructor( return application.restriction != Constants.Restriction.NOT_RESTRICTED } - /* - * Some apps are not visible because of geo-restriction, banning, etc. - */ private suspend fun isApplicationVisible(application: Application): Boolean { - val appDetails = playStoreRepository.getAppDetailsWeb(application.package_name) - return appDetails != null + return visibilityFetcher.isApplicationVisible(application) } fun updateStatus(application: Application) { diff --git a/app/src/main/java/foundation/e/apps/data/application/utils/AppVisibilityResolver.kt b/app/src/main/java/foundation/e/apps/data/application/utils/AppVisibilityResolver.kt new file mode 100644 index 0000000000000000000000000000000000000000..55621c99844a821d54ec53a477814b3cd87dab83 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/data/application/utils/AppVisibilityResolver.kt @@ -0,0 +1,31 @@ +package foundation.e.apps.data.application.utils + +import android.content.Context +import com.aurora.gplayapi.helpers.web.WebAppDetailsHelper +import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.handleNetworkResult +import foundation.e.apps.data.playstore.utils.GPlayHttpClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AppVisibilityResolver @Inject constructor( + private val gPlayHttpClient: GPlayHttpClient, + @ApplicationContext private val context: Context +) { + suspend fun isApplicationVisible(application: Application): Boolean { + val webAppDetailsHelper = WebAppDetailsHelper().using(gPlayHttpClient) + + val appDetails = withContext(Dispatchers.IO) { + val result = + handleNetworkResult { webAppDetailsHelper.getAppByPackageName(application.package_name) } + val app = result.data ?: return@withContext null + + app.toApplication(context) + } + return appDetails != null + } +} diff --git a/app/src/main/java/foundation/e/apps/data/login/AuthenticatorRepository.kt b/app/src/main/java/foundation/e/apps/data/login/AuthenticatorRepository.kt index 1aa297978cb88c6edad5194866db334d27aa6e1d..c8efb84fc1119f20de0af0cd7fb5979a182b6d20 100644 --- a/app/src/main/java/foundation/e/apps/data/login/AuthenticatorRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/login/AuthenticatorRepository.kt @@ -45,13 +45,13 @@ class AuthenticatorRepository @Inject constructor( appLoungeDataStore.saveAuthData(auth) } - suspend fun getAuthObjects(clearAuthTypes: List = listOf()): List { + suspend fun fetchAuthObjects(authTypes: List = listOf()): List { val authObjectsLocal = ArrayList() for (authenticator in authenticators) { if (!authenticator.isStoreActive()) continue - if (authenticator::class.java.simpleName in clearAuthTypes) { + if (authenticator::class.java.simpleName in authTypes) { authenticator.logout() } diff --git a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt index f8d1968ccaf04d48c69db9a3b1a094f2aaf9684d..c97bdbd65102c772bde10f0688d168e7e5cea022 100644 --- a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt @@ -29,12 +29,10 @@ import com.aurora.gplayapi.helpers.ContentRatingHelper import com.aurora.gplayapi.helpers.PurchaseHelper import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Chart import com.aurora.gplayapi.helpers.contracts.TopChartsContract.Type -import com.aurora.gplayapi.helpers.web.WebAppDetailsHelper import com.aurora.gplayapi.helpers.web.WebCategoryHelper import com.aurora.gplayapi.helpers.web.WebCategoryStreamHelper import com.aurora.gplayapi.helpers.web.WebSearchHelper import com.aurora.gplayapi.helpers.web.WebTopChartsHelper -import dagger.Lazy import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.data.StoreRepository @@ -44,7 +42,6 @@ import foundation.e.apps.data.application.data.Home import foundation.e.apps.data.application.utils.CategoryType import foundation.e.apps.data.application.utils.toApplication import foundation.e.apps.data.enums.Source -import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.AuthenticatorRepository import foundation.e.apps.data.login.PlayStoreAuthenticator import foundation.e.apps.data.playstore.utils.GPlayHttpClient @@ -60,7 +57,7 @@ class PlayStoreRepository @Inject constructor( @ApplicationContext private val context: Context, private val gPlayHttpClient: GPlayHttpClient, private val authenticatorRepository: AuthenticatorRepository, - private val applicationDataManager: Lazy // Used Lazy to break circular dependency + private val applicationDataManager: ApplicationDataManager ) : StoreRepository { override suspend fun getHomeScreenData(list: MutableList): List { @@ -79,8 +76,8 @@ class PlayStoreRepository @Inject constructor( homeScreenData.map { val fusedApps = it.value.map { app -> app.apply { - applicationDataManager.get().updateStatus(this) - applicationDataManager.get().updateFilterLevel(this) + applicationDataManager.updateStatus(this) + applicationDataManager.updateFilterLevel(this) source = Source.PLAY_STORE } } @@ -177,19 +174,7 @@ class PlayStoreRepository @Inject constructor( private suspend fun refreshPlayStoreAuthentication() { Timber.i("Refreshing authentication.") - authenticatorRepository.getAuthObjects(listOf(PlayStoreAuthenticator::class.java.simpleName)) - } - - suspend fun getAppDetailsWeb(packageName: String): Application? { - val webAppDetailsHelper = WebAppDetailsHelper().using(gPlayHttpClient) - - return withContext(Dispatchers.IO) { - val result = - handleNetworkResult { webAppDetailsHelper.getAppByPackageName(packageName) } - val app = result.data ?: return@withContext null - - app.toApplication(context) - } + authenticatorRepository.fetchAuthObjects(listOf(PlayStoreAuthenticator::class.java.simpleName)) } private fun isEmulator(): Boolean { diff --git a/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt b/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt index 16cb8c28313d9533d8bcef30449270fcc280e7e4..211e45bdfe3813c8dd448692c1ea669a5b467feb 100644 --- a/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt @@ -59,7 +59,7 @@ class LoginViewModel @Inject constructor( */ fun startLoginFlow(clearList: List = listOf()) { viewModelScope.launch { - val authObjectsLocal = authenticatorRepository.getAuthObjects(clearList) + val authObjectsLocal = authenticatorRepository.fetchAuthObjects(clearList) authObjects.postValue(authObjectsLocal) } } diff --git a/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt b/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt index abe3d4e64bd0b455e83a44746cdbdc5ed4ced77a..92f2dccfa3b9559d002da02037ac78eab6ee4228 100644 --- a/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt +++ b/app/src/test/java/foundation/e/apps/apps/AppsApiTest.kt @@ -22,12 +22,12 @@ import android.content.Context import android.text.format.Formatter import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.aurora.gplayapi.Constants -import foundation.e.apps.FakeAppLoungePreference import foundation.e.apps.data.Stores import foundation.e.apps.data.application.ApplicationDataManager import foundation.e.apps.data.application.apps.AppsApi import foundation.e.apps.data.application.apps.AppsApiImpl import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.application.utils.AppVisibilityResolver import foundation.e.apps.data.enums.FilterLevel import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.Status @@ -48,6 +48,7 @@ import org.mockito.Mock import org.mockito.MockedStatic import org.mockito.Mockito import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any import org.mockito.kotlin.eq @OptIn(ExperimentalCoroutinesApi::class) @@ -78,21 +79,21 @@ class AppsApiTest { @Mock private lateinit var stores: Stores + @Mock + private lateinit var visibilityFetcher: AppVisibilityResolver + private lateinit var appsApi: AppsApi private lateinit var applicationDataManager: ApplicationDataManager - private lateinit var preferenceManagerModule: FakeAppLoungePreference - private lateinit var formatterMocked: MockedStatic @Before fun setup() { MockitoAnnotations.openMocks(this) formatterMocked = Mockito.mockStatic(Formatter::class.java) - preferenceManagerModule = FakeAppLoungePreference(context) applicationDataManager = - ApplicationDataManager(appLoungePackageManager, pwaManager, playStoreRepository) + ApplicationDataManager(appLoungePackageManager, pwaManager, visibilityFetcher) appsApi = AppsApiImpl( stores, applicationDataManager @@ -462,13 +463,14 @@ class AppsApiTest { @Test fun `getAppFilterLevel when app is restricted and getAppDetails and getDownloadDetails returns success`() = runTest { + val fusedApp = getFusedAppForFilterLevelTest().apply { this.source = Source.PLAY_STORE this.restriction = Constants.Restriction.UNKNOWN } - Mockito.`when`(playStoreRepository.getAppDetailsWeb(fusedApp.package_name)) - .thenReturn(Application(fusedApp.package_name)) + Mockito.`when`(visibilityFetcher.isApplicationVisible(any())) + .thenReturn(true) Mockito.`when`( playStoreRepository.getDownloadInfo( diff --git a/app/src/test/java/foundation/e/apps/category/CategoryApiTest.kt b/app/src/test/java/foundation/e/apps/category/CategoryApiTest.kt index 7c522dee32965cd15e4175a5e51661f937b41659..bf8798149bbe03ca13dc011bcfc4073d466eb958 100644 --- a/app/src/test/java/foundation/e/apps/category/CategoryApiTest.kt +++ b/app/src/test/java/foundation/e/apps/category/CategoryApiTest.kt @@ -28,6 +28,7 @@ import foundation.e.apps.data.Stores import foundation.e.apps.data.application.ApplicationDataManager import foundation.e.apps.data.application.category.CategoryApi import foundation.e.apps.data.application.category.CategoryApiImpl +import foundation.e.apps.data.application.utils.AppVisibilityResolver import foundation.e.apps.data.application.utils.CategoryType import foundation.e.apps.data.cleanapk.data.categories.Categories import foundation.e.apps.data.cleanapk.repositories.CleanApkAppsRepository @@ -85,6 +86,9 @@ class CategoryApiTest { @Mock private lateinit var appLoungePreference: AppLoungePreference + @Mock + private lateinit var visibilityFetcher: AppVisibilityResolver + private lateinit var fakeStores: Stores private lateinit var categoryApi: CategoryApi @@ -93,7 +97,7 @@ class CategoryApiTest { fun setup() { MockitoAnnotations.openMocks(this) val applicationDataManager = - ApplicationDataManager(appLoungePackageManager, pwaManager, playStoreRepository) + ApplicationDataManager(appLoungePackageManager, pwaManager, visibilityFetcher) fakeStores = Stores(playStoreRepository, cleanApkAppsRepository, cleanApkPWARepository, appLoungePreference) diff --git a/app/src/test/java/foundation/e/apps/fused/SearchApiImplTest.kt b/app/src/test/java/foundation/e/apps/fused/SearchApiImplTest.kt index 24107984a45d153435c311384ee44a7c3a6a2e78..c06469b7241fb086f038db63739c32df3f4050d3 100644 --- a/app/src/test/java/foundation/e/apps/fused/SearchApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/fused/SearchApiImplTest.kt @@ -30,6 +30,7 @@ import foundation.e.apps.data.application.apps.AppsApi import foundation.e.apps.data.application.apps.AppsApiImpl import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.application.search.SearchApiImpl +import foundation.e.apps.data.application.utils.AppVisibilityResolver import foundation.e.apps.data.cleanapk.data.search.Search import foundation.e.apps.data.cleanapk.repositories.CleanApkAppsRepository import foundation.e.apps.data.cleanapk.repositories.CleanApkPwaRepository @@ -91,6 +92,9 @@ class SearchApiImplTest { @Mock private lateinit var stores: Stores + @Mock + private lateinit var visibilityFetcher: AppVisibilityResolver + private lateinit var appsApi: AppsApi private lateinit var applicationDataManager: ApplicationDataManager @@ -105,7 +109,7 @@ class SearchApiImplTest { formatterMocked = Mockito.mockStatic(Formatter::class.java) preferenceManagerModule = FakeAppLoungePreference(context) applicationDataManager = - ApplicationDataManager(appLoungePackageManager, pwaManager, playStoreRepository) + ApplicationDataManager(appLoungePackageManager, pwaManager, visibilityFetcher) val appSourcesContainer = AppSourcesContainer(playStoreRepository, cleanApkAppsRepository, cleanApkPWARepository) appsApi = AppsApiImpl(