diff --git a/app/build.gradle b/app/build.gradle index da7abac210998c55b96b0412d91f72a8c0380e02..1a50799bb1642441c521d1f59caea9ddf2844248 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMinor = 6 -def versionPatch = 4 +def versionPatch = 5 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt index 00dd50683738bdcc6da11490f52790cf822c3575..6a3c50f2e6a28926f7e3d42c73dbfa3667a869cb 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedAPIRepository.kt @@ -19,6 +19,8 @@ package foundation.e.apps.data.fused import androidx.lifecycle.LiveData +import androidx.lifecycle.map +import androidx.lifecycle.switchMap import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.SearchBundle @@ -33,14 +35,44 @@ import foundation.e.apps.data.fused.data.FusedCategory import foundation.e.apps.data.fused.data.FusedHome import foundation.e.apps.data.fused.utils.CategoryType import foundation.e.apps.data.fusedDownload.models.FusedDownload +import foundation.e.apps.data.login.AuthObject +import foundation.e.apps.utils.eventBus.AppEvent +import foundation.e.apps.utils.eventBus.EventBus +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject import javax.inject.Singleton @Singleton class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedApi) { + private var hasGplayLimitedResult: Boolean = false + suspend fun getHomeScreenData(authData: AuthData): LiveData>> { - return fusedAPIImpl.getHomeScreenData(authData) + return fusedAPIImpl.getHomeScreenData(authData).map { + if (!it.isSuccess()) { + return@map it + } + + val gplayHomes = it.data?.filter { fusedHome -> fusedHome.source.isEmpty() } + Timber.d("Gplayhome size: ${gplayHomes?.size}") + hasGplayLimitedResult = gplayHomes?.any { fusedHome -> fusedHome.list.size < 4 } == true + Timber.d("hasGplayLimitedResult: $hasGplayLimitedResult") + if (hasGplayLimitedResult) { + triggerInvalidAuthEvent() + } + + it + } + } + + private fun triggerInvalidAuthEvent() { + MainScope().launch { + EventBus.invokeEvent( + AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) + ) + } } fun isHomesEmpty(fusedHomes: List): Boolean { @@ -119,7 +151,13 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedApi) query: String, nextPageSubBundle: Set? ): GplaySearchResult { - return fusedAPIImpl.getGplaySearchResult(query, nextPageSubBundle) + val gplaySearchResult = fusedAPIImpl.getGplaySearchResult(query, nextPageSubBundle) + val appList = gplaySearchResult.data?.first + if (hasGplayLimitedResult && appList.isNullOrEmpty()) { + triggerInvalidAuthEvent() + } + + return gplaySearchResult } suspend fun getAppsListBasedOnCategory( diff --git a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt index 5aa83c320f7bfc44dc45372b65b422d65c6751f4..853b45df343364b4427a1fafa9de4acfb5b1101e 100644 --- a/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/fused/FusedApiImpl.kt @@ -62,13 +62,18 @@ import foundation.e.apps.data.fused.utils.CategoryUtils import foundation.e.apps.data.fusedDownload.models.FusedDownload import foundation.e.apps.data.gplay.GplayStoreRepository import foundation.e.apps.data.handleNetworkResult +import foundation.e.apps.data.login.AuthObject 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.home.model.HomeChildFusedAppDiffUtil +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 import javax.inject.Inject @@ -93,6 +98,8 @@ class FusedApiImpl @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" } /** @@ -1031,6 +1038,7 @@ class FusedApiImpl @Inject constructor( val fusedAppList = searchResults.first.map { app -> replaceWithFDroid(app) }.toMutableList() + hasLimitedResultForSearch(fusedAppList) if (searchResults.second.isNotEmpty()) { fusedAppList.add(FusedApp(isPlaceHolder = true)) @@ -1040,6 +1048,16 @@ class FusedApiImpl @Inject constructor( } } + private suspend fun hasLimitedResultForSearch(appList: List?) { + if (appList.isNullOrEmpty()) { + val searchResult = gplayRepository.getSearchResult(KEYWORD_TEST_SEARCH, null) + if (searchResult.first.isEmpty()) { + Timber.w("Limited result for search is found...") + triggerInvalidAuthEvent() + } + } + } + /* * This function will replace a GPlay app with F-Droid app if exists, * else will show the GPlay app itself. @@ -1165,7 +1183,7 @@ class FusedApiImpl @Inject constructor( } } - private suspend fun fetchGPlayHome(authData: AuthData): List { + private suspend fun fetchGPlayHome(authData: AuthData): List { val list = mutableListOf() val gplayHomeData = gplayRepository.getHomeScreenData() as Map> gplayHomeData.map { @@ -1176,14 +1194,33 @@ class FusedApiImpl @Inject constructor( } list.add(FusedHome(it.key, fusedApps)) } - Timber.d("===> $list") + + handleLimitedResultForHomePage(list) + Timber.d("HomePageData: $list") + return list } + private fun handleLimitedResultForHomePage(it: List) { + val gplayHomes = it.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...") + triggerInvalidAuthEvent() + } + } + + private fun triggerInvalidAuthEvent() { + MainScope().launch { + EventBus.invokeEvent( + AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) + ) + } + } + /* * FusedApp-related internal extensions and functions */ - private fun App.transformToFusedApp(): FusedApp { val app = FusedApp( _id = this.id.toString(), diff --git a/app/src/main/java/foundation/e/apps/data/gplay/GplayStoreRepositoryImpl.kt b/app/src/main/java/foundation/e/apps/data/gplay/GplayStoreRepositoryImpl.kt index 383f8e7c6e43a3914944d9e2708fbb45bfbc0bfe..123e6646cbef086ab5c25c3cff78861ec1a22f23 100644 --- a/app/src/main/java/foundation/e/apps/data/gplay/GplayStoreRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/apps/data/gplay/GplayStoreRepositoryImpl.kt @@ -60,7 +60,8 @@ class GplayStoreRepositoryImpl @Inject constructor( val result = getTopApps(type, chart, authData) homeScreenData[it.key] = result } - + val firstAppList = homeScreenData[Chart.TOP_SELLING_FREE.toString()] + homeScreenData[Chart.TOP_SELLING_FREE.toString()] = firstAppList?.toMutableList()?.subList(0, 2) ?: mutableListOf() return homeScreenData } diff --git a/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt b/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt index a0b02883a0e4c23f931bc186a8d9b067ca9ba26d..5e2a519ab519e5b30f0a9847cf53eadbd5487118 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/SearchFragment.kt @@ -140,6 +140,11 @@ class SearchFragment : if (!requireContext().isNetworkAvailable()) { return } + + if (authObjects.value?.none { it is AuthObject.GPlayAuth } == true) { + return + } + searchViewModel.loadMore(searchText) } } diff --git a/app/src/main/java/foundation/e/apps/ui/search/SearchViewModel.kt b/app/src/main/java/foundation/e/apps/ui/search/SearchViewModel.kt index a2bc710807f7e60f1d9d0e8e69d45bbf02b466b8..dbf0b1ba968b7f90a4861ecc74fe1e05d5192228 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/SearchViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/SearchViewModel.kt @@ -91,7 +91,7 @@ class SearchViewModel @Inject constructor( } successAuthList.find { it is AuthObject.CleanApk }?.run { - getSearchResults(query, AuthData("", ""), lifecycleOwner) + getSearchResults(query, null, lifecycleOwner) return@onLoadData } }, retryBlock) @@ -105,17 +105,20 @@ class SearchViewModel @Inject constructor( */ private fun getSearchResults( query: String, - authData: AuthData, + authData: AuthData?, lifecycleOwner: LifecycleOwner ) { viewModelScope.launch(Dispatchers.IO) { - val searchResultSupreme = fusedAPIRepository.getCleanApkSearchResults(query, authData) + val searchResultSupreme = fusedAPIRepository.getCleanApkSearchResults( + query, + authData ?: AuthData("", "") + ) searchResult.postValue(searchResultSupreme) if (!searchResultSupreme.isSuccess()) { val exception = - if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) { + if (authData != null) { GPlayException( searchResultSupreme.isTimeout(), searchResultSupreme.message.ifBlank { DATA_LOAD_ERROR } @@ -130,6 +133,10 @@ class SearchViewModel @Inject constructor( handleException(exception) } + if (authData == null) { + return@launch + } + nextSubBundle = null fetchGplayData(query) } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index bc86371592b832135f31405533e1e9470e93371d..aafa2cb17d8e926650d38f08b02d34bf1909485d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -166,4 +166,7 @@ \n\t• Micro-Targeting abzuschwächen \n\t• die Auswirkungen zu begrenzen, falls dieses Konto von Google eingeschränkt wird Bitte %1$s Speicherplatz auf diesem Gerät freimachen, damtit die neueste Aktualisierung installiert werden kann. + Aktualisierungen werden überprüft … + Das anonyme Konto, das von Ihnen genutzt wird, ist nicht verfügbar. Bitte erneuern (refresh) Sie die Sitzung, um ein neues anonymes Konto zu erhalten. + SITZUNG ERNEUERN \ No newline at end of file diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 58dda78daac2ccc8c5ebc587034914b502340057..f60f9e174cefb942e4bff7823948766a02cd00a7 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -168,4 +168,6 @@ Með því að smella á \"%1$s\" mun opnast flipi í vafranum þínum mep heiti pakkans forútfylltu.<br /><br />Smelltu á \"Perform analysis\" til að hefja greiningu með Exodus.<br /><br />Þegar hnappurinn \"See the report\" birtist (tíminn sem það tekur fer eftir forritinu) geturðu lokað flipanum og snúið til baka í lýsingu forritsins á %2$s þar sem þú ættir að sjá gagnaleyndareinkunnina (Privacy Score). Stundum mistekst Exodus að greina forrit.<br /><br />ATH: það getur tekið allt að 10 mínútur fyrir einkunnina að birtast í lýsingunni á forritinu. ENDURLESA SETU Nafnlausi aðgangurinn sem þú ert að nota er ekki tiltækur. Endurlestu setuna til að fá annann. + Losaðu um %1$s pláss á símanum þínum til að fá nýjustu uppfærslur. + Athuga með uppfærslur... \ No newline at end of file diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index cfc91ab0cbfa690cd173c9b96974a0c4d942e4a7..4c2e6cede1612af42a969d897298ace558ec9e1e 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -127,4 +127,8 @@ Integritetspoängen är automatiskt beräknad utifrån behörigheter och spårare som detekterats i applikationer. Det ger en fingervisning micro-spårar sina användare.<br /><br />Algoritmens källkod för beräkningar kan hittas <a href=%1$s>här</a>.<br /><br />Spårardetektering utförs med <a href=%2$s>Exodus Privacy tools</a>.<br /><br />Poäng av 10.<br /><br />Läs mer om hur Integritetspoäng beräknas, dess begränsningar och hur du kan skydda dig själv från microspårning <a href=%3$s>på denna sidan</a>. Uppdateringar På grund av ett tillfälligt fel kan inte alla dina appar uppdateras. Försök igen senare. + Söker efter uppdateringar ... + Topplista: Gratisappar + Topplista: Gratisspel + Topplista: Betalappar \ No newline at end of file