Loading app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt +0 −4 Original line number Diff line number Diff line Loading @@ -29,10 +29,6 @@ interface ApplicationApi { fun getApplicationCategoryPreference(): List<String> suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> /* * Return three elements from the function. * - List<FusedCategory> : List of categories. Loading app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt +10 −214 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ package foundation.e.apps.data.application import android.content.Context import android.text.format.Formatter import androidx.lifecycle.LiveData import androidx.lifecycle.liveData import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App Loading @@ -32,28 +30,26 @@ 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.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.data.cleanapk.data.categories.Categories import foundation.e.apps.data.cleanapk.data.home.HomeScreen 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.Source 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.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.fusedDownload.models.FusedDownload import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.AuthObject Loading @@ -66,8 +62,6 @@ 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.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import retrofit2.Response import timber.log.Timber Loading @@ -76,7 +70,6 @@ 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 import foundation.e.apps.data.cleanapk.data.home.Home as CleanApkHome typealias FusedHomeDeferred = Deferred<ResultSupreme<List<Home>>> Loading @@ -95,7 +88,6 @@ class ApplicationApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" private const val THRESHOLD_LIMITED_RESULT_HOME_PAGE = 4 private const val KEYWORD_TEST_SEARCH = "facebook" } Loading @@ -107,97 +99,6 @@ class ApplicationApiImpl @Inject constructor( return prefs } override suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> { val list = mutableListOf<Home>() var resultGplay: FusedHomeDeferred? = null var resultOpenSource: FusedHomeDeferred? = null var resultPWA: FusedHomeDeferred? = null return liveData { coroutineScope { if (preferenceManagerModule.isGplaySelected()) { resultGplay = async { loadHomeData(list, Source.GPLAY, authData) } } if (preferenceManagerModule.isOpenSourceSelected()) { resultOpenSource = async { loadHomeData(list, Source.OPEN, authData) } } if (preferenceManagerModule.isPWASelected()) { resultPWA = async { loadHomeData(list, Source.PWA, authData) } } resultGplay?.await()?.let { emit(it) } resultOpenSource?.await()?.let { emit(it) } resultPWA?.await()?.let { emit(it) } } } } private suspend fun loadHomeData( priorList: MutableList<Home>, source: Source, authData: AuthData, ): ResultSupreme<List<Home>> { val result = when (source) { Source.GPLAY -> handleNetworkResult<List<Home>> { priorList.addAll(fetchGPlayHome(authData)) priorList } Source.OPEN -> handleNetworkResult { val response = (cleanApkAppsRepository.getHomeScreenData() as Response<HomeScreen>).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } priorList } Source.PWA -> handleNetworkResult { val response = (cleanApkPWARepository.getHomeScreenData() as Response<HomeScreen>).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } priorList } } setHomeErrorMessage(result.getResultStatus(), source) priorList.sortByDescending { when (it.source) { APP_TYPE_OPEN -> 2 APP_TYPE_PWA -> 1 else -> 3 } } return ResultSupreme.create(result.getResultStatus(), priorList) } private fun setHomeErrorMessage(apiStatus: ResultStatus, source: Source) { if (apiStatus != ResultStatus.OK) { apiStatus.message = when (source) { Source.GPLAY -> ("GPlay home loading error\n" + apiStatus.message).trim() Source.OPEN -> ("Open Source home loading error\n" + apiStatus.message).trim() Source.PWA -> ("PWA home loading error\n" + apiStatus.message).trim() } } } /* * Return three elements from the function. * - List<FusedCategory> : List of categories. Loading Loading @@ -756,7 +657,7 @@ class ApplicationApiImpl @Inject constructor( /* * Handy method to run on an instance of FusedApp to update its filter level. */ private suspend fun Application.updateFilterLevel(authData: AuthData?) { suspend fun Application.updateFilterLevel(authData: AuthData?) { this.filterLevel = getAppFilterLevel(this, authData) } Loading Loading @@ -1065,111 +966,6 @@ class ApplicationApiImpl @Inject constructor( return gPlayFusedApp } /* * Home screen-related internal functions */ private suspend fun generateCleanAPKHome(home: CleanApkHome, appType: String): List<Home> { val list = mutableListOf<Home>() val headings = if (appType == APP_TYPE_OPEN) { getOpenSourceHomeCategories() } else { getPWAHomeCategories() } headings.forEach { (key, value) -> when (key) { "top_updated_apps" -> { prepareApps(home.top_updated_apps, list, value) } "top_updated_games" -> { prepareApps(home.top_updated_games, list, value) } "popular_apps" -> { prepareApps(home.popular_apps, list, value) } "popular_games" -> { prepareApps(home.popular_games, list, value) } "popular_apps_in_last_24_hours" -> { prepareApps(home.popular_apps_in_last_24_hours, list, value) } "popular_games_in_last_24_hours" -> { prepareApps(home.popular_games_in_last_24_hours, list, value) } "discover" -> { prepareApps(home.discover, list, value) } } } return list.map { it.source = appType it } } private suspend fun prepareApps( appList: List<Application>, list: MutableList<Home>, value: String ) { if (appList.isNotEmpty()) { appList.forEach { it.updateStatus() it.updateType() it.updateFilterLevel(null) } list.add(Home(value, appList)) } } private fun getPWAHomeCategories() = mapOf( "popular_apps" to context.getString(R.string.popular_apps), "popular_games" to context.getString(R.string.popular_games), "discover" to context.getString(R.string.discover_pwa) ) private fun getOpenSourceHomeCategories() = mapOf( "top_updated_apps" to context.getString(R.string.top_updated_apps), "top_updated_games" to context.getString(R.string.top_updated_games), "popular_apps_in_last_24_hours" to context.getString(R.string.popular_apps_in_last_24_hours), "popular_games_in_last_24_hours" to context.getString(R.string.popular_games_in_last_24_hours), "discover" to context.getString(R.string.discover) ) private suspend fun fetchGPlayHome(authData: AuthData): List<Home> { val list = mutableListOf<Home>() val gplayHomeData = gplayRepository.getHomeScreenData() as Map<String, List<App>> gplayHomeData.map { val fusedApps = it.value.map { app -> app.transformToFusedApp().apply { updateFilterLevel(authData) } } list.add(Home(it.key, fusedApps)) } handleLimitedResult(list) Timber.d("HomePageData: $list") return list } private fun handleLimitedResult(homeList: List<Home>) { val gplayHomes = homeList.filter { fusedHome -> fusedHome.source.isEmpty() } val hasGplayLimitedResult = gplayHomes.any { fusedHome -> fusedHome.list.size < THRESHOLD_LIMITED_RESULT_HOME_PAGE } if (hasGplayLimitedResult) { Timber.w("Limited result is found for homepage...") refreshToken() } } private fun refreshToken() { MainScope().launch { EventBus.invokeEvent( Loading app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.application import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.application.data.Home 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.playstore.PlayStoreRepository import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @Singleton class ApplicationDataManager @Inject constructor( @Named("gplayRepository") private val gplayRepository: PlayStoreRepository, private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule ) { suspend fun updateFilterLevel(authData: AuthData?, application: Application) { application.filterLevel = getAppFilterLevel(application, authData) } suspend fun prepareApps( appList: List<Application>, list: MutableList<Home>, value: String ) { if (appList.isNotEmpty()) { appList.forEach { it.updateType() updateStatus(it) updateFilterLevel(null, it) } list.add(Home(value, appList)) } } private 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 } } private fun isRestricted(application: Application): Boolean { return application.restriction != Constants.Restriction.NOT_RESTRICTED } /** * 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 } fun updateStatus(application: Application) { if (application.status != Status.INSTALLATION_ISSUE) { application.status = getFusedAppInstallationStatus(application) } } /** * 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 if (application.is_pwa) { pwaManagerModule.getPwaStatus(application) } else { pkgManagerModule.getPackageStatus(application.package_name, application.latest_version_code) } } } app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt +5 −2 Original line number Diff line number Diff line Loading @@ -37,10 +37,13 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton class ApplicationRepository @Inject constructor(private val applicationAPIImpl: ApplicationApi) { class ApplicationRepository @Inject constructor( private val applicationAPIImpl: ApplicationApi, private val homeApi: HomeApi ) { suspend fun getHomeScreenData(authData: AuthData): LiveData<ResultSupreme<List<Home>>> { return applicationAPIImpl.getHomeScreenData(authData) return homeApi.getHomeScreenData(authData) } fun getApplicationCategoryPreference(): List<String> { Loading app/src/main/java/foundation/e/apps/data/application/HomeApi.kt 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.application import androidx.lifecycle.LiveData import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.application.data.Home interface HomeApi { suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> } Loading
app/src/main/java/foundation/e/apps/data/application/ApplicationApi.kt +0 −4 Original line number Diff line number Diff line Loading @@ -29,10 +29,6 @@ interface ApplicationApi { fun getApplicationCategoryPreference(): List<String> suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> /* * Return three elements from the function. * - List<FusedCategory> : List of categories. Loading
app/src/main/java/foundation/e/apps/data/application/ApplicationApiImpl.kt +10 −214 Original line number Diff line number Diff line Loading @@ -20,8 +20,6 @@ package foundation.e.apps.data.application import android.content.Context import android.text.format.Formatter import androidx.lifecycle.LiveData import androidx.lifecycle.liveData import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App Loading @@ -32,28 +30,26 @@ 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.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.data.cleanapk.data.categories.Categories import foundation.e.apps.data.cleanapk.data.home.HomeScreen 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.Source 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.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.fusedDownload.models.FusedDownload import foundation.e.apps.data.handleNetworkResult import foundation.e.apps.data.login.AuthObject Loading @@ -66,8 +62,6 @@ 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.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import retrofit2.Response import timber.log.Timber Loading @@ -76,7 +70,6 @@ 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 import foundation.e.apps.data.cleanapk.data.home.Home as CleanApkHome typealias FusedHomeDeferred = Deferred<ResultSupreme<List<Home>>> Loading @@ -95,7 +88,6 @@ class ApplicationApiImpl @Inject constructor( private const val CATEGORY_TITLE_REPLACEABLE_CONJUNCTION = "&" private const val CATEGORY_OPEN_GAMES_ID = "game_open_games" private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" private const val THRESHOLD_LIMITED_RESULT_HOME_PAGE = 4 private const val KEYWORD_TEST_SEARCH = "facebook" } Loading @@ -107,97 +99,6 @@ class ApplicationApiImpl @Inject constructor( return prefs } override suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> { val list = mutableListOf<Home>() var resultGplay: FusedHomeDeferred? = null var resultOpenSource: FusedHomeDeferred? = null var resultPWA: FusedHomeDeferred? = null return liveData { coroutineScope { if (preferenceManagerModule.isGplaySelected()) { resultGplay = async { loadHomeData(list, Source.GPLAY, authData) } } if (preferenceManagerModule.isOpenSourceSelected()) { resultOpenSource = async { loadHomeData(list, Source.OPEN, authData) } } if (preferenceManagerModule.isPWASelected()) { resultPWA = async { loadHomeData(list, Source.PWA, authData) } } resultGplay?.await()?.let { emit(it) } resultOpenSource?.await()?.let { emit(it) } resultPWA?.await()?.let { emit(it) } } } } private suspend fun loadHomeData( priorList: MutableList<Home>, source: Source, authData: AuthData, ): ResultSupreme<List<Home>> { val result = when (source) { Source.GPLAY -> handleNetworkResult<List<Home>> { priorList.addAll(fetchGPlayHome(authData)) priorList } Source.OPEN -> handleNetworkResult { val response = (cleanApkAppsRepository.getHomeScreenData() as Response<HomeScreen>).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } priorList } Source.PWA -> handleNetworkResult { val response = (cleanApkPWARepository.getHomeScreenData() as Response<HomeScreen>).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } priorList } } setHomeErrorMessage(result.getResultStatus(), source) priorList.sortByDescending { when (it.source) { APP_TYPE_OPEN -> 2 APP_TYPE_PWA -> 1 else -> 3 } } return ResultSupreme.create(result.getResultStatus(), priorList) } private fun setHomeErrorMessage(apiStatus: ResultStatus, source: Source) { if (apiStatus != ResultStatus.OK) { apiStatus.message = when (source) { Source.GPLAY -> ("GPlay home loading error\n" + apiStatus.message).trim() Source.OPEN -> ("Open Source home loading error\n" + apiStatus.message).trim() Source.PWA -> ("PWA home loading error\n" + apiStatus.message).trim() } } } /* * Return three elements from the function. * - List<FusedCategory> : List of categories. Loading Loading @@ -756,7 +657,7 @@ class ApplicationApiImpl @Inject constructor( /* * Handy method to run on an instance of FusedApp to update its filter level. */ private suspend fun Application.updateFilterLevel(authData: AuthData?) { suspend fun Application.updateFilterLevel(authData: AuthData?) { this.filterLevel = getAppFilterLevel(this, authData) } Loading Loading @@ -1065,111 +966,6 @@ class ApplicationApiImpl @Inject constructor( return gPlayFusedApp } /* * Home screen-related internal functions */ private suspend fun generateCleanAPKHome(home: CleanApkHome, appType: String): List<Home> { val list = mutableListOf<Home>() val headings = if (appType == APP_TYPE_OPEN) { getOpenSourceHomeCategories() } else { getPWAHomeCategories() } headings.forEach { (key, value) -> when (key) { "top_updated_apps" -> { prepareApps(home.top_updated_apps, list, value) } "top_updated_games" -> { prepareApps(home.top_updated_games, list, value) } "popular_apps" -> { prepareApps(home.popular_apps, list, value) } "popular_games" -> { prepareApps(home.popular_games, list, value) } "popular_apps_in_last_24_hours" -> { prepareApps(home.popular_apps_in_last_24_hours, list, value) } "popular_games_in_last_24_hours" -> { prepareApps(home.popular_games_in_last_24_hours, list, value) } "discover" -> { prepareApps(home.discover, list, value) } } } return list.map { it.source = appType it } } private suspend fun prepareApps( appList: List<Application>, list: MutableList<Home>, value: String ) { if (appList.isNotEmpty()) { appList.forEach { it.updateStatus() it.updateType() it.updateFilterLevel(null) } list.add(Home(value, appList)) } } private fun getPWAHomeCategories() = mapOf( "popular_apps" to context.getString(R.string.popular_apps), "popular_games" to context.getString(R.string.popular_games), "discover" to context.getString(R.string.discover_pwa) ) private fun getOpenSourceHomeCategories() = mapOf( "top_updated_apps" to context.getString(R.string.top_updated_apps), "top_updated_games" to context.getString(R.string.top_updated_games), "popular_apps_in_last_24_hours" to context.getString(R.string.popular_apps_in_last_24_hours), "popular_games_in_last_24_hours" to context.getString(R.string.popular_games_in_last_24_hours), "discover" to context.getString(R.string.discover) ) private suspend fun fetchGPlayHome(authData: AuthData): List<Home> { val list = mutableListOf<Home>() val gplayHomeData = gplayRepository.getHomeScreenData() as Map<String, List<App>> gplayHomeData.map { val fusedApps = it.value.map { app -> app.transformToFusedApp().apply { updateFilterLevel(authData) } } list.add(Home(it.key, fusedApps)) } handleLimitedResult(list) Timber.d("HomePageData: $list") return list } private fun handleLimitedResult(homeList: List<Home>) { val gplayHomes = homeList.filter { fusedHome -> fusedHome.source.isEmpty() } val hasGplayLimitedResult = gplayHomes.any { fusedHome -> fusedHome.list.size < THRESHOLD_LIMITED_RESULT_HOME_PAGE } if (hasGplayLimitedResult) { Timber.w("Limited result is found for homepage...") refreshToken() } } private fun refreshToken() { MainScope().launch { EventBus.invokeEvent( Loading
app/src/main/java/foundation/e/apps/data/application/ApplicationDataManager.kt 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.application import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.application.data.Home 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.playstore.PlayStoreRepository import foundation.e.apps.install.pkg.PWAManagerModule import foundation.e.apps.install.pkg.PkgManagerModule import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @Singleton class ApplicationDataManager @Inject constructor( @Named("gplayRepository") private val gplayRepository: PlayStoreRepository, private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule ) { suspend fun updateFilterLevel(authData: AuthData?, application: Application) { application.filterLevel = getAppFilterLevel(application, authData) } suspend fun prepareApps( appList: List<Application>, list: MutableList<Home>, value: String ) { if (appList.isNotEmpty()) { appList.forEach { it.updateType() updateStatus(it) updateFilterLevel(null, it) } list.add(Home(value, appList)) } } private 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 } } private fun isRestricted(application: Application): Boolean { return application.restriction != Constants.Restriction.NOT_RESTRICTED } /** * 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 } fun updateStatus(application: Application) { if (application.status != Status.INSTALLATION_ISSUE) { application.status = getFusedAppInstallationStatus(application) } } /** * 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 if (application.is_pwa) { pwaManagerModule.getPwaStatus(application) } else { pkgManagerModule.getPackageStatus(application.package_name, application.latest_version_code) } } }
app/src/main/java/foundation/e/apps/data/application/ApplicationRepository.kt +5 −2 Original line number Diff line number Diff line Loading @@ -37,10 +37,13 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton class ApplicationRepository @Inject constructor(private val applicationAPIImpl: ApplicationApi) { class ApplicationRepository @Inject constructor( private val applicationAPIImpl: ApplicationApi, private val homeApi: HomeApi ) { suspend fun getHomeScreenData(authData: AuthData): LiveData<ResultSupreme<List<Home>>> { return applicationAPIImpl.getHomeScreenData(authData) return homeApi.getHomeScreenData(authData) } fun getApplicationCategoryPreference(): List<String> { Loading
app/src/main/java/foundation/e/apps/data/application/HomeApi.kt 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * 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 <https://www.gnu.org/licenses/>. */ package foundation.e.apps.data.application import androidx.lifecycle.LiveData import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.application.data.Home interface HomeApi { suspend fun getHomeScreenData( authData: AuthData, ): LiveData<ResultSupreme<List<Home>>> }