From cfffabc15dc2041be288ca59eb82c65e554670b1 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Mon, 20 Feb 2023 20:39:15 +0600 Subject: [PATCH 01/13] paritally done --- .../e/apps/api/StoreApiRepository.kt | 6 + .../e/apps/api/fused/FusedAPIImpl.kt | 22 ++- .../e/apps/api/gplay/GplayRepository.kt | 148 ++++++++++++++++++ .../e/apps/di/NamedRepositoryModule.kt | 29 ++++ .../e/apps/login/LoginSourceRepository.kt | 5 + 5 files changed, 197 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt diff --git a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt new file mode 100644 index 000000000..cb3985672 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt @@ -0,0 +1,6 @@ +package foundation.e.apps.api + +interface StoreApiRepository { + suspend fun getHomeScreenData(): Any + fun getSearchResult(query: String): Any +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 889cbb999..63c4eace2 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -36,6 +36,7 @@ import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme +import foundation.e.apps.api.StoreApiRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories @@ -48,6 +49,7 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.gplay.GPlayAPIRepository +import foundation.e.apps.api.gplay.GplayRepository import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule @@ -66,6 +68,7 @@ import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.withTimeout import timber.log.Timber import javax.inject.Inject +import javax.inject.Named import javax.inject.Singleton @Singleton @@ -76,6 +79,7 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, + @Named("gplayRepository") private val gplayRepository: StoreApiRepository, @ApplicationContext private val context: Context ) { @@ -1320,24 +1324,16 @@ class FusedAPIImpl @Inject constructor( private suspend fun fetchGPlayHome(authData: AuthData): List { val list = mutableListOf() - val homeElements = mutableMapOf( - context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), - context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), - context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), - ) - homeElements.forEach { - val chart = it.value.keys.iterator().next() - val type = it.value.values.iterator().next() - val result = gPlayAPIRepository.getTopApps(type, chart, authData).map { app -> + val gplayHomeData = gplayRepository.getHomeScreenData() as Map> + gplayHomeData.map { + val fusedApps = it.value.map { app -> app.transformToFusedApp().apply { updateFilterLevel(authData) } } - list.add(FusedHome(it.key, result)) + list.add(FusedHome(it.key, fusedApps)) } + Timber.d("===> $list") return list } diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt new file mode 100644 index 000000000..f4e380549 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -0,0 +1,148 @@ +package foundation.e.apps.api.gplay + +import android.content.Context +import androidx.lifecycle.LiveData +import androidx.lifecycle.LiveDataScope +import androidx.lifecycle.liveData +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.SearchBundle +import com.aurora.gplayapi.helpers.SearchHelper +import com.aurora.gplayapi.helpers.TopChartsHelper +import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.R +import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.fused.data.FusedApp +import foundation.e.apps.api.fused.data.FusedHome +import foundation.e.apps.api.gplay.utils.GPlayHttpClient +import foundation.e.apps.login.LoginSourceRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class GplayRepository @Inject constructor( + @ApplicationContext private val context: Context, + private val gPlayHttpClient: GPlayHttpClient, + private val loginSourceRepository: LoginSourceRepository +) : StoreApiRepository { + + override suspend fun getHomeScreenData(): Any { + val homeScreenData = mutableMapOf>() + val homeElements = mutableMapOf( + context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), + context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), + context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), + ) + homeElements.forEach { + val chart = it.value.keys.iterator().next() + val type = it.value.values.iterator().next() + val result = getTopApps(type, chart, loginSourceRepository.gplayAuth!!) + homeScreenData[it.key] = result + } + + return homeScreenData + } + + override fun getSearchResult(query: String): LiveData, Boolean>> { + return liveData { + withContext(Dispatchers.IO) { + /* + * Variable names and logic made same as that of Aurora store. + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 + */ + val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + val searchBundle = searchHelper.searchResults(query) + + val initialReplacedList = mutableListOf() + val INITIAL_LIMIT = 4 + + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + searchBundle, + true, + ) + + var nextSubBundleSet: MutableSet + do { + nextSubBundleSet = searchBundle.subBundles + val newSearchBundle = searchHelper.next(nextSubBundleSet) + if (newSearchBundle.appList.isNotEmpty()) { + searchBundle.apply { + subBundles.clear() + subBundles.addAll(newSearchBundle.subBundles) + emitReplacedList( + this@liveData, + initialReplacedList, + INITIAL_LIMIT, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) + } + } + } while (nextSubBundleSet.isNotEmpty()) + + /* + * If initialReplacedList size is less than INITIAL_LIMIT, + * it means the results were very less and nothing has been emitted so far. + * Hence emit the list. + */ + if (initialReplacedList.size < INITIAL_LIMIT) { + emit(Pair(initialReplacedList, false)) + } + } + } + } + + private suspend fun emitReplacedList( + scope: LiveDataScope, Boolean>>, + accumulationList: MutableList, + accumulationLimit: Int, + searchBundle: SearchBundle, + moreToEmit: Boolean, + ) { + searchBundle.appList.forEach { + when { + accumulationList.size < accumulationLimit - 1 -> { + /* + * If initial limit is 4, add apps to list (without emitting) + * till 2 apps. + */ + accumulationList.add(it) + } + accumulationList.size == accumulationLimit - 1 -> { + /* + * If initial limit is 4, and we have reached till 3 apps, + * add the 4th app and emit the list. + */ + accumulationList.add(it) + scope.emit(Pair(accumulationList, moreToEmit)) + } + accumulationList.size == accumulationLimit -> { + /* + * If initial limit is 4, and we have emitted 4 apps, + * for all rest of the apps, emit each app one by one. + */ + scope.emit(Pair(listOf(it), moreToEmit)) + } + } + } + } + + private suspend fun getTopApps( + type: TopChartsHelper.Type, + chart: TopChartsHelper.Chart, + authData: AuthData + ): List { + val topApps = mutableListOf() + withContext(Dispatchers.IO) { + val topChartsHelper = TopChartsHelper(authData).using(gPlayHttpClient) + topApps.addAll(topChartsHelper.getCluster(type, chart).clusterAppList) + } + return topApps + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt new file mode 100644 index 000000000..12a57e353 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -0,0 +1,29 @@ +package foundation.e.apps.di + +import android.content.Context +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.gplay.GplayRepository +import foundation.e.apps.api.gplay.utils.GPlayHttpClient +import foundation.e.apps.login.LoginSourceRepository +import javax.inject.Named +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +object NamedRepositoryModule { + @Singleton + @Provides + @Named("gplayRepository") + fun getGplayRepository( + @ApplicationContext context: Context, + gPlayHttpClient: GPlayHttpClient, + loginSourceRepository: LoginSourceRepository + ): StoreApiRepository { + return GplayRepository(context, gPlayHttpClient, loginSourceRepository) + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt b/app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt index ddc4bb392..43dc65c94 100644 --- a/app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt +++ b/app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt @@ -17,6 +17,7 @@ package foundation.e.apps.login +import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.utils.enums.User import javax.inject.Inject import javax.inject.Singleton @@ -28,6 +29,7 @@ class LoginSourceRepository @Inject constructor( private val sources: List, ) { + var gplayAuth: AuthData? = null suspend fun getAuthObjects(clearAuthTypes: List = listOf()): List { val authObjectsLocal = ArrayList() @@ -37,6 +39,9 @@ class LoginSourceRepository @Inject constructor( if (source::class.java.simpleName in clearAuthTypes) { source.clearSavedAuth() } + if (source is LoginSourceGPlay) { + gplayAuth = source.getAuthObject().result.data + } authObjectsLocal.add(source.getAuthObject()) } -- GitLab From ec95bfe07a521a45376b526455098197ffa0f215 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Mon, 27 Feb 2023 12:13:59 +0600 Subject: [PATCH 02/13] refactored search api of gplay --- .../e/apps/api/fused/FusedAPIImpl.kt | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 63c4eace2..fdaf4338d 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -20,10 +20,7 @@ package foundation.e.apps.api.fused import android.content.Context import android.text.format.Formatter -import androidx.lifecycle.LiveData -import androidx.lifecycle.LiveDataScope -import androidx.lifecycle.liveData -import androidx.lifecycle.map +import androidx.lifecycle.* import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App @@ -65,6 +62,9 @@ import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withTimeout import timber.log.Timber import javax.inject.Inject @@ -324,7 +324,7 @@ class FusedAPIImpl @Inject constructor( searchResult: MutableList, packageSpecificResults: ArrayList ): LiveData, Boolean>>> = - getGplaySearchResults(query, authData).map { + getGplaySearchResult(query, authData).map { if (it.first.isNotEmpty()) { searchResult.addAll(it.first) } @@ -1203,6 +1203,19 @@ class FusedAPIImpl @Inject constructor( } } + private fun getGplaySearchResult( + query: String, + authData: AuthData + ): LiveData, Boolean>> { + val searchResults = gplayRepository.getSearchResult(query) as LiveData, Boolean>> + return searchResults.asFlow().map { + val fusedAppList = it.first.map { app -> replaceWithFDroid(app) } + Pair( + fusedAppList, + it.second + ) + }.asLiveData() + } /* * This function will replace a GPlay app with F-Droid app if exists, * else will show the GPlay app itself. -- GitLab From 9fa3bdaaedf31009b09a0d3987a3e45ff3ed8db9 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Tue, 28 Feb 2023 09:47:24 +0600 Subject: [PATCH 03/13] CleanApk repository is introduced --- .../e/apps/api/StoreApiRepository.kt | 2 +- .../api/cleanapk/CleanApkAppsRepository.kt | 28 +++++++++++++++++++ .../api/cleanapk/CleanApkPWARepository.kt | 19 +++++++++++++ .../e/apps/api/fused/FusedAPIImpl.kt | 18 ++++++------ .../e/apps/api/gplay/GplayRepository.kt | 2 +- .../e/apps/di/NamedRepositoryModule.kt | 24 ++++++++++++++++ 6 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt diff --git a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt index cb3985672..04d45b240 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt @@ -2,5 +2,5 @@ package foundation.e.apps.api interface StoreApiRepository { suspend fun getHomeScreenData(): Any - fun getSearchResult(query: String): Any + suspend fun getSearchResult(query: String): Any } \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt new file mode 100644 index 000000000..0eceec6db --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -0,0 +1,28 @@ +package foundation.e.apps.api.cleanapk + +import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.cleanapk.data.home.HomeScreen +import retrofit2.Response + +class CleanApkAppsRepository( + private val cleanAPKInterface: CleanAPKInterface, + private val cleanApkAppDetailApi: CleanApkAppDetailApi +) : StoreApiRepository { + override suspend fun getHomeScreenData(): Response { + return cleanAPKInterface.getHomeScreenData( + CleanAPKInterface.APP_TYPE_ANY, + CleanAPKInterface.APP_SOURCE_FOSS + ) + } + + override suspend fun getSearchResult(query: String): Any { + return cleanAPKInterface.searchApps( + query, + CleanAPKInterface.APP_TYPE_ANY, + CleanAPKInterface.APP_SOURCE_FOSS, + 20, + 1, + null + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt new file mode 100644 index 000000000..8a8a09871 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -0,0 +1,19 @@ +package foundation.e.apps.api.cleanapk + +import foundation.e.apps.api.StoreApiRepository + +class CleanApkPWARepository( + private val cleanAPKInterface: CleanAPKInterface, + private val cleanApkAppDetailApi: CleanApkAppDetailApi +) : StoreApiRepository { + override suspend fun getHomeScreenData(): Any { + return cleanAPKInterface.getHomeScreenData( + CleanAPKInterface.APP_TYPE_PWA, + CleanAPKInterface.APP_SOURCE_ANY + ) + } + + override suspend fun getSearchResult(query: String): Any { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index fdaf4338d..18b78bdb4 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -38,6 +38,7 @@ import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.home.Home +import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search import foundation.e.apps.api.fdroid.FdroidWebInterface import foundation.e.apps.api.fused.data.FusedApp @@ -66,6 +67,7 @@ import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withTimeout +import retrofit2.Response import timber.log.Timber import javax.inject.Inject import javax.inject.Named @@ -80,6 +82,8 @@ class FusedAPIImpl @Inject constructor( private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, @Named("gplayRepository") private val gplayRepository: StoreApiRepository, + @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreApiRepository, + @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreApiRepository, @ApplicationContext private val context: Context ) { @@ -156,20 +160,14 @@ class FusedAPIImpl @Inject constructor( }) Source.OPEN -> runCodeBlockWithTimeout({ - val response = cleanAPKRepository.getHomeScreenData( - CleanAPKInterface.APP_TYPE_ANY, - CleanAPKInterface.APP_SOURCE_FOSS - ).body() + val response = (cleanApkAppsRepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } }) Source.PWA -> runCodeBlockWithTimeout({ - val response = cleanAPKRepository.getHomeScreenData( - CleanAPKInterface.APP_TYPE_PWA, - CleanAPKInterface.APP_SOURCE_ANY - ).body() + val response = (cleanApkPWARepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } @@ -318,7 +316,7 @@ class FusedAPIImpl @Inject constructor( ) } - private fun fetchGplaySearchResults( + private suspend fun fetchGplaySearchResults( query: String, authData: AuthData, searchResult: MutableList, @@ -1203,7 +1201,7 @@ class FusedAPIImpl @Inject constructor( } } - private fun getGplaySearchResult( + private suspend fun getGplaySearchResult( query: String, authData: AuthData ): LiveData, Boolean>> { diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index f4e380549..496adaaf5 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -46,7 +46,7 @@ class GplayRepository @Inject constructor( return homeScreenData } - override fun getSearchResult(query: String): LiveData, Boolean>> { + override suspend fun getSearchResult(query: String): LiveData, Boolean>> { return liveData { withContext(Dispatchers.IO) { /* diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 12a57e353..85e3ef5d6 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -7,6 +7,9 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkAppDetailApi +import foundation.e.apps.api.cleanapk.CleanApkAppsRepository import foundation.e.apps.api.gplay.GplayRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository @@ -26,4 +29,25 @@ object NamedRepositoryModule { ): StoreApiRepository { return GplayRepository(context, gPlayHttpClient, loginSourceRepository) } + + @Singleton + @Provides + @Named("cleanApkAppsRepository") + fun getCleanApkAppsRepository( + cleanAPKInterface: CleanAPKInterface, + cleanApkAppDetailApi: CleanApkAppDetailApi + ): StoreApiRepository { + return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) + } + + @Singleton + @Provides + @Named("cleanApkPWARepository") + fun getCleanApkPWARepository( + cleanAPKInterface: CleanAPKInterface, + cleanApkAppDetailApi: CleanApkAppDetailApi + ): StoreApiRepository { + return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) + } + } \ No newline at end of file -- GitLab From fa0ab8ae3a89d7b46b3345215a96270fce4dc4ec Mon Sep 17 00:00:00 2001 From: hasibprince Date: Mon, 6 Mar 2023 10:33:49 +0600 Subject: [PATCH 04/13] search apis refactored for storeapirepository --- .../e/apps/api/StoreApiRepository.kt | 3 +- .../api/cleanapk/CleanApkAppsRepository.kt | 11 +- .../api/cleanapk/CleanApkPWARepository.kt | 17 ++- .../e/apps/api/fused/FusedAPIImpl.kt | 36 +++---- .../e/apps/api/gplay/GplayRepository.kt | 101 ++++++++++-------- .../e/apps/di/NamedRepositoryModule.kt | 3 +- 6 files changed, 102 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt index 04d45b240..519222b93 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt @@ -3,4 +3,5 @@ package foundation.e.apps.api interface StoreApiRepository { suspend fun getHomeScreenData(): Any suspend fun getSearchResult(query: String): Any -} \ No newline at end of file + suspend fun getSearchSuggestions(query: String): Any +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index 0eceec6db..e84b5e054 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -2,6 +2,7 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.StoreApiRepository import foundation.e.apps.api.cleanapk.data.home.HomeScreen +import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response class CleanApkAppsRepository( @@ -15,14 +16,18 @@ class CleanApkAppsRepository( ) } - override suspend fun getSearchResult(query: String): Any { + override suspend fun getSearchResult(query: String): Response { return cleanAPKInterface.searchApps( query, - CleanAPKInterface.APP_TYPE_ANY, CleanAPKInterface.APP_SOURCE_FOSS, + CleanAPKInterface.APP_TYPE_ANY, 20, 1, null ) } -} \ No newline at end of file + + override suspend fun getSearchSuggestions(query: String): Any { + TODO("Not yet implemented") + } +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index 8a8a09871..d9bb243c5 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -1,6 +1,8 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.cleanapk.data.search.Search +import retrofit2.Response class CleanApkPWARepository( private val cleanAPKInterface: CleanAPKInterface, @@ -13,7 +15,18 @@ class CleanApkPWARepository( ) } - override suspend fun getSearchResult(query: String): Any { + override suspend fun getSearchResult(query: String): Response { + return cleanAPKInterface.searchApps( + query, + CleanAPKInterface.APP_SOURCE_ANY, + CleanAPKInterface.APP_TYPE_PWA, + 20, + 1, + null + ) + } + + override suspend fun getSearchSuggestions(query: String): Any { TODO("Not yet implemented") } -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 18b78bdb4..ff7269843 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -20,7 +20,11 @@ package foundation.e.apps.api.fused import android.content.Context import android.text.format.Formatter -import androidx.lifecycle.* +import androidx.lifecycle.LiveData +import androidx.lifecycle.LiveDataScope +import androidx.lifecycle.asLiveData +import androidx.lifecycle.liveData +import androidx.lifecycle.map import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App @@ -29,7 +33,6 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster -import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme @@ -47,7 +50,6 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.gplay.GPlayAPIRepository -import foundation.e.apps.api.gplay.GplayRepository import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule @@ -63,9 +65,8 @@ import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber @@ -274,7 +275,7 @@ class FusedAPIImpl @Inject constructor( authData, searchResult, packageSpecificResults - ) + ).asLiveData() ) } } @@ -288,11 +289,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme, Boolean>> { val pwaApps: MutableList = mutableListOf() val status = fusedAPIImpl.runCodeBlockWithTimeout({ - getCleanAPKSearchResults( - query, - CleanAPKInterface.APP_SOURCE_ANY, - CleanAPKInterface.APP_TYPE_PWA - ).apply { + val apps = (cleanApkPWARepository.getSearchResult(query,) as Response).body()?.apps + apps?.apply { if (this.isNotEmpty()) { pwaApps.addAll(this) } @@ -321,7 +319,7 @@ class FusedAPIImpl @Inject constructor( authData: AuthData, searchResult: MutableList, packageSpecificResults: ArrayList - ): LiveData, Boolean>>> = + ): Flow, Boolean>>> = getGplaySearchResult(query, authData).map { if (it.first.isNotEmpty()) { searchResult.addAll(it.first) @@ -471,7 +469,7 @@ class FusedAPIImpl @Inject constructor( } suspend fun getSearchSuggestions(query: String, authData: AuthData): List { - return gPlayAPIRepository.getSearchSuggestions(query, authData) + return gplayRepository.getSearchSuggestions(query) as List } suspend fun getOnDemandModule( @@ -1175,8 +1173,8 @@ class FusedAPIImpl @Inject constructor( by: String? = null ): List { val list = mutableListOf() - val response = - cleanAPKRepository.searchApps(keyword, source, type, nres, page, by).body()?.apps + val response = (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps +// val response = cleanAPKRepository.searchApps(keyword, source, type, nres,page, by).body()?.apps response?.forEach { it.updateStatus() @@ -1204,15 +1202,15 @@ class FusedAPIImpl @Inject constructor( private suspend fun getGplaySearchResult( query: String, authData: AuthData - ): LiveData, Boolean>> { - val searchResults = gplayRepository.getSearchResult(query) as LiveData, Boolean>> - return searchResults.asFlow().map { + ): Flow, Boolean>> { + val searchResults = gplayRepository.getSearchResult(query) as Flow, Boolean>> + return searchResults.map { val fusedAppList = it.first.map { app -> replaceWithFDroid(app) } Pair( fusedAppList, it.second ) - }.asLiveData() + } } /* * This function will replace a GPlay app with F-Droid app if exists, diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 496adaaf5..53ba3ae04 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -1,9 +1,7 @@ package foundation.e.apps.api.gplay import android.content.Context -import androidx.lifecycle.LiveData -import androidx.lifecycle.LiveDataScope -import androidx.lifecycle.liveData +import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.SearchBundle @@ -12,11 +10,13 @@ import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.StoreApiRepository -import foundation.e.apps.api.fused.data.FusedApp -import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext import javax.inject.Inject @@ -46,60 +46,68 @@ class GplayRepository @Inject constructor( return homeScreenData } - override suspend fun getSearchResult(query: String): LiveData, Boolean>> { - return liveData { - withContext(Dispatchers.IO) { + override suspend fun getSearchResult(query: String): Flow, Boolean>> { + return flow { /* * Variable names and logic made same as that of Aurora store. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 */ - val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) - val searchBundle = searchHelper.searchResults(query) + val searchHelper = + SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + val searchBundle = searchHelper.searchResults(query) - val initialReplacedList = mutableListOf() - val INITIAL_LIMIT = 4 + val initialReplacedList = mutableListOf() + val INITIAL_LIMIT = 4 - emitReplacedList( - this@liveData, - initialReplacedList, - INITIAL_LIMIT, - searchBundle, - true, - ) + emitReplacedList( + this@flow, + initialReplacedList, + INITIAL_LIMIT, + searchBundle, + true, + ) - var nextSubBundleSet: MutableSet - do { - nextSubBundleSet = searchBundle.subBundles - val newSearchBundle = searchHelper.next(nextSubBundleSet) - if (newSearchBundle.appList.isNotEmpty()) { - searchBundle.apply { - subBundles.clear() - subBundles.addAll(newSearchBundle.subBundles) - emitReplacedList( - this@liveData, - initialReplacedList, - INITIAL_LIMIT, - newSearchBundle, - nextSubBundleSet.isNotEmpty(), - ) - } + var nextSubBundleSet: MutableSet + do { + nextSubBundleSet = searchBundle.subBundles + val newSearchBundle = searchHelper.next(nextSubBundleSet) + if (newSearchBundle.appList.isNotEmpty()) { + searchBundle.apply { + subBundles.clear() + subBundles.addAll(newSearchBundle.subBundles) + emitReplacedList( + this@flow, + initialReplacedList, + INITIAL_LIMIT, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) } - } while (nextSubBundleSet.isNotEmpty()) + } + } while (nextSubBundleSet.isNotEmpty()) /* * If initialReplacedList size is less than INITIAL_LIMIT, * it means the results were very less and nothing has been emitted so far. * Hence emit the list. */ - if (initialReplacedList.size < INITIAL_LIMIT) { - emit(Pair(initialReplacedList, false)) - } + if (initialReplacedList.size < INITIAL_LIMIT) { + emitInMain(this@flow, initialReplacedList, false) } + }.flowOn(Dispatchers.IO) + } + + override suspend fun getSearchSuggestions(query: String): List { + val searchData = mutableListOf() + withContext(Dispatchers.IO) { + val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + searchData.addAll(searchHelper.searchSuggestions(query)) } + return searchData.filter { it.suggestedQuery.isNotBlank() } } private suspend fun emitReplacedList( - scope: LiveDataScope, Boolean>>, + scope: FlowCollector, Boolean>>, accumulationList: MutableList, accumulationLimit: Int, searchBundle: SearchBundle, @@ -121,18 +129,27 @@ class GplayRepository @Inject constructor( */ accumulationList.add(it) scope.emit(Pair(accumulationList, moreToEmit)) + emitInMain(scope, accumulationList, moreToEmit) } accumulationList.size == accumulationLimit -> { /* * If initial limit is 4, and we have emitted 4 apps, * for all rest of the apps, emit each app one by one. */ - scope.emit(Pair(listOf(it), moreToEmit)) + emitInMain(scope, listOf(it), moreToEmit) } } } } + private suspend fun emitInMain( + scope: FlowCollector, Boolean>>, + it: List, + moreToEmit: Boolean + ) { + scope.emit(Pair(it, moreToEmit)) + } + private suspend fun getTopApps( type: TopChartsHelper.Type, chart: TopChartsHelper.Chart, @@ -145,4 +162,4 @@ class GplayRepository @Inject constructor( } return topApps } -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 85e3ef5d6..3bde1dcf2 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -49,5 +49,4 @@ object NamedRepositoryModule { ): StoreApiRepository { return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) } - -} \ No newline at end of file +} -- GitLab From 7daf93c103b585eecb0e3866a03ceb65cce014be Mon Sep 17 00:00:00 2001 From: hasibprince Date: Thu, 9 Mar 2023 19:41:13 +0600 Subject: [PATCH 05/13] some refactoring --- .../e/apps/api/StoreApiRepository.kt | 7 -- .../foundation/e/apps/api/StoreRepository.kt | 25 ++++ .../api/cleanapk/CleanApkAppsRepository.kt | 23 +++- .../api/cleanapk/CleanApkPWARepository.kt | 23 +++- .../e/apps/api/fused/FusedAPIImpl.kt | 58 +++++---- .../e/apps/api/gplay/GplayRepository.kt | 111 ++++++++++++------ .../e/apps/di/NamedRepositoryModule.kt | 27 ++++- 7 files changed, 198 insertions(+), 76 deletions(-) delete mode 100644 app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/api/StoreRepository.kt diff --git a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt deleted file mode 100644 index 519222b93..000000000 --- a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package foundation.e.apps.api - -interface StoreApiRepository { - suspend fun getHomeScreenData(): Any - suspend fun getSearchResult(query: String): Any - suspend fun getSearchSuggestions(query: String): Any -} diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt new file mode 100644 index 000000000..96d182cc3 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt @@ -0,0 +1,25 @@ +/* + * 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.api + +interface StoreRepository { + suspend fun getHomeScreenData(): Any + suspend fun getSearchResult(query: String): Any + suspend fun getSearchSuggestions(query: String): Any +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index e84b5e054..50e2426cc 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -1,6 +1,24 @@ +/* + * 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.api.cleanapk -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response @@ -8,7 +26,8 @@ import retrofit2.Response class CleanApkAppsRepository( private val cleanAPKInterface: CleanAPKInterface, private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreApiRepository { +) : StoreRepository { + override suspend fun getHomeScreenData(): Response { return cleanAPKInterface.getHomeScreenData( CleanAPKInterface.APP_TYPE_ANY, diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index d9bb243c5..39a90cce4 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -1,13 +1,32 @@ +/* + * 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.api.cleanapk -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response class CleanApkPWARepository( private val cleanAPKInterface: CleanAPKInterface, private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreApiRepository { +) : StoreRepository { + override suspend fun getHomeScreenData(): Any { return cleanAPKInterface.getHomeScreenData( CleanAPKInterface.APP_TYPE_PWA, diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index ff7269843..2eba6f4be 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -36,7 +36,7 @@ import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories @@ -74,6 +74,8 @@ import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton +typealias GplaySearchResultFlow = Flow, Boolean>>> + @Singleton class FusedAPIImpl @Inject constructor( private val cleanAPKRepository: CleanAPKRepository, @@ -82,9 +84,9 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, - @Named("gplayRepository") private val gplayRepository: StoreApiRepository, - @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreApiRepository, - @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreApiRepository, + @Named("gplayRepository") private val gplayRepository: StoreRepository, + @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreRepository, + @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreRepository, @ApplicationContext private val context: Context ) { @@ -161,14 +163,16 @@ class FusedAPIImpl @Inject constructor( }) Source.OPEN -> runCodeBlockWithTimeout({ - val response = (cleanApkAppsRepository.getHomeScreenData() as Response).body() + val response = + (cleanApkAppsRepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } }) Source.PWA -> runCodeBlockWithTimeout({ - val response = (cleanApkPWARepository.getHomeScreenData() as Response).body() + val response = + (cleanApkPWARepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } @@ -289,7 +293,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme, Boolean>> { val pwaApps: MutableList = mutableListOf() val status = fusedAPIImpl.runCodeBlockWithTimeout({ - val apps = (cleanApkPWARepository.getSearchResult(query,) as Response).body()?.apps + val apps = + (cleanApkPWARepository.getSearchResult(query) as Response).body()?.apps apps?.apply { if (this.isNotEmpty()) { pwaApps.addAll(this) @@ -319,22 +324,21 @@ class FusedAPIImpl @Inject constructor( authData: AuthData, searchResult: MutableList, packageSpecificResults: ArrayList - ): Flow, Boolean>>> = - getGplaySearchResult(query, authData).map { - if (it.first.isNotEmpty()) { - searchResult.addAll(it.first) - } - ResultSupreme.Success( - Pair( - filterWithKeywordSearch( - searchResult, - packageSpecificResults, - query - ), - it.second - ) - ) + ): GplaySearchResultFlow = getGplaySearchResult(query, authData).map { + if (it.first.isNotEmpty()) { + searchResult.addAll(it.first) } + ResultSupreme.Success( + Pair( + filterWithKeywordSearch( + searchResult, + packageSpecificResults, + query + ), + it.second + ) + ) + } private suspend fun fetchOpenSourceSearchResult( fusedAPIImpl: FusedAPIImpl, @@ -1052,7 +1056,7 @@ class FusedAPIImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { @@ -1173,8 +1177,8 @@ class FusedAPIImpl @Inject constructor( by: String? = null ): List { val list = mutableListOf() - val response = (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps -// val response = cleanAPKRepository.searchApps(keyword, source, type, nres,page, by).body()?.apps + val response = + (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps response?.forEach { it.updateStatus() @@ -1190,7 +1194,8 @@ class FusedAPIImpl @Inject constructor( query: String, authData: AuthData ): LiveData, Boolean>> { - val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) + val searchResults = + gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { Pair( it.first, @@ -1212,6 +1217,7 @@ class FusedAPIImpl @Inject constructor( ) } } + /* * This function will replace a GPlay app with F-Droid app if exists, * else will show the GPlay app itself. diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 53ba3ae04..76ed53e79 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -1,3 +1,21 @@ +/* + * 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.api.gplay import android.content.Context @@ -9,7 +27,7 @@ import com.aurora.gplayapi.helpers.SearchHelper import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository import kotlinx.coroutines.Dispatchers @@ -24,18 +42,12 @@ class GplayRepository @Inject constructor( @ApplicationContext private val context: Context, private val gPlayHttpClient: GPlayHttpClient, private val loginSourceRepository: LoginSourceRepository -) : StoreApiRepository { +) : StoreRepository { override suspend fun getHomeScreenData(): Any { val homeScreenData = mutableMapOf>() - val homeElements = mutableMapOf( - context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), - context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), - context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), - ) + val homeElements = createTopChartElements() + homeElements.forEach { val chart = it.value.keys.iterator().next() val type = it.value.values.iterator().next() @@ -46,12 +58,21 @@ class GplayRepository @Inject constructor( return homeScreenData } + private fun createTopChartElements() = mutableMapOf( + context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), + context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), + context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), + ) + override suspend fun getSearchResult(query: String): Flow, Boolean>> { return flow { - /* - * Variable names and logic made same as that of Aurora store. - * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 - */ + /* + * Variable names and logic made same as that of Aurora store. + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 + */ val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) @@ -69,38 +90,56 @@ class GplayRepository @Inject constructor( var nextSubBundleSet: MutableSet do { - nextSubBundleSet = searchBundle.subBundles - val newSearchBundle = searchHelper.next(nextSubBundleSet) - if (newSearchBundle.appList.isNotEmpty()) { - searchBundle.apply { - subBundles.clear() - subBundles.addAll(newSearchBundle.subBundles) - emitReplacedList( - this@flow, - initialReplacedList, - INITIAL_LIMIT, - newSearchBundle, - nextSubBundleSet.isNotEmpty(), - ) - } - } + nextSubBundleSet = fetchNextSubBundle( + searchBundle, + searchHelper, + this@flow, + initialReplacedList, + INITIAL_LIMIT + ) } while (nextSubBundleSet.isNotEmpty()) - /* - * If initialReplacedList size is less than INITIAL_LIMIT, - * it means the results were very less and nothing has been emitted so far. - * Hence emit the list. - */ + /* + * If initialReplacedList size is less than INITIAL_LIMIT, + * it means the results were very less and nothing has been emitted so far. + * Hence emit the list. + */ if (initialReplacedList.size < INITIAL_LIMIT) { emitInMain(this@flow, initialReplacedList, false) } }.flowOn(Dispatchers.IO) } + private suspend fun fetchNextSubBundle( + searchBundle: SearchBundle, + searchHelper: SearchHelper, + scope: FlowCollector, Boolean>>, + accumulationList: MutableList, + accumulationLimit: Int, + ): MutableSet { + val nextSubBundleSet = searchBundle.subBundles + val newSearchBundle = searchHelper.next(nextSubBundleSet) + if (newSearchBundle.appList.isNotEmpty()) { + searchBundle.apply { + subBundles.clear() + subBundles.addAll(newSearchBundle.subBundles) + emitReplacedList( + scope, + accumulationList, + accumulationLimit, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) + } + } + return nextSubBundleSet + } + override suspend fun getSearchSuggestions(query: String): List { val searchData = mutableListOf() withContext(Dispatchers.IO) { - val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + val searchHelper = + SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) searchData.addAll(searchHelper.searchSuggestions(query)) } return searchData.filter { it.suggestedQuery.isNotBlank() } @@ -122,6 +161,7 @@ class GplayRepository @Inject constructor( */ accumulationList.add(it) } + accumulationList.size == accumulationLimit - 1 -> { /* * If initial limit is 4, and we have reached till 3 apps, @@ -131,6 +171,7 @@ class GplayRepository @Inject constructor( scope.emit(Pair(accumulationList, moreToEmit)) emitInMain(scope, accumulationList, moreToEmit) } + accumulationList.size == accumulationLimit -> { /* * If initial limit is 4, and we have emitted 4 apps, diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 3bde1dcf2..f328c8096 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -1,12 +1,31 @@ +/* + * 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.di + import android.content.Context import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanApkAppDetailApi import foundation.e.apps.api.cleanapk.CleanApkAppsRepository @@ -26,7 +45,7 @@ object NamedRepositoryModule { @ApplicationContext context: Context, gPlayHttpClient: GPlayHttpClient, loginSourceRepository: LoginSourceRepository - ): StoreApiRepository { + ): StoreRepository { return GplayRepository(context, gPlayHttpClient, loginSourceRepository) } @@ -36,7 +55,7 @@ object NamedRepositoryModule { fun getCleanApkAppsRepository( cleanAPKInterface: CleanAPKInterface, cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreApiRepository { + ): StoreRepository { return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) } @@ -46,7 +65,7 @@ object NamedRepositoryModule { fun getCleanApkPWARepository( cleanAPKInterface: CleanAPKInterface, cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreApiRepository { + ): StoreRepository { return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) } } -- GitLab From a4c7c84cd3d8e894c7381d8bed3b9eebfd96504e Mon Sep 17 00:00:00 2001 From: hasibprince Date: Mon, 20 Mar 2023 21:49:21 +0600 Subject: [PATCH 06/13] refactor: fetching apps according to category --- app/build.gradle | 2 +- .../foundation/e/apps/api/StoreRepository.kt | 2 + .../api/cleanapk/CleanApkAppsRepository.kt | 12 +- .../api/cleanapk/CleanApkPWARepository.kt | 10 + .../e/apps/api/fused/FusedAPIImpl.kt | 21 +- .../e/apps/api/gplay/GplayRepository.kt | 235 +++++++++++++++++- 6 files changed, 263 insertions(+), 19 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 35ed7284f..af1cce8d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMinor = 4 -def versionPatch = 7 +def versionPatch = 9 def getGitHash = { -> def stdOut = new ByteArrayOutputStream() diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt index 96d182cc3..8b95c6c13 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt @@ -22,4 +22,6 @@ interface StoreRepository { suspend fun getHomeScreenData(): Any suspend fun getSearchResult(query: String): Any suspend fun getSearchSuggestions(query: String): Any + + suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Any } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index 50e2426cc..4103d004c 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -47,6 +47,16 @@ class CleanApkAppsRepository( } override suspend fun getSearchSuggestions(query: String): Any { - TODO("Not yet implemented") + return Any() + } + + override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Response { + return cleanAPKInterface.listApps( + category, + CleanAPKInterface.APP_SOURCE_FOSS, + CleanAPKInterface.APP_TYPE_ANY, + 20, + 1 + ) } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index 39a90cce4..9172943e0 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -48,4 +48,14 @@ class CleanApkPWARepository( override suspend fun getSearchSuggestions(query: String): Any { TODO("Not yet implemented") } + + override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Any { + return cleanAPKInterface.listApps( + category, + CleanAPKInterface.APP_SOURCE_FOSS, + CleanAPKInterface.APP_TYPE_PWA, + 20, + 1 + ) + } } diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 2eba6f4be..61a51ae20 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -562,7 +562,7 @@ class FusedAPIImpl @Inject constructor( var streamBundle = StreamBundle() val status = runCodeBlockWithTimeout({ streamBundle = - gPlayAPIRepository.getNextStreamBundle(authData, homeUrl, currentStreamBundle) + gplayRepository.getAppsByCategory(homeUrl, currentStreamBundle) as StreamBundle }) return ResultSupreme.create(status, streamBundle) } @@ -575,7 +575,7 @@ class FusedAPIImpl @Inject constructor( var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ streamCluster = - gPlayAPIRepository.getAdjustedFirstCluster(authData, streamBundle, pointer) + gplayRepository.getAppsByCategory("", Pair(streamBundle, pointer)) as StreamCluster }) return ResultSupreme.create(status, streamCluster) } @@ -586,7 +586,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme { var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ - streamCluster = gPlayAPIRepository.getNextStreamCluster(authData, currentStreamCluster) + streamCluster = + gplayRepository.getAppsByCategory("", currentStreamCluster) as StreamCluster }) return ResultSupreme.create(status, streamCluster) } @@ -598,7 +599,7 @@ class FusedAPIImpl @Inject constructor( val list = mutableListOf() val status = runCodeBlockWithTimeout({ list.addAll( - gPlayAPIRepository.listApps(browseUrl, authData).map { app -> + (gplayRepository.getAppsByCategory(browseUrl) as List).map { app -> app.transformToFusedApp() } ) @@ -1139,19 +1140,15 @@ class FusedAPIImpl @Inject constructor( } private suspend fun getOpenSourceAppsResponse(category: String): Search? { - return cleanAPKRepository.listApps( + return (cleanApkAppsRepository.getAppsByCategory( category, - CleanAPKInterface.APP_SOURCE_FOSS, - CleanAPKInterface.APP_TYPE_ANY - ).body() + ) as Response).body() } private suspend fun getPWAAppsResponse(category: String): Search? { - return cleanAPKRepository.listApps( + return (cleanApkPWARepository.getAppsByCategory( category, - CleanAPKInterface.APP_SOURCE_ANY, - CleanAPKInterface.APP_TYPE_PWA - ).body() + ) as Response).body() } private fun Category.transformToFusedCategory(): FusedCategory { diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 76ed53e79..0024db814 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -20,11 +20,8 @@ package foundation.e.apps.api.gplay import android.content.Context import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.App -import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.SearchBundle -import com.aurora.gplayapi.helpers.SearchHelper -import com.aurora.gplayapi.helpers.TopChartsHelper +import com.aurora.gplayapi.data.models.* +import com.aurora.gplayapi.helpers.* import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.StoreRepository @@ -35,6 +32,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext import javax.inject.Inject @@ -145,6 +143,233 @@ class GplayRepository @Inject constructor( return searchData.filter { it.suggestedQuery.isNotBlank() } } + override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Any { + if (paginationParameter != null && paginationParameter is StreamCluster) { + return getNextStreamCluster(loginSourceRepository.gplayAuth!!, paginationParameter) + } + + if (paginationParameter != null && paginationParameter is StreamBundle) { + return getNextStreamBundle( + loginSourceRepository.gplayAuth!!, + category, + paginationParameter + ) + } + + if (paginationParameter != null && paginationParameter is Pair<*, *>) { + return getAdjustedFirstCluster( + loginSourceRepository.gplayAuth!!, + paginationParameter.first as StreamBundle, + paginationParameter.second as Int + ) + } + + return getGplayApps(category) + } + + private suspend fun getGplayApps(category: String): List { + val list = mutableListOf() + withContext(Dispatchers.IO) { + supervisorScope { + val categoryHelper = + CategoryHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + + var streamBundle: StreamBundle + var nextStreamBundleUrl = category + + /* + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 + * + * Logic: We start with the browseUrl. + * When we call getSubCategoryBundle(), we get a new StreamBundle object, having + * StreamClusters, which have app data. + * The generated StreamBundle also has a url for next StreamBundle to be generated + * with fresh app data. + * Hence we loop as long as the StreamBundle's next page url is not blank. + */ + do { + streamBundle = categoryHelper.getSubCategoryBundle(nextStreamBundleUrl) + val streamClusters = streamBundle.streamClusters + + /* + * Similarly to the logic of StreamBundles, each StreamCluster can have a url, + * pointing to another StreamCluster with new set of app data. + * We loop over all the StreamCluster of one StreamBundle, and for each of the + * StreamCluster we continue looping as long as the StreamCluster.clusterNextPageUrl + * is not blank. + */ + streamClusters.values.forEach { streamCluster -> + list.addAll(streamCluster.clusterAppList) // Add all apps for this StreamCluster + + // Loop over possible next StreamClusters + var currentStreamCluster = streamCluster + while (currentStreamCluster.hasNext()) { + currentStreamCluster = categoryHelper + .getNextStreamCluster(currentStreamCluster.clusterNextPageUrl) + .also { + list.addAll(it.clusterAppList) + } + } + } + + nextStreamBundleUrl = streamBundle.streamNextPageUrl + } while (streamBundle.hasNext()) + + // TODO: DEAL WITH DUPLICATE AND LESS ITEMS + /*val streamClusters = categoryHelper.getSubCategoryBundle(browseUrl).streamClusters + streamClusters.values.forEach { + list.addAll(it.clusterAppList) + }*/ + } + } + return list.distinctBy { it.packageName } + } + + /* + * Get next StreamCluster from currentNextPageUrl. + * This method is to be called when the scrollview reaches the bottom. + * + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2] + */ + private suspend fun getNextStreamCluster( + authData: AuthData, + currentStreamCluster: StreamCluster, + ): StreamCluster { + return withContext(Dispatchers.IO) { + if (!currentStreamCluster.hasNext()) { + return@withContext StreamCluster() + } + + /* + * Logic found in Aurora store code. + */ + return@withContext if (currentStreamCluster.clusterNextPageUrl.contains("expanded")) { + getExpandedStreamCluster( + currentStreamCluster.clusterNextPageUrl, + authData + ) + } else { + getStreamCluster(currentStreamCluster.clusterNextPageUrl, authData) + } + } + } + + private fun getExpandedStreamCluster( + url: String, + authData: AuthData, + checkStartUrl: Boolean = false + ): StreamCluster { + ExpandedBrowseHelper(authData).using(gPlayHttpClient).run { + + if (!checkStartUrl) { + return getExpandedBrowseClusters(url) + } + + val browseResponse = getBrowseStreamResponse(url) + + if (browseResponse.hasBrowseTab()) { + return getExpandedBrowseClusters(browseResponse.browseTab.listUrl) + } + } + return StreamCluster() + } + + private fun getStreamCluster( + url: String, + authData: AuthData, + checkStartUrl: Boolean = false + ): StreamCluster { + StreamHelper(authData).using(gPlayHttpClient).run { + + if (!checkStartUrl) { + return getNextStreamCluster(url) + } + + val browseResponse = getBrowseStreamResponse(url) + + if (browseResponse.contentsUrl.isNotEmpty()) { + return getNextStreamCluster(browseResponse.contentsUrl) + } + + if (browseResponse.hasBrowseTab()) { + return getNextStreamCluster(browseResponse.browseTab.listUrl) + } + } + return StreamCluster() + } + + suspend fun getNextStreamBundle( + authData: AuthData, + homeUrl: String, + currentStreamBundle: StreamBundle, + ): StreamBundle { + return withContext(Dispatchers.IO) { + val categoryHelper = CategoryHelper(authData).using(gPlayHttpClient) + if (currentStreamBundle.streamClusters.isEmpty()) { + categoryHelper.getSubCategoryBundle(homeUrl) + } else { + categoryHelper.getSubCategoryBundle(currentStreamBundle.streamNextPageUrl) + } + } + } + + /** + * Get first adjusted StreamCluster of a StreamBundle. + * + * Takes the clusterBrowseUrl of streamBundle.streamClusters[[pointer]], + * Populates the cluster and returns it. + * + * This does not always operate on zeroth StreamCluster of [streamBundle]. + * A StreamBundle can have many StreamClusters, each of the individual StreamCluster can point + * to completely different StreamClusters. + * + * StreamBundle 1 (streamNextPageUrl points to StreamBundle 2) + * StreamCluster 1 -> StreamCluster 1.1 -> StreamCluster 1.2 .... + * StreamCluster 2 -> StreamCluster 2.1 -> StreamCluster 2.2 .... + * StreamCluster 3 -> StreamCluster 3.1 -> StreamCluster 3.2 .... + * + * Here [pointer] refers to the position of StreamCluster 1, 2, 3.... but not 1.1, 2.1 .... + * The subsequent clusters (1.1, 1.2, .. 2.1 ..) are accessed by [getNextStreamCluster]. + * + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2] + */ + suspend fun getAdjustedFirstCluster( + authData: AuthData, + streamBundle: StreamBundle, + pointer: Int = 0, + ): StreamCluster { + return withContext(Dispatchers.IO) { + val clusterSize = streamBundle.streamClusters.size + if (clusterSize != 0 && pointer < clusterSize && pointer >= 0) { + val firstCluster = streamBundle.streamClusters.values.toList()[pointer] + + val clusterBrowseUrl = firstCluster.clusterBrowseUrl + + /* + * Logic found in Aurora store code. + */ + val adjustedCluster = if (firstCluster.clusterBrowseUrl.contains("expanded")) { + getExpandedStreamCluster(clusterBrowseUrl, authData, true) + } else { + getStreamCluster(clusterBrowseUrl, authData, true) + } + + return@withContext adjustedCluster.apply { + clusterAppList.addAll(firstCluster.clusterAppList) + if (!hasNext()) { + clusterNextPageUrl = firstCluster.clusterNextPageUrl + } + } + } + + /* + * If nothing works return blank StreamCluster. + */ + StreamCluster() + } + } + private suspend fun emitReplacedList( scope: FlowCollector, Boolean>>, accumulationList: MutableList, -- GitLab From 9796ce3c64b9381162e543af5de2fe0d482fb878 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Thu, 9 Mar 2023 19:41:13 +0600 Subject: [PATCH 07/13] some refactoring --- .../e/apps/api/StoreApiRepository.kt | 7 -- .../foundation/e/apps/api/StoreRepository.kt | 25 ++++ .../api/cleanapk/CleanApkAppsRepository.kt | 24 +++- .../api/cleanapk/CleanApkPWARepository.kt | 24 +++- .../e/apps/api/fused/FusedAPIImpl.kt | 58 +++++---- .../e/apps/api/gplay/GplayRepository.kt | 111 ++++++++++++------ .../e/apps/di/NamedRepositoryModule.kt | 34 ++++-- 7 files changed, 201 insertions(+), 82 deletions(-) delete mode 100644 app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt create mode 100644 app/src/main/java/foundation/e/apps/api/StoreRepository.kt diff --git a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt deleted file mode 100644 index 519222b93..000000000 --- a/app/src/main/java/foundation/e/apps/api/StoreApiRepository.kt +++ /dev/null @@ -1,7 +0,0 @@ -package foundation.e.apps.api - -interface StoreApiRepository { - suspend fun getHomeScreenData(): Any - suspend fun getSearchResult(query: String): Any - suspend fun getSearchSuggestions(query: String): Any -} diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt new file mode 100644 index 000000000..96d182cc3 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt @@ -0,0 +1,25 @@ +/* + * 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.api + +interface StoreRepository { + suspend fun getHomeScreenData(): Any + suspend fun getSearchResult(query: String): Any + suspend fun getSearchSuggestions(query: String): Any +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index e84b5e054..709b22f9e 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -1,14 +1,32 @@ +/* + * 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.api.cleanapk -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response class CleanApkAppsRepository( private val cleanAPKInterface: CleanAPKInterface, - private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreApiRepository { +) : StoreRepository { + override suspend fun getHomeScreenData(): Response { return cleanAPKInterface.getHomeScreenData( CleanAPKInterface.APP_TYPE_ANY, diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index d9bb243c5..fa4ad5c27 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -1,13 +1,31 @@ +/* + * 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.api.cleanapk -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response class CleanApkPWARepository( private val cleanAPKInterface: CleanAPKInterface, - private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreApiRepository { +) : StoreRepository { + override suspend fun getHomeScreenData(): Any { return cleanAPKInterface.getHomeScreenData( CleanAPKInterface.APP_TYPE_PWA, diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index ff7269843..2eba6f4be 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -36,7 +36,7 @@ import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories @@ -74,6 +74,8 @@ import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton +typealias GplaySearchResultFlow = Flow, Boolean>>> + @Singleton class FusedAPIImpl @Inject constructor( private val cleanAPKRepository: CleanAPKRepository, @@ -82,9 +84,9 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, - @Named("gplayRepository") private val gplayRepository: StoreApiRepository, - @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreApiRepository, - @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreApiRepository, + @Named("gplayRepository") private val gplayRepository: StoreRepository, + @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreRepository, + @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreRepository, @ApplicationContext private val context: Context ) { @@ -161,14 +163,16 @@ class FusedAPIImpl @Inject constructor( }) Source.OPEN -> runCodeBlockWithTimeout({ - val response = (cleanApkAppsRepository.getHomeScreenData() as Response).body() + val response = + (cleanApkAppsRepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } }) Source.PWA -> runCodeBlockWithTimeout({ - val response = (cleanApkPWARepository.getHomeScreenData() as Response).body() + val response = + (cleanApkPWARepository.getHomeScreenData() as Response).body() response?.home?.let { priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } @@ -289,7 +293,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme, Boolean>> { val pwaApps: MutableList = mutableListOf() val status = fusedAPIImpl.runCodeBlockWithTimeout({ - val apps = (cleanApkPWARepository.getSearchResult(query,) as Response).body()?.apps + val apps = + (cleanApkPWARepository.getSearchResult(query) as Response).body()?.apps apps?.apply { if (this.isNotEmpty()) { pwaApps.addAll(this) @@ -319,22 +324,21 @@ class FusedAPIImpl @Inject constructor( authData: AuthData, searchResult: MutableList, packageSpecificResults: ArrayList - ): Flow, Boolean>>> = - getGplaySearchResult(query, authData).map { - if (it.first.isNotEmpty()) { - searchResult.addAll(it.first) - } - ResultSupreme.Success( - Pair( - filterWithKeywordSearch( - searchResult, - packageSpecificResults, - query - ), - it.second - ) - ) + ): GplaySearchResultFlow = getGplaySearchResult(query, authData).map { + if (it.first.isNotEmpty()) { + searchResult.addAll(it.first) } + ResultSupreme.Success( + Pair( + filterWithKeywordSearch( + searchResult, + packageSpecificResults, + query + ), + it.second + ) + ) + } private suspend fun fetchOpenSourceSearchResult( fusedAPIImpl: FusedAPIImpl, @@ -1052,7 +1056,7 @@ class FusedAPIImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { @@ -1173,8 +1177,8 @@ class FusedAPIImpl @Inject constructor( by: String? = null ): List { val list = mutableListOf() - val response = (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps -// val response = cleanAPKRepository.searchApps(keyword, source, type, nres,page, by).body()?.apps + val response = + (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps response?.forEach { it.updateStatus() @@ -1190,7 +1194,8 @@ class FusedAPIImpl @Inject constructor( query: String, authData: AuthData ): LiveData, Boolean>> { - val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) + val searchResults = + gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { Pair( it.first, @@ -1212,6 +1217,7 @@ class FusedAPIImpl @Inject constructor( ) } } + /* * This function will replace a GPlay app with F-Droid app if exists, * else will show the GPlay app itself. diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 53ba3ae04..76ed53e79 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -1,3 +1,21 @@ +/* + * 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.api.gplay import android.content.Context @@ -9,7 +27,7 @@ import com.aurora.gplayapi.helpers.SearchHelper import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository import kotlinx.coroutines.Dispatchers @@ -24,18 +42,12 @@ class GplayRepository @Inject constructor( @ApplicationContext private val context: Context, private val gPlayHttpClient: GPlayHttpClient, private val loginSourceRepository: LoginSourceRepository -) : StoreApiRepository { +) : StoreRepository { override suspend fun getHomeScreenData(): Any { val homeScreenData = mutableMapOf>() - val homeElements = mutableMapOf( - context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), - context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), - context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), - context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), - ) + val homeElements = createTopChartElements() + homeElements.forEach { val chart = it.value.keys.iterator().next() val type = it.value.values.iterator().next() @@ -46,12 +58,21 @@ class GplayRepository @Inject constructor( return homeScreenData } + private fun createTopChartElements() = mutableMapOf( + context.getString(R.string.topselling_free_apps) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topselling_free_games) to mapOf(TopChartsHelper.Chart.TOP_SELLING_FREE to TopChartsHelper.Type.GAME), + context.getString(R.string.topgrossing_apps) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.topgrossing_games) to mapOf(TopChartsHelper.Chart.TOP_GROSSING to TopChartsHelper.Type.GAME), + context.getString(R.string.movers_shakers_apps) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.APPLICATION), + context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), + ) + override suspend fun getSearchResult(query: String): Flow, Boolean>> { return flow { - /* - * Variable names and logic made same as that of Aurora store. - * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 - */ + /* + * Variable names and logic made same as that of Aurora store. + * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 + */ val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) @@ -69,38 +90,56 @@ class GplayRepository @Inject constructor( var nextSubBundleSet: MutableSet do { - nextSubBundleSet = searchBundle.subBundles - val newSearchBundle = searchHelper.next(nextSubBundleSet) - if (newSearchBundle.appList.isNotEmpty()) { - searchBundle.apply { - subBundles.clear() - subBundles.addAll(newSearchBundle.subBundles) - emitReplacedList( - this@flow, - initialReplacedList, - INITIAL_LIMIT, - newSearchBundle, - nextSubBundleSet.isNotEmpty(), - ) - } - } + nextSubBundleSet = fetchNextSubBundle( + searchBundle, + searchHelper, + this@flow, + initialReplacedList, + INITIAL_LIMIT + ) } while (nextSubBundleSet.isNotEmpty()) - /* - * If initialReplacedList size is less than INITIAL_LIMIT, - * it means the results were very less and nothing has been emitted so far. - * Hence emit the list. - */ + /* + * If initialReplacedList size is less than INITIAL_LIMIT, + * it means the results were very less and nothing has been emitted so far. + * Hence emit the list. + */ if (initialReplacedList.size < INITIAL_LIMIT) { emitInMain(this@flow, initialReplacedList, false) } }.flowOn(Dispatchers.IO) } + private suspend fun fetchNextSubBundle( + searchBundle: SearchBundle, + searchHelper: SearchHelper, + scope: FlowCollector, Boolean>>, + accumulationList: MutableList, + accumulationLimit: Int, + ): MutableSet { + val nextSubBundleSet = searchBundle.subBundles + val newSearchBundle = searchHelper.next(nextSubBundleSet) + if (newSearchBundle.appList.isNotEmpty()) { + searchBundle.apply { + subBundles.clear() + subBundles.addAll(newSearchBundle.subBundles) + emitReplacedList( + scope, + accumulationList, + accumulationLimit, + newSearchBundle, + nextSubBundleSet.isNotEmpty(), + ) + } + } + return nextSubBundleSet + } + override suspend fun getSearchSuggestions(query: String): List { val searchData = mutableListOf() withContext(Dispatchers.IO) { - val searchHelper = SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + val searchHelper = + SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) searchData.addAll(searchHelper.searchSuggestions(query)) } return searchData.filter { it.suggestedQuery.isNotBlank() } @@ -122,6 +161,7 @@ class GplayRepository @Inject constructor( */ accumulationList.add(it) } + accumulationList.size == accumulationLimit - 1 -> { /* * If initial limit is 4, and we have reached till 3 apps, @@ -131,6 +171,7 @@ class GplayRepository @Inject constructor( scope.emit(Pair(accumulationList, moreToEmit)) emitInMain(scope, accumulationList, moreToEmit) } + accumulationList.size == accumulationLimit -> { /* * If initial limit is 4, and we have emitted 4 apps, diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 3bde1dcf2..102ef6e29 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -1,15 +1,35 @@ +/* + * 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.di + import android.content.Context import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import foundation.e.apps.api.StoreApiRepository +import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanApkAppDetailApi import foundation.e.apps.api.cleanapk.CleanApkAppsRepository +import foundation.e.apps.api.cleanapk.CleanApkPWARepository import foundation.e.apps.api.gplay.GplayRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository @@ -26,7 +46,7 @@ object NamedRepositoryModule { @ApplicationContext context: Context, gPlayHttpClient: GPlayHttpClient, loginSourceRepository: LoginSourceRepository - ): StoreApiRepository { + ): StoreRepository { return GplayRepository(context, gPlayHttpClient, loginSourceRepository) } @@ -35,9 +55,8 @@ object NamedRepositoryModule { @Named("cleanApkAppsRepository") fun getCleanApkAppsRepository( cleanAPKInterface: CleanAPKInterface, - cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreApiRepository { - return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) + ): StoreRepository { + return CleanApkAppsRepository(cleanAPKInterface) } @Singleton @@ -45,8 +64,7 @@ object NamedRepositoryModule { @Named("cleanApkPWARepository") fun getCleanApkPWARepository( cleanAPKInterface: CleanAPKInterface, - cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreApiRepository { - return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) + ): StoreRepository { + return CleanApkPWARepository(cleanAPKInterface) } } -- GitLab From 20852b84569c7a1b95cc52b9015e4c0eee7f3a92 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Sat, 25 Mar 2023 18:01:32 +0600 Subject: [PATCH 08/13] Refactor: StoreRepository for categories --- .../foundation/e/apps/api/StoreRepository.kt | 6 +- .../api/cleanapk/CleanApkAppsRepository.kt | 18 ++- .../api/cleanapk/CleanApkPWARepository.kt | 13 +- .../e/apps/api/fused/FusedAPIImpl.kt | 136 ++++-------------- .../e/apps/api/fused/FusedAPIRepository.kt | 7 +- .../e/apps/api/fused/utils/CategoryUtils.kt | 4 + .../e/apps/api/gplay/GplayRepository.kt | 36 +++-- .../e/apps/categories/AppsFragment.kt | 4 +- .../e/apps/categories/CategoriesViewModel.kt | 8 +- .../e/apps/categories/GamesFragment.kt | 4 +- 10 files changed, 103 insertions(+), 133 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt index 8b95c6c13..364e5a982 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt @@ -18,10 +18,12 @@ package foundation.e.apps.api +import foundation.e.apps.api.fused.utils.CategoryType + interface StoreRepository { suspend fun getHomeScreenData(): Any - suspend fun getSearchResult(query: String): Any + suspend fun getSearchResult(query: String, searchBy: String? = null): Any suspend fun getSearchSuggestions(query: String): Any - suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Any + suspend fun getCategories(type: CategoryType? = null): Any } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index 4103d004c..39054750d 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -19,8 +19,10 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.StoreRepository +import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search +import foundation.e.apps.api.fused.utils.CategoryType import retrofit2.Response class CleanApkAppsRepository( @@ -35,14 +37,14 @@ class CleanApkAppsRepository( ) } - override suspend fun getSearchResult(query: String): Response { + override suspend fun getSearchResult(query: String, searchBy: String?): Response { return cleanAPKInterface.searchApps( query, CleanAPKInterface.APP_SOURCE_FOSS, CleanAPKInterface.APP_TYPE_ANY, 20, 1, - null + searchBy ) } @@ -50,7 +52,10 @@ class CleanApkAppsRepository( return Any() } - override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Response { + override suspend fun getAppsByCategory( + category: String, + paginationParameter: Any? + ): Response { return cleanAPKInterface.listApps( category, CleanAPKInterface.APP_SOURCE_FOSS, @@ -59,4 +64,11 @@ class CleanApkAppsRepository( 1 ) } + + override suspend fun getCategories(type: CategoryType?): Response { + return cleanAPKInterface.getCategoriesList( + CleanAPKInterface.APP_TYPE_ANY, + CleanAPKInterface.APP_SOURCE_FOSS + ) + } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index 9172943e0..2bdf0841c 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -19,7 +19,9 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.StoreRepository +import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search +import foundation.e.apps.api.fused.utils.CategoryType import retrofit2.Response class CleanApkPWARepository( @@ -34,14 +36,14 @@ class CleanApkPWARepository( ) } - override suspend fun getSearchResult(query: String): Response { + override suspend fun getSearchResult(query: String, searchBy: String?): Response { return cleanAPKInterface.searchApps( query, CleanAPKInterface.APP_SOURCE_ANY, CleanAPKInterface.APP_TYPE_PWA, 20, 1, - null + searchBy ) } @@ -58,4 +60,11 @@ class CleanApkPWARepository( 1 ) } + + override suspend fun getCategories(type: CategoryType?): Response { + return cleanAPKInterface.getCategoriesList( + CleanAPKInterface.APP_TYPE_PWA, + CleanAPKInterface.APP_SOURCE_ANY + ) + } } diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 61a51ae20..bef4bbcb3 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -20,19 +20,10 @@ package foundation.e.apps.api.fused import android.content.Context import android.text.format.Formatter -import androidx.lifecycle.LiveData -import androidx.lifecycle.LiveDataScope -import androidx.lifecycle.asLiveData -import androidx.lifecycle.liveData -import androidx.lifecycle.map +import androidx.lifecycle.* 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.Category -import com.aurora.gplayapi.data.models.StreamBundle -import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.data.models.* import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme @@ -48,20 +39,14 @@ import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedCategory import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.Constants.timeoutDurationInMillis -import foundation.e.apps.utils.enums.AppTag -import foundation.e.apps.utils.enums.FilterLevel -import foundation.e.apps.utils.enums.Origin -import foundation.e.apps.utils.enums.ResultStatus -import foundation.e.apps.utils.enums.Source -import foundation.e.apps.utils.enums.Status -import foundation.e.apps.utils.enums.Type -import foundation.e.apps.utils.enums.isUnFiltered +import foundation.e.apps.utils.enums.* import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.TimeoutCancellationException @@ -206,15 +191,14 @@ class FusedAPIImpl @Inject constructor( * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5413 */ suspend fun getCategoriesList( - type: Category.Type, - authData: AuthData + type: CategoryType, ): Triple, String, ResultStatus> { val categoriesList = mutableListOf() val preferredApplicationType = preferenceManagerModule.preferredApplicationType() var apiStatus: ResultStatus = ResultStatus.OK var applicationCategoryType = preferredApplicationType - handleAllSourcesCategories(categoriesList, type, authData).run { + handleAllSourcesCategories(categoriesList, type).run { if (first != ResultStatus.OK) { apiStatus = first applicationCategoryType = second @@ -461,10 +445,11 @@ class FusedAPIImpl @Inject constructor( private suspend fun getCleanapkSearchResult(packageName: String): ResultSupreme { var fusedApp = FusedApp() val status = runCodeBlockWithTimeout({ - val result = cleanAPKRepository.searchApps( - keyword = packageName, - by = "package_name" - ).body() + val result = (cleanApkAppsRepository.getSearchResult( + packageName, + "package_name" + ) as Response).body() + if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = result.apps[0] } @@ -616,10 +601,11 @@ class FusedAPIImpl @Inject constructor( suspend fun getCleanapkAppDetails(packageName: String): Pair { var fusedApp = FusedApp() val status = runCodeBlockWithTimeout({ - val result = cleanAPKRepository.searchApps( - keyword = packageName, - by = "package_name" - ).body() + val result = (cleanApkAppsRepository.getSearchResult( + packageName, + "package_name" + ) as Response).body() + if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = cleanAPKRepository.getAppOrPWADetailsByID(result.apps[0]._id).body()?.app @@ -672,10 +658,10 @@ class FusedAPIImpl @Inject constructor( */ for (packageName in packageNameList) { status = runCodeBlockWithTimeout({ - cleanAPKRepository.searchApps( - keyword = packageName, - by = "package_name" - ).body()?.run { + (cleanApkAppsRepository.getSearchResult( + packageName, + "package_name" + ) as Response).body()?.run { if (apps.isNotEmpty() && numberOfResults == 1) { fusedAppList.add( apps[0].apply { @@ -859,45 +845,6 @@ class FusedAPIImpl @Inject constructor( return Pair(response ?: FusedApp(), status) } - /* - * Categories-related internal functions - */ - - private suspend fun handleCleanApkCategories( - preferredApplicationType: String, - categoriesList: MutableList, - type: Category.Type - ): ResultStatus { - return runCodeBlockWithTimeout({ - val data = getCleanApkCategories(preferredApplicationType) - data?.let { category -> - categoriesList.addAll( - getFusedCategoryBasedOnCategoryType( - category, - type, - getCategoryTag(preferredApplicationType) - ) - ) - } - }) - } - - private fun getCategoryTag(preferredApplicationType: String): AppTag { - return if (preferredApplicationType == APP_TYPE_OPEN) { - AppTag.OpenSource(context.getString(R.string.open_source)) - } else { - AppTag.PWA(context.getString(R.string.pwa)) - } - } - - private suspend fun getCleanApkCategories(preferredApplicationType: String): Categories? { - return if (preferredApplicationType == APP_TYPE_OPEN) { - getOpenSourceCategories() - } else { - getPWAsCategories() - } - } - /* * Function to populate a given category list, from all GPlay categories, open source categories, * and PWAs. @@ -910,8 +857,7 @@ class FusedAPIImpl @Inject constructor( */ private suspend fun handleAllSourcesCategories( categoriesList: MutableList, - type: Category.Type, - authData: AuthData + type: CategoryType, ): Pair { var apiStatus = ResultStatus.OK var errorApplicationCategory = "" @@ -933,7 +879,6 @@ class FusedAPIImpl @Inject constructor( if (preferenceManagerModule.isGplaySelected()) { val gplayCategoryResult = fetchGplayCategories( type, - authData ) categoriesList.addAll(gplayCategoryResult.second) apiStatus = gplayCategoryResult.first @@ -944,14 +889,13 @@ class FusedAPIImpl @Inject constructor( } private suspend fun FusedAPIImpl.fetchGplayCategories( - type: Category.Type, - authData: AuthData, + type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" var apiStatus = ResultStatus.OK val categoryList = mutableListOf() runCodeBlockWithTimeout({ - val playResponse = gPlayAPIRepository.getCategoriesList(type, authData).map { app -> + val playResponse = (gplayRepository.getCategories(type) as List).map { app -> val category = app.transformToFusedCategory() updateCategoryDrawable(category) category @@ -968,7 +912,7 @@ class FusedAPIImpl @Inject constructor( } private suspend fun FusedAPIImpl.fetchPWACategories( - type: Category.Type, + type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" var apiStatus: ResultStatus = ResultStatus.OK @@ -992,7 +936,7 @@ class FusedAPIImpl @Inject constructor( } private suspend fun FusedAPIImpl.fetchOpenSourceCategories( - type: Category.Type, + type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" var apiStatus: ResultStatus = ResultStatus.OK @@ -1069,14 +1013,14 @@ class FusedAPIImpl @Inject constructor( private fun getFusedCategoryBasedOnCategoryType( categories: Categories, - categoryType: Category.Type, + categoryType: CategoryType, tag: AppTag ): List { return when (categoryType) { - Category.Type.APPLICATION -> { + CategoryType.APPLICATION -> { getAppsCategoriesAsFusedCategory(categories, tag) } - Category.Type.GAME -> { + CategoryType.GAMES -> { getGamesCategoriesAsFusedCategory(categories, tag) } } @@ -1126,17 +1070,11 @@ class FusedAPIImpl @Inject constructor( } private suspend fun getPWAsCategories(): Categories? { - return cleanAPKRepository.getCategoriesList( - CleanAPKInterface.APP_TYPE_PWA, - CleanAPKInterface.APP_SOURCE_ANY - ).body() + return (cleanApkPWARepository.getCategories() as Response).body() } private suspend fun getOpenSourceCategories(): Categories? { - return cleanAPKRepository.getCategoriesList( - CleanAPKInterface.APP_TYPE_ANY, - CleanAPKInterface.APP_SOURCE_FOSS - ).body() + return (cleanApkAppsRepository.getCategories() as Response).body() } private suspend fun getOpenSourceAppsResponse(category: String): Search? { @@ -1187,20 +1125,6 @@ class FusedAPIImpl @Inject constructor( return list } - private fun getGplaySearchResults( - query: String, - authData: AuthData - ): LiveData, Boolean>> { - val searchResults = - gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) - return searchResults.map { - Pair( - it.first, - it.second - ) - } - } - private suspend fun getGplaySearchResult( query: String, authData: AuthData diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt index 537b533c0..275c55370 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt @@ -22,13 +22,13 @@ import androidx.lifecycle.LiveData import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedCategory import foundation.e.apps.api.fused.data.FusedHome +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.utils.enums.FilterLevel import foundation.e.apps.utils.enums.Origin @@ -145,10 +145,9 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII } suspend fun getCategoriesList( - type: Category.Type, - authData: AuthData + type: CategoryType, ): Triple, String, ResultStatus> { - return fusedAPIImpl.getCategoriesList(type, authData) + return fusedAPIImpl.getCategoriesList(type) } suspend fun getSearchSuggestions(query: String, authData: AuthData): List { diff --git a/app/src/main/java/foundation/e/apps/api/fused/utils/CategoryUtils.kt b/app/src/main/java/foundation/e/apps/api/fused/utils/CategoryUtils.kt index c6048a94a..8b203a6b7 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/utils/CategoryUtils.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/utils/CategoryUtils.kt @@ -176,3 +176,7 @@ object CategoryUtils { } } } + +enum class CategoryType { + APPLICATION, GAMES +} diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 0024db814..57ebcc671 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -25,6 +25,7 @@ import com.aurora.gplayapi.helpers.* import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.StoreRepository +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository import kotlinx.coroutines.Dispatchers @@ -42,6 +43,8 @@ class GplayRepository @Inject constructor( private val loginSourceRepository: LoginSourceRepository ) : StoreRepository { + private val authData by lazy { loginSourceRepository.gplayAuth!! } + override suspend fun getHomeScreenData(): Any { val homeScreenData = mutableMapOf>() val homeElements = createTopChartElements() @@ -49,7 +52,7 @@ class GplayRepository @Inject constructor( homeElements.forEach { val chart = it.value.keys.iterator().next() val type = it.value.values.iterator().next() - val result = getTopApps(type, chart, loginSourceRepository.gplayAuth!!) + val result = getTopApps(type, chart, authData) homeScreenData[it.key] = result } @@ -65,14 +68,14 @@ class GplayRepository @Inject constructor( context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), ) - override suspend fun getSearchResult(query: String): Flow, Boolean>> { + override suspend fun getSearchResult(query: String, searchBy: String?): Flow, Boolean>> { return flow { /* * Variable names and logic made same as that of Aurora store. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 */ val searchHelper = - SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + SearchHelper(authData).using(gPlayHttpClient) val searchBundle = searchHelper.searchResults(query) val initialReplacedList = mutableListOf() @@ -137,7 +140,7 @@ class GplayRepository @Inject constructor( val searchData = mutableListOf() withContext(Dispatchers.IO) { val searchHelper = - SearchHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + SearchHelper(authData).using(gPlayHttpClient) searchData.addAll(searchHelper.searchSuggestions(query)) } return searchData.filter { it.suggestedQuery.isNotBlank() } @@ -145,12 +148,12 @@ class GplayRepository @Inject constructor( override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Any { if (paginationParameter != null && paginationParameter is StreamCluster) { - return getNextStreamCluster(loginSourceRepository.gplayAuth!!, paginationParameter) + return getNextStreamCluster(authData, paginationParameter) } if (paginationParameter != null && paginationParameter is StreamBundle) { return getNextStreamBundle( - loginSourceRepository.gplayAuth!!, + authData, category, paginationParameter ) @@ -158,7 +161,7 @@ class GplayRepository @Inject constructor( if (paginationParameter != null && paginationParameter is Pair<*, *>) { return getAdjustedFirstCluster( - loginSourceRepository.gplayAuth!!, + authData, paginationParameter.first as StreamBundle, paginationParameter.second as Int ) @@ -167,12 +170,29 @@ class GplayRepository @Inject constructor( return getGplayApps(category) } + override suspend fun getCategories(type: CategoryType?): List { + val categoryList = mutableListOf() + if (type == null) { + return categoryList + } + + withContext(Dispatchers.IO) { + val categoryHelper = CategoryHelper(authData).using(gPlayHttpClient) + categoryList.addAll(categoryHelper.getAllCategoriesList(getCategoryType(type))) + } + return categoryList + } + + private fun getCategoryType(type: CategoryType): Category.Type { + return if (type == CategoryType.APPLICATION) Category.Type.APPLICATION else Category.Type.GAME + } + private suspend fun getGplayApps(category: String): List { val list = mutableListOf() withContext(Dispatchers.IO) { supervisorScope { val categoryHelper = - CategoryHelper(loginSourceRepository.gplayAuth!!).using(gPlayHttpClient) + CategoryHelper(authData).using(gPlayHttpClient) var streamBundle: StreamBundle var nextStreamBundleUrl = category diff --git a/app/src/main/java/foundation/e/apps/categories/AppsFragment.kt b/app/src/main/java/foundation/e/apps/categories/AppsFragment.kt index 07497a782..0915792a6 100644 --- a/app/src/main/java/foundation/e/apps/categories/AppsFragment.kt +++ b/app/src/main/java/foundation/e/apps/categories/AppsFragment.kt @@ -24,10 +24,10 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager -import com.aurora.gplayapi.data.models.Category import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.MainActivityViewModel import foundation.e.apps.R +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.categories.model.CategoriesRVAdapter import foundation.e.apps.databinding.FragmentAppsBinding import foundation.e.apps.login.AuthObject @@ -73,7 +73,7 @@ class AppsFragment : TimeoutFragment(R.layout.fragment_apps) { } override fun loadData(authObjectList: List) { - categoriesViewModel.loadData(Category.Type.APPLICATION, authObjectList) { + categoriesViewModel.loadData(CategoryType.APPLICATION, authObjectList) { clearAndRestartGPlayLogin() true } diff --git a/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt b/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt index d505cf136..9cb652112 100644 --- a/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt +++ b/app/src/main/java/foundation/e/apps/categories/CategoriesViewModel.kt @@ -21,10 +21,10 @@ package foundation.e.apps.categories import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData -import com.aurora.gplayapi.data.models.Category import dagger.hilt.android.lifecycle.HiltViewModel import foundation.e.apps.api.fused.FusedAPIRepository import foundation.e.apps.api.fused.data.FusedCategory +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.login.AuthObject import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.exceptions.CleanApkException @@ -42,7 +42,7 @@ class CategoriesViewModel @Inject constructor( MutableLiveData() fun loadData( - type: Category.Type, + type: CategoryType, authObjectList: List, retryBlock: (failedObjects: List) -> Boolean, ) { @@ -60,9 +60,9 @@ class CategoriesViewModel @Inject constructor( }, retryBlock) } - fun getCategoriesList(type: Category.Type, authData: AuthData) { + fun getCategoriesList(type: CategoryType, authData: AuthData) { viewModelScope.launch { - val categoriesData = fusedAPIRepository.getCategoriesList(type, authData) + val categoriesData = fusedAPIRepository.getCategoriesList(type) categoriesList.postValue(categoriesData) val status = categoriesData.third diff --git a/app/src/main/java/foundation/e/apps/categories/GamesFragment.kt b/app/src/main/java/foundation/e/apps/categories/GamesFragment.kt index f5d9fe62b..cb2499528 100644 --- a/app/src/main/java/foundation/e/apps/categories/GamesFragment.kt +++ b/app/src/main/java/foundation/e/apps/categories/GamesFragment.kt @@ -24,10 +24,10 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager -import com.aurora.gplayapi.data.models.Category import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.MainActivityViewModel import foundation.e.apps.R +import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.categories.model.CategoriesRVAdapter import foundation.e.apps.databinding.FragmentGamesBinding import foundation.e.apps.login.AuthObject @@ -73,7 +73,7 @@ class GamesFragment : TimeoutFragment(R.layout.fragment_games) { } override fun loadData(authObjectList: List) { - categoriesViewModel.loadData(Category.Type.GAME, authObjectList) { + categoriesViewModel.loadData(CategoryType.GAMES, authObjectList) { clearAndRestartGPlayLogin() true } -- GitLab From b656005b67cda54b78c12f006c41957ba6a3ba29 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Mon, 15 May 2023 12:00:40 +0600 Subject: [PATCH 09/13] intoduced iterfaces for downloading stuffs --- .../e/apps/api/DownloadInfoFetcher.kt | 6 ++ .../e/apps/api/OnDemandModuleFetcher.kt | 12 ++++ .../foundation/e/apps/api/StoreRepository.kt | 2 + .../api/cleanapk/CleanApkAppsRepository.kt | 28 ++++++++- .../api/cleanapk/CleanApkPWARepository.kt | 22 ++++++- .../e/apps/api/fused/FusedAPIImpl.kt | 43 +++++++------ .../e/apps/api/fused/FusedAPIRepository.kt | 2 +- .../e/apps/api/gplay/GplayRepository.kt | 63 ++++++++++++++++++- .../e/apps/di/NamedRepositoryModule.kt | 14 +++-- 9 files changed, 161 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt create mode 100644 app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt diff --git a/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt b/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt new file mode 100644 index 000000000..71e7c5dd1 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt @@ -0,0 +1,6 @@ +package foundation.e.apps.api + + +interface DownloadInfoFetcher { + suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any? = null, offerType: Int = -1): Any +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt b/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt new file mode 100644 index 000000000..c0f511ad6 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt @@ -0,0 +1,12 @@ +package foundation.e.apps.api + +import foundation.e.apps.manager.database.fusedDownload.FusedDownload + +interface OnDemandModuleFetcher { + suspend fun getOnDemandModule( + packageName: String, + moduleName: String, + versionCode: Int, + offerType: Int + ): Any +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt index 364e5a982..4ada8b8cb 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/StoreRepository.kt @@ -26,4 +26,6 @@ interface StoreRepository { suspend fun getSearchSuggestions(query: String): Any suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Any suspend fun getCategories(type: CategoryType? = null): Any + suspend fun getAppDetails(packageNameOrId: String): Any? + suspend fun getAppsDetails(packageNamesOrIds: List): Any } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt index b614524eb..831d07fdb 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt @@ -18,16 +18,21 @@ package foundation.e.apps.api.cleanapk +import foundation.e.apps.api.DownloadInfoFetcher import foundation.e.apps.api.StoreRepository +import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories +import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search import foundation.e.apps.api.fused.utils.CategoryType +import foundation.e.apps.manager.database.fusedDownload.FusedDownload import retrofit2.Response class CleanApkAppsRepository( private val cleanAPKInterface: CleanAPKInterface, -) : StoreRepository { + private val cleanApkAppDetailApi: CleanApkAppDetailApi +) : StoreRepository, DownloadInfoFetcher { override suspend fun getHomeScreenData(): Response { return cleanAPKInterface.getHomeScreenData( @@ -70,4 +75,25 @@ class CleanApkAppsRepository( CleanAPKInterface.APP_SOURCE_FOSS ) } + + override suspend fun getAppDetails(packageNameOrId: String): Response { + return cleanApkAppDetailApi.getAppOrPWADetailsByID(packageNameOrId, null, null) + } + + override suspend fun getAppsDetails(packageNamesOrIds: List): Any { + val applications = mutableListOf() + + packageNamesOrIds.forEach { + val applicationResponse = getAppDetails(it) + if (applicationResponse.isSuccessful && applicationResponse.body() != null) { + applications.add(applicationResponse.body()!!) + } + } + return applications + } + + override suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any?, offerType: Int): Response { + val version = versionCode?.let { it as String } + return cleanAPKInterface.getDownloadInfo(idOrPackageName, version, null) + } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index e5395133a..934a2644f 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -19,12 +19,16 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.StoreRepository +import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search import foundation.e.apps.api.fused.utils.CategoryType import retrofit2.Response -class CleanApkPWARepository(private val cleanAPKInterface: CleanAPKInterface) : StoreRepository { +class CleanApkPWARepository( + private val cleanAPKInterface: CleanAPKInterface, + private val cleanApkAppDetailApi: CleanApkAppDetailApi +) : StoreRepository { override suspend fun getHomeScreenData(): Any { return cleanAPKInterface.getHomeScreenData( @@ -64,4 +68,20 @@ class CleanApkPWARepository(private val cleanAPKInterface: CleanAPKInterface) : CleanAPKInterface.APP_SOURCE_ANY ) } + + override suspend fun getAppDetails(packageNameOrId: String): Response { + return cleanApkAppDetailApi.getAppOrPWADetailsByID(packageNameOrId, null, null) + } + + override suspend fun getAppsDetails(packageNamesOrIds: List): Any { + val applications = mutableListOf() + + packageNamesOrIds.forEach { + val applicationResponse = getAppDetails(it) + if (applicationResponse.isSuccessful && applicationResponse.body() != null) { + applications.add(applicationResponse.body()!!) + } + } + return applications + } } diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index ac50bbe16..1618551a2 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -24,17 +24,20 @@ import androidx.lifecycle.* import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import androidx.lifecycle.liveData -import androidx.lifecycle.map import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.* import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.api.DownloadInfoFetcher import foundation.e.apps.R +import foundation.e.apps.api.OnDemandModuleFetcher import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.CleanAPKInterface import foundation.e.apps.api.cleanapk.CleanAPKRepository +import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories +import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.home.Home import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search @@ -71,8 +74,6 @@ typealias FusedHomeDeferred = Deferred>> @Singleton class FusedAPIImpl @Inject constructor( - private val cleanAPKRepository: CleanAPKRepository, - private val gPlayAPIRepository: GPlayAPIRepository, private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, @@ -490,19 +491,17 @@ class FusedAPIImpl @Inject constructor( } suspend fun getOnDemandModule( - authData: AuthData, packageName: String, moduleName: String, versionCode: Int, offerType: Int ): String? { - val list = gPlayAPIRepository.getOnDemandModule( + val list = (gplayRepository as OnDemandModuleFetcher).getOnDemandModule( packageName, moduleName, versionCode, offerType, - authData - ) + ) as List for (element in list) { if (element.name == "$moduleName.apk") { return element.url @@ -519,17 +518,18 @@ class FusedAPIImpl @Inject constructor( val list = mutableListOf() when (origin) { Origin.CLEANAPK -> { - val downloadInfo = cleanAPKRepository.getDownloadInfo(fusedDownload.id).body() + val downloadInfo = + ((cleanApkAppsRepository as DownloadInfoFetcher).getDownloadInfo(fusedDownload.id) as Response).body() downloadInfo?.download_data?.download_link?.let { list.add(it) } fusedDownload.signature = downloadInfo?.download_data?.signature ?: "" } Origin.GPLAY -> { - val downloadList = gPlayAPIRepository.getDownloadInfo( - fusedDownload.packageName, - fusedDownload.versionCode, - fusedDownload.offerType, - authData - ) + val downloadList = + (gplayRepository as DownloadInfoFetcher).getDownloadInfo( + fusedDownload.packageName, + fusedDownload.versionCode, + fusedDownload.offerType + ) as List fusedDownload.files = downloadList list.addAll(downloadList.map { it.url }) } @@ -540,7 +540,7 @@ class FusedAPIImpl @Inject constructor( } suspend fun getOSSDownloadInfo(id: String, version: String?) = - cleanAPKRepository.getDownloadInfo(id, version) + (cleanApkAppsRepository as DownloadInfoFetcher).getDownloadInfo(id, version) as Response suspend fun getPWAApps(category: String): ResultSupreme> { val list = mutableListOf() @@ -639,7 +639,7 @@ class FusedAPIImpl @Inject constructor( if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = - cleanAPKRepository.getAppOrPWADetailsByID(result.apps[0]._id).body()?.app + (cleanApkAppsRepository.getAppDetails(result.apps[0]._id) as Response).body()?.app ?: FusedApp() } fusedApp.updateFilterLevel(null) @@ -728,7 +728,7 @@ class FusedAPIImpl @Inject constructor( * Old code moved from getApplicationDetails() */ val status = runCodeBlockWithTimeout({ - gPlayAPIRepository.getAppDetails(packageNameList, authData).forEach { app -> + (gplayRepository.getAppsDetails(packageNameList) as List).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. @@ -810,7 +810,7 @@ class FusedAPIImpl @Inject constructor( * Check if app details can be shown. If not then remove the app from lists. */ try { - gPlayAPIRepository.getAppDetails(fusedApp.package_name, authData) + gplayRepository.getAppDetails(fusedApp.package_name) } catch (e: Exception) { return FilterLevel.DATA } @@ -820,11 +820,10 @@ class FusedAPIImpl @Inject constructor( * If not then change "Install" button to "N/A" */ try { - gPlayAPIRepository.getDownloadInfo( + (gplayRepository as DownloadInfoFetcher).getDownloadInfo( fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type, - authData ) } catch (e: Exception) { return FilterLevel.UI @@ -860,9 +859,9 @@ class FusedAPIImpl @Inject constructor( val status = runCodeBlockWithTimeout({ response = if (origin == Origin.CLEANAPK) { - cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app + (cleanApkAppsRepository.getAppDetails(id) as Response).body()?.app } else { - val app = gPlayAPIRepository.getAppDetails(packageName, authData) + val app = gplayRepository.getAppDetails(packageName) as App? app?.transformToFusedApp() } response?.let { diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt index 148a50f82..71b1e5372 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt @@ -144,7 +144,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII versionCode: Int, offerType: Int ): String? { - return fusedAPIImpl.getOnDemandModule(authData, packageName, moduleName, versionCode, offerType) + return fusedAPIImpl.getOnDemandModule(packageName, moduleName, versionCode, offerType) } suspend fun getCategoriesList( diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt index 27c5ab58f..7997c78bf 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt @@ -23,11 +23,14 @@ import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.* import com.aurora.gplayapi.helpers.* import dagger.hilt.android.qualifiers.ApplicationContext +import foundation.e.apps.api.DownloadInfoFetcher import foundation.e.apps.R +import foundation.e.apps.api.OnDemandModuleFetcher import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository +import foundation.e.apps.manager.database.fusedDownload.FusedDownload import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector @@ -41,7 +44,7 @@ class GplayRepository @Inject constructor( @ApplicationContext private val context: Context, private val gPlayHttpClient: GPlayHttpClient, private val loginSourceRepository: LoginSourceRepository -) : StoreRepository { +) : StoreRepository, DownloadInfoFetcher, OnDemandModuleFetcher { private val authData by lazy { loginSourceRepository.gplayAuth!! } @@ -68,7 +71,10 @@ class GplayRepository @Inject constructor( context.getString(R.string.movers_shakers_games) to mapOf(TopChartsHelper.Chart.MOVERS_SHAKERS to TopChartsHelper.Type.GAME), ) - override suspend fun getSearchResult(query: String, searchBy: String?): Flow, Boolean>> { + override suspend fun getSearchResult( + query: String, + searchBy: String? + ): Flow, Boolean>> { return flow { /* * Variable names and logic made same as that of Aurora store. @@ -182,6 +188,24 @@ class GplayRepository @Inject constructor( return categoryList } + override suspend fun getAppDetails(packageNameOrId: String): App? { + var appDetails: App? + withContext(Dispatchers.IO) { + val appDetailsHelper = AppDetailsHelper(authData).using(gPlayHttpClient) + appDetails = appDetailsHelper.getAppByPackageName(packageNameOrId) + } + return appDetails + } + + override suspend fun getAppsDetails(packageNamesOrIds: List): List { + val appDetailsList = mutableListOf() + withContext(Dispatchers.IO) { + val appDetailsHelper = AppDetailsHelper(authData).using(gPlayHttpClient) + appDetailsList.addAll(appDetailsHelper.getAppByPackageName(packageNamesOrIds)) + } + return appDetailsList + } + private fun getCategoryType(type: CategoryType): Category.Type { return if (type == CategoryType.APPLICATION) Category.Type.APPLICATION else Category.Type.GAME } @@ -447,4 +471,39 @@ class GplayRepository @Inject constructor( } return topApps } + + override suspend fun getDownloadInfo( + idOrPackageName: String, + versionCode: Any?, + offerType: Int + ): List { + val downloadData = mutableListOf() + withContext(Dispatchers.IO) { + val version = versionCode?.let { it as Int } ?: -1 + val purchaseHelper = PurchaseHelper(authData).using(gPlayHttpClient) + downloadData.addAll(purchaseHelper.purchase(idOrPackageName, version, offerType)) + } + return downloadData + } + + override suspend fun getOnDemandModule( + packageName: String, + moduleName: String, + versionCode: Int, + offerType: Int + ): List { + val downloadData = mutableListOf() + withContext(Dispatchers.IO) { + val purchaseHelper = PurchaseHelper(authData).using(gPlayHttpClient) + downloadData.addAll( + purchaseHelper.getOnDemandModule( + packageName, + moduleName, + versionCode, + offerType + ) + ) + } + return downloadData + } } diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index cee2c53b1..64f1ae35b 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -53,14 +53,20 @@ object NamedRepositoryModule { @Singleton @Provides @Named("cleanApkAppsRepository") - fun getCleanApkAppsRepository(cleanAPKInterface: CleanAPKInterface): StoreRepository { - return CleanApkAppsRepository(cleanAPKInterface) + fun getCleanApkAppsRepository( + cleanAPKInterface: CleanAPKInterface, + cleanApkAppDetailApi: CleanApkAppDetailApi + ): StoreRepository { + return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) } @Singleton @Provides @Named("cleanApkPWARepository") - fun getCleanApkPWARepository(cleanAPKInterface: CleanAPKInterface): StoreRepository { - return CleanApkPWARepository(cleanAPKInterface) + fun getCleanApkPWARepository( + cleanAPKInterface: CleanAPKInterface, + cleanApkAppDetailApi: CleanApkAppDetailApi + ): StoreRepository { + return CleanApkPWARepository(cleanAPKInterface, cleanApkAppDetailApi) } } -- GitLab From 2fcc8767f8b4bc7dd43e574746fc3bc01affd962 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Thu, 18 May 2023 21:59:33 +0600 Subject: [PATCH 10/13] fixed syntax error --- app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 6103720bd..20984bab2 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -86,7 +86,7 @@ class FusedAPIImpl @Inject constructor( private val pkgManagerModule: PkgManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, - private val fdroidWebInterface: FdroidWebInterface,Build Analyzer detected new build performance issues Review to improve build performance + private val fdroidWebInterface: FdroidWebInterface, @Named("gplayRepository") private val gplayRepository: StoreRepository, @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreRepository, @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreRepository, -- GitLab From da72ceebf2832c43388062ddfe326949a554976c Mon Sep 17 00:00:00 2001 From: hasibprince Date: Tue, 16 May 2023 06:21:43 +0600 Subject: [PATCH 11/13] some more refactoring --- ...reRepository.kt => BaseStoreRepository.kt} | 9 +- .../e/apps/api/DownloadInfoFetcher.kt | 6 - .../e/apps/api/OnDemandModuleFetcher.kt | 12 -- .../e/apps/api/cleanapk/CleanAPKRepository.kt | 32 ++--- ...ilApi.kt => CleanApkAppDetailsRetrofit.kt} | 2 +- ...itory.kt => CleanApkAppsRepositoryImpl.kt} | 60 +++------ .../cleanapk/CleanApkDownloadInfoFetcher.kt | 8 ++ .../api/cleanapk/CleanApkPWARepository.kt | 54 +++----- .../e/apps/api/cleanapk/CleanApkRepository.kt | 31 +++++ ...eanAPKInterface.kt => CleanApkRetrofit.kt} | 2 +- .../e/apps/api/cleanapk/RetrofitModule.kt | 16 +-- .../e/apps/api/fused/FusedAPIImpl.kt | 119 +++++++++--------- .../e/apps/api/fused/FusedAPIRepository.kt | 26 ++-- .../e/apps/api/gplay/GplayStoreRepository.kt | 46 +++++++ ...ository.kt => GplayStoreRepositoryImpl.kt} | 18 +-- .../e/apps/application/ApplicationFragment.kt | 4 +- .../model/ApplicationScreenshotsRVAdapter.kt | 4 +- .../application/model/ScreenshotRVAdapter.kt | 4 +- .../ApplicationListRVAdapter.kt | 4 +- .../e/apps/di/NamedRepositoryModule.kt | 31 ++--- .../e/apps/home/model/HomeChildRVAdapter.kt | 4 +- .../e/apps/splitinstall/SplitInstallBinder.kt | 11 +- .../e/apps/updates/manager/UpdatesWorker.kt | 4 +- .../foundation/e/apps/FusedApiImplTest.kt | 14 +-- 24 files changed, 260 insertions(+), 261 deletions(-) rename app/src/main/java/foundation/e/apps/api/{StoreRepository.kt => BaseStoreRepository.kt} (66%) delete mode 100644 app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt delete mode 100644 app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt rename app/src/main/java/foundation/e/apps/api/cleanapk/{CleanApkAppDetailApi.kt => CleanApkAppDetailsRetrofit.kt} (97%) rename app/src/main/java/foundation/e/apps/api/cleanapk/{CleanApkAppsRepository.kt => CleanApkAppsRepositoryImpl.kt} (50%) create mode 100644 app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt create mode 100644 app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt rename app/src/main/java/foundation/e/apps/api/cleanapk/{CleanAPKInterface.kt => CleanApkRetrofit.kt} (96%) create mode 100644 app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt rename app/src/main/java/foundation/e/apps/api/gplay/{GplayRepository.kt => GplayStoreRepositoryImpl.kt} (95%) diff --git a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt b/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt similarity index 66% rename from app/src/main/java/foundation/e/apps/api/StoreRepository.kt rename to app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt index 4ada8b8cb..0173774d6 100644 --- a/app/src/main/java/foundation/e/apps/api/StoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt @@ -18,14 +18,9 @@ package foundation.e.apps.api -import foundation.e.apps.api.fused.utils.CategoryType -interface StoreRepository { +interface BaseStoreRepository { suspend fun getHomeScreenData(): Any - suspend fun getSearchResult(query: String, searchBy: String? = null): Any - suspend fun getSearchSuggestions(query: String): Any - suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Any - suspend fun getCategories(type: CategoryType? = null): Any suspend fun getAppDetails(packageNameOrId: String): Any? - suspend fun getAppsDetails(packageNamesOrIds: List): Any } + diff --git a/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt b/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt deleted file mode 100644 index 71e7c5dd1..000000000 --- a/app/src/main/java/foundation/e/apps/api/DownloadInfoFetcher.kt +++ /dev/null @@ -1,6 +0,0 @@ -package foundation.e.apps.api - - -interface DownloadInfoFetcher { - suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any? = null, offerType: Int = -1): Any -} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt b/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt deleted file mode 100644 index c0f511ad6..000000000 --- a/app/src/main/java/foundation/e/apps/api/OnDemandModuleFetcher.kt +++ /dev/null @@ -1,12 +0,0 @@ -package foundation.e.apps.api - -import foundation.e.apps.manager.database.fusedDownload.FusedDownload - -interface OnDemandModuleFetcher { - suspend fun getOnDemandModule( - packageName: String, - moduleName: String, - versionCode: Int, - offerType: Int - ): Any -} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt index 45c47a58d..fc77fbb13 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKRepository.kt @@ -29,15 +29,15 @@ import javax.inject.Inject @OpenForTesting class CleanAPKRepository @Inject constructor( - private val cleanAPKInterface: CleanAPKInterface, - private val cleanApkAppDetailApi: CleanApkAppDetailApi + private val cleanAPKRetrofit: CleanApkRetrofit, + private val cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit ) { suspend fun getHomeScreenData( - type: String = CleanAPKInterface.APP_TYPE_ANY, - source: String = CleanAPKInterface.APP_SOURCE_ANY + type: String = CleanApkRetrofit.APP_TYPE_ANY, + source: String = CleanApkRetrofit.APP_SOURCE_ANY ): Response { - return cleanAPKInterface.getHomeScreenData(type, source) + return cleanAPKRetrofit.getHomeScreenData(type, source) } suspend fun getAppOrPWADetailsByID( @@ -45,28 +45,28 @@ class CleanAPKRepository @Inject constructor( architectures: List? = null, type: String? = null ): Response { - return cleanApkAppDetailApi.getAppOrPWADetailsByID(id, architectures, type) + return cleanApkAppDetailsRetrofit.getAppOrPWADetailsByID(id, architectures, type) } suspend fun searchApps( keyword: String, - source: String = CleanAPKInterface.APP_SOURCE_FOSS, - type: String = CleanAPKInterface.APP_TYPE_ANY, + source: String = CleanApkRetrofit.APP_SOURCE_FOSS, + type: String = CleanApkRetrofit.APP_TYPE_ANY, nres: Int = 20, page: Int = 1, by: String? = null ): Response { - return cleanAPKInterface.searchApps(keyword, source, type, nres, page, by) + return cleanAPKRetrofit.searchApps(keyword, source, type, nres, page, by) } suspend fun listApps( category: String, - source: String = CleanAPKInterface.APP_SOURCE_FOSS, - type: String = CleanAPKInterface.APP_TYPE_ANY, + source: String = CleanApkRetrofit.APP_SOURCE_FOSS, + type: String = CleanApkRetrofit.APP_TYPE_ANY, nres: Int = 20, page: Int = 1, ): Response { - return cleanAPKInterface.listApps(category, source, type, nres, page) + return cleanAPKRetrofit.listApps(category, source, type, nres, page) } suspend fun getDownloadInfo( @@ -74,13 +74,13 @@ class CleanAPKRepository @Inject constructor( version: String? = null, architecture: String? = null ): Response { - return cleanAPKInterface.getDownloadInfo(id, version, architecture) + return cleanAPKRetrofit.getDownloadInfo(id, version, architecture) } suspend fun getCategoriesList( - type: String = CleanAPKInterface.APP_TYPE_ANY, - source: String = CleanAPKInterface.APP_SOURCE_ANY + type: String = CleanApkRetrofit.APP_TYPE_ANY, + source: String = CleanApkRetrofit.APP_SOURCE_ANY ): Response { - return cleanAPKInterface.getCategoriesList(type, source) + return cleanAPKRetrofit.getCategoriesList(type, source) } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailsRetrofit.kt similarity index 97% rename from app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt rename to app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailsRetrofit.kt index f6795e12c..9ab5b6f47 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailApi.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppDetailsRetrofit.kt @@ -25,7 +25,7 @@ import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Query -interface CleanApkAppDetailApi { +interface CleanApkAppDetailsRetrofit { companion object { // API endpoints diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt similarity index 50% rename from app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt rename to app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt index 831d07fdb..1deb2c7e5 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt @@ -18,82 +18,62 @@ package foundation.e.apps.api.cleanapk -import foundation.e.apps.api.DownloadInfoFetcher -import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search -import foundation.e.apps.api.fused.utils.CategoryType -import foundation.e.apps.manager.database.fusedDownload.FusedDownload import retrofit2.Response -class CleanApkAppsRepository( - private val cleanAPKInterface: CleanAPKInterface, - private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreRepository, DownloadInfoFetcher { +class CleanApkAppsRepositoryImpl( + private val cleanApkRetrofit: CleanApkRetrofit, + private val cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit +) : CleanApkRepository, CleanApkDownloadInfoFetcher{ override suspend fun getHomeScreenData(): Response { - return cleanAPKInterface.getHomeScreenData( - CleanAPKInterface.APP_TYPE_ANY, - CleanAPKInterface.APP_SOURCE_FOSS + return cleanApkRetrofit.getHomeScreenData( + CleanApkRetrofit.APP_TYPE_ANY, + CleanApkRetrofit.APP_SOURCE_FOSS ) } override suspend fun getSearchResult(query: String, searchBy: String?): Response { - return cleanAPKInterface.searchApps( + return cleanApkRetrofit.searchApps( query, - CleanAPKInterface.APP_SOURCE_FOSS, - CleanAPKInterface.APP_TYPE_ANY, + CleanApkRetrofit.APP_SOURCE_FOSS, + CleanApkRetrofit.APP_TYPE_ANY, 20, 1, searchBy ) } - override suspend fun getSearchSuggestions(query: String): Any { - return Any() - } - override suspend fun getAppsByCategory( category: String, paginationParameter: Any? ): Response { - return cleanAPKInterface.listApps( + return cleanApkRetrofit.listApps( category, - CleanAPKInterface.APP_SOURCE_FOSS, - CleanAPKInterface.APP_TYPE_ANY, + CleanApkRetrofit.APP_SOURCE_FOSS, + CleanApkRetrofit.APP_TYPE_ANY, 20, 1 ) } - override suspend fun getCategories(type: CategoryType?): Response { - return cleanAPKInterface.getCategoriesList( - CleanAPKInterface.APP_TYPE_ANY, - CleanAPKInterface.APP_SOURCE_FOSS + override suspend fun getCategories(): Response { + return cleanApkRetrofit.getCategoriesList( + CleanApkRetrofit.APP_TYPE_ANY, + CleanApkRetrofit.APP_SOURCE_FOSS ) } override suspend fun getAppDetails(packageNameOrId: String): Response { - return cleanApkAppDetailApi.getAppOrPWADetailsByID(packageNameOrId, null, null) - } - - override suspend fun getAppsDetails(packageNamesOrIds: List): Any { - val applications = mutableListOf() - - packageNamesOrIds.forEach { - val applicationResponse = getAppDetails(it) - if (applicationResponse.isSuccessful && applicationResponse.body() != null) { - applications.add(applicationResponse.body()!!) - } - } - return applications + return cleanApkAppDetailsRetrofit.getAppOrPWADetailsByID(packageNameOrId, null, null) } - override suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any?, offerType: Int): Response { + override suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any?): Response { val version = versionCode?.let { it as String } - return cleanAPKInterface.getDownloadInfo(idOrPackageName, version, null) + return cleanApkRetrofit.getDownloadInfo(idOrPackageName, version, null) } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt new file mode 100644 index 000000000..90f5b5346 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt @@ -0,0 +1,8 @@ +package foundation.e.apps.api.cleanapk + +import foundation.e.apps.api.cleanapk.data.download.Download +import retrofit2.Response + +interface CleanApkDownloadInfoFetcher { + suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any? = null): Response +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index 934a2644f..5d17d109f 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -18,70 +18,52 @@ package foundation.e.apps.api.cleanapk -import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search -import foundation.e.apps.api.fused.utils.CategoryType import retrofit2.Response class CleanApkPWARepository( - private val cleanAPKInterface: CleanAPKInterface, - private val cleanApkAppDetailApi: CleanApkAppDetailApi -) : StoreRepository { + private val cleanAPKRetrofit: CleanApkRetrofit, + private val cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit +) : CleanApkRepository { override suspend fun getHomeScreenData(): Any { - return cleanAPKInterface.getHomeScreenData( - CleanAPKInterface.APP_TYPE_PWA, - CleanAPKInterface.APP_SOURCE_ANY + return cleanAPKRetrofit.getHomeScreenData( + CleanApkRetrofit.APP_TYPE_PWA, + CleanApkRetrofit.APP_SOURCE_ANY ) } override suspend fun getSearchResult(query: String, searchBy: String?): Response { - return cleanAPKInterface.searchApps( + return cleanAPKRetrofit.searchApps( query, - CleanAPKInterface.APP_SOURCE_ANY, - CleanAPKInterface.APP_TYPE_PWA, + CleanApkRetrofit.APP_SOURCE_ANY, + CleanApkRetrofit.APP_TYPE_PWA, 20, 1, searchBy ) } - override suspend fun getSearchSuggestions(query: String): Any { - TODO("Not yet implemented") - } - - override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Any { - return cleanAPKInterface.listApps( + override suspend fun getAppsByCategory(category: String, paginationParameter: Any?): Response { + return cleanAPKRetrofit.listApps( category, - CleanAPKInterface.APP_SOURCE_FOSS, - CleanAPKInterface.APP_TYPE_PWA, + CleanApkRetrofit.APP_SOURCE_ANY, + CleanApkRetrofit.APP_TYPE_PWA, 20, 1 ) } - override suspend fun getCategories(type: CategoryType?): Response { - return cleanAPKInterface.getCategoriesList( - CleanAPKInterface.APP_TYPE_PWA, - CleanAPKInterface.APP_SOURCE_ANY + override suspend fun getCategories(): Response { + return cleanAPKRetrofit.getCategoriesList( + CleanApkRetrofit.APP_TYPE_PWA, + CleanApkRetrofit.APP_SOURCE_ANY ) } override suspend fun getAppDetails(packageNameOrId: String): Response { - return cleanApkAppDetailApi.getAppOrPWADetailsByID(packageNameOrId, null, null) - } - - override suspend fun getAppsDetails(packageNamesOrIds: List): Any { - val applications = mutableListOf() - - packageNamesOrIds.forEach { - val applicationResponse = getAppDetails(it) - if (applicationResponse.isSuccessful && applicationResponse.body() != null) { - applications.add(applicationResponse.body()!!) - } - } - return applications + return cleanApkAppDetailsRetrofit.getAppOrPWADetailsByID(packageNameOrId, null, null) } } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt new file mode 100644 index 000000000..8838b51d6 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt @@ -0,0 +1,31 @@ +/* + * 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.api.cleanapk + +import foundation.e.apps.api.BaseStoreRepository +import foundation.e.apps.api.cleanapk.data.categories.Categories +import foundation.e.apps.api.cleanapk.data.download.Download +import foundation.e.apps.api.cleanapk.data.search.Search +import retrofit2.Response + +interface CleanApkRepository : BaseStoreRepository { + suspend fun getSearchResult(query: String, searchBy: String? = null): Response + suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Response + suspend fun getCategories(): Response +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKInterface.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRetrofit.kt similarity index 96% rename from app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKInterface.kt rename to app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRetrofit.kt index 6a9599335..4feb18bc5 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanAPKInterface.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRetrofit.kt @@ -27,7 +27,7 @@ import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Query -interface CleanAPKInterface { +interface CleanApkRetrofit { companion object { // API endpoints diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt index b03baa0b3..26e8f8cad 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/RetrofitModule.kt @@ -57,35 +57,35 @@ object RetrofitModule { /** * Provides an instance of Retrofit to work with CleanAPK API - * @return instance of [CleanAPKInterface] + * @return instance of [CleanApkRetrofit] */ @Singleton @Provides - fun provideCleanAPKInterface(okHttpClient: OkHttpClient, moshi: Moshi): CleanAPKInterface { + fun provideCleanAPKInterface(okHttpClient: OkHttpClient, moshi: Moshi): CleanApkRetrofit { return Retrofit.Builder() - .baseUrl(CleanAPKInterface.BASE_URL) + .baseUrl(CleanApkRetrofit.BASE_URL) .client(okHttpClient) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() - .create(CleanAPKInterface::class.java) + .create(CleanApkRetrofit::class.java) } /** * Provides an instance of Retrofit to work with CleanAPK API - * @return instance of [CleanApkAppDetailApi] + * @return instance of [CleanApkAppDetailsRetrofit] */ @Singleton @Provides fun provideCleanAPKDetailApi( okHttpClient: OkHttpClient, @Named("gsonCustomAdapter") gson: Gson - ): CleanApkAppDetailApi { + ): CleanApkAppDetailsRetrofit { return Retrofit.Builder() - .baseUrl(CleanAPKInterface.BASE_URL) + .baseUrl(CleanApkRetrofit.BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create(gson)) .build() - .create(CleanApkAppDetailApi::class.java) + .create(CleanApkAppDetailsRetrofit::class.java) } @Singleton diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 1618551a2..180b3ecbf 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -20,24 +20,25 @@ package foundation.e.apps.api.fused import android.content.Context import android.text.format.Formatter -import androidx.lifecycle.* import androidx.lifecycle.LiveData import androidx.lifecycle.asLiveData import androidx.lifecycle.liveData import com.aurora.gplayapi.Constants import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.* +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.Category +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.gplayapi.data.models.Artwork import dagger.hilt.android.qualifiers.ApplicationContext -import foundation.e.apps.api.DownloadInfoFetcher import foundation.e.apps.R -import foundation.e.apps.api.OnDemandModuleFetcher import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.StoreRepository -import foundation.e.apps.api.cleanapk.CleanAPKInterface -import foundation.e.apps.api.cleanapk.CleanAPKRepository +import foundation.e.apps.api.cleanapk.CleanApkRetrofit +import foundation.e.apps.api.cleanapk.CleanApkDownloadInfoFetcher +import foundation.e.apps.api.cleanapk.CleanApkRepository import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories -import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.home.Home import foundation.e.apps.api.cleanapk.data.home.HomeScreen import foundation.e.apps.api.cleanapk.data.search.Search @@ -48,12 +49,19 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.api.fused.utils.CategoryUtils -import foundation.e.apps.api.gplay.GPlayAPIRepository +import foundation.e.apps.api.gplay.GplayStoreRepository import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.Constants.timeoutDurationInMillis -import foundation.e.apps.utils.enums.* +import foundation.e.apps.utils.enums.ResultStatus +import foundation.e.apps.utils.enums.Status +import foundation.e.apps.utils.enums.Source +import foundation.e.apps.utils.enums.FilterLevel +import foundation.e.apps.utils.enums.AppTag +import foundation.e.apps.utils.enums.isUnFiltered +import foundation.e.apps.utils.enums.Origin +import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.Deferred @@ -78,9 +86,9 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, - @Named("gplayRepository") private val gplayRepository: StoreRepository, - @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: StoreRepository, - @Named("cleanApkPWARepository") private val cleanApkPWARepository: StoreRepository, + @Named("gplayRepository") private val gplayRepository: GplayStoreRepository, + @Named("cleanApkAppsRepository") private val cleanApkAppsRepository: CleanApkRepository, + @Named("cleanApkPWARepository") private val cleanApkPWARepository: CleanApkRepository, @ApplicationContext private val context: Context ) { @@ -100,8 +108,6 @@ class FusedAPIImpl @Inject constructor( private const val CATEGORY_OPEN_GAMES_TITLE = "Open games" } - private var TAG = FusedAPIImpl::class.java.simpleName - /** * Check if list in all the FusedHome is empty. * If any list is not empty, send false. @@ -256,7 +262,7 @@ class FusedAPIImpl @Inject constructor( */ return liveData { val packageSpecificResults = ArrayList() - fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let { + fetchPackageSpecificResult(authData, query, packageSpecificResults).let { if (it.data?.second == true) { // if there are no data to load emit(it) return@liveData @@ -289,7 +295,6 @@ class FusedAPIImpl @Inject constructor( emitSource( fetchGplaySearchResults( query, - authData, searchResult, packageSpecificResults ).asLiveData() @@ -307,7 +312,7 @@ class FusedAPIImpl @Inject constructor( val pwaApps: MutableList = mutableListOf() val status = fusedAPIImpl.runCodeBlockWithTimeout({ val apps = - (cleanApkPWARepository.getSearchResult(query) as Response).body()?.apps + cleanApkPWARepository.getSearchResult(query).body()?.apps apps?.apply { if (this.isNotEmpty()) { pwaApps.addAll(this) @@ -334,10 +339,9 @@ class FusedAPIImpl @Inject constructor( private suspend fun fetchGplaySearchResults( query: String, - authData: AuthData, searchResult: MutableList, packageSpecificResults: ArrayList - ): GplaySearchResultFlow = getGplaySearchResult(query, authData).map { + ): GplaySearchResultFlow = getGplaySearchResult(query).map { if (it.first.isNotEmpty()) { searchResult.addAll(it.first) } @@ -385,7 +389,7 @@ class FusedAPIImpl @Inject constructor( authData: AuthData, query: String, packageSpecificResults: MutableList - ): ResultSupreme, Boolean>>? { + ): ResultSupreme, Boolean>> { var gplayPackageResult: FusedApp? = null var cleanapkPackageResult: FusedApp? = null @@ -474,10 +478,10 @@ class FusedAPIImpl @Inject constructor( private suspend fun getCleanapkSearchResult(packageName: String): ResultSupreme { var fusedApp = FusedApp() val status = runCodeBlockWithTimeout({ - val result = (cleanApkAppsRepository.getSearchResult( + val result = cleanApkAppsRepository.getSearchResult( packageName, "package_name" - ) as Response).body() + ).body() if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = result.apps[0] @@ -486,8 +490,8 @@ class FusedAPIImpl @Inject constructor( return ResultSupreme.create(status, fusedApp) } - suspend fun getSearchSuggestions(query: String, authData: AuthData): List { - return gplayRepository.getSearchSuggestions(query) as List + suspend fun getSearchSuggestions(query: String): List { + return gplayRepository.getSearchSuggestions(query) } suspend fun getOnDemandModule( @@ -496,12 +500,12 @@ class FusedAPIImpl @Inject constructor( versionCode: Int, offerType: Int ): String? { - val list = (gplayRepository as OnDemandModuleFetcher).getOnDemandModule( + val list = gplayRepository.getOnDemandModule( packageName, moduleName, versionCode, offerType, - ) as List + ) for (element in list) { if (element.name == "$moduleName.apk") { return element.url @@ -511,7 +515,6 @@ class FusedAPIImpl @Inject constructor( } suspend fun updateFusedDownloadWithDownloadingInfo( - authData: AuthData, origin: Origin, fusedDownload: FusedDownload ) { @@ -519,17 +522,20 @@ class FusedAPIImpl @Inject constructor( when (origin) { Origin.CLEANAPK -> { val downloadInfo = - ((cleanApkAppsRepository as DownloadInfoFetcher).getDownloadInfo(fusedDownload.id) as Response).body() + (cleanApkAppsRepository as CleanApkDownloadInfoFetcher).getDownloadInfo( + fusedDownload.id + ) + .body() downloadInfo?.download_data?.download_link?.let { list.add(it) } fusedDownload.signature = downloadInfo?.download_data?.signature ?: "" } Origin.GPLAY -> { val downloadList = - (gplayRepository as DownloadInfoFetcher).getDownloadInfo( + gplayRepository.getDownloadInfo( fusedDownload.packageName, fusedDownload.versionCode, fusedDownload.offerType - ) as List + ) fusedDownload.files = downloadList list.addAll(downloadList.map { it.url }) } @@ -540,7 +546,7 @@ class FusedAPIImpl @Inject constructor( } suspend fun getOSSDownloadInfo(id: String, version: String?) = - (cleanApkAppsRepository as DownloadInfoFetcher).getDownloadInfo(id, version) as Response + (cleanApkAppsRepository as CleanApkDownloadInfoFetcher).getDownloadInfo(id, version) suspend fun getPWAApps(category: String): ResultSupreme> { val list = mutableListOf() @@ -571,7 +577,6 @@ class FusedAPIImpl @Inject constructor( } suspend fun getNextStreamBundle( - authData: AuthData, homeUrl: String, currentStreamBundle: StreamBundle, ): ResultSupreme { @@ -584,7 +589,6 @@ class FusedAPIImpl @Inject constructor( } suspend fun getAdjustedFirstCluster( - authData: AuthData, streamBundle: StreamBundle, pointer: Int = 0, ): ResultSupreme { @@ -597,7 +601,6 @@ class FusedAPIImpl @Inject constructor( } suspend fun getNextStreamCluster( - authData: AuthData, currentStreamCluster: StreamCluster, ): ResultSupreme { var streamCluster = StreamCluster() @@ -610,7 +613,6 @@ class FusedAPIImpl @Inject constructor( suspend fun getPlayStoreApps( browseUrl: String, - authData: AuthData ): ResultSupreme> { val list = mutableListOf() val status = runCodeBlockWithTimeout({ @@ -632,10 +634,10 @@ class FusedAPIImpl @Inject constructor( suspend fun getCleanapkAppDetails(packageName: String): Pair { var fusedApp = FusedApp() val status = runCodeBlockWithTimeout({ - val result = (cleanApkAppsRepository.getSearchResult( + val result = cleanApkAppsRepository.getSearchResult( packageName, "package_name" - ) as Response).body() + ).body() if (result?.apps?.isNotEmpty() == true && result.numberOfResults == 1) { fusedApp = @@ -689,10 +691,10 @@ class FusedAPIImpl @Inject constructor( */ for (packageName in packageNameList) { status = runCodeBlockWithTimeout({ - (cleanApkAppsRepository.getSearchResult( + cleanApkAppsRepository.getSearchResult( packageName, "package_name" - ) as Response).body()?.run { + ).body()?.run { if (apps.isNotEmpty() && numberOfResults == 1) { fusedAppList.add( apps[0].apply { @@ -728,7 +730,7 @@ class FusedAPIImpl @Inject constructor( * Old code moved from getApplicationDetails() */ val status = runCodeBlockWithTimeout({ - (gplayRepository.getAppsDetails(packageNameList) as List).forEach { app -> + 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. @@ -820,7 +822,7 @@ class FusedAPIImpl @Inject constructor( * If not then change "Install" button to "N/A" */ try { - (gplayRepository as DownloadInfoFetcher).getDownloadInfo( + gplayRepository.getDownloadInfo( fusedApp.package_name, fusedApp.latest_version_code, fusedApp.offer_type, @@ -918,14 +920,14 @@ class FusedAPIImpl @Inject constructor( return Pair(apiStatus, errorApplicationCategory) } - private suspend fun FusedAPIImpl.fetchGplayCategories( + private suspend fun fetchGplayCategories( type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" var apiStatus = ResultStatus.OK val categoryList = mutableListOf() runCodeBlockWithTimeout({ - val playResponse = (gplayRepository.getCategories(type) as List).map { app -> + val playResponse = gplayRepository.getCategories(type).map { app -> val category = app.transformToFusedCategory() updateCategoryDrawable(category) category @@ -941,7 +943,7 @@ class FusedAPIImpl @Inject constructor( return Triple(apiStatus, categoryList, errorApplicationCategory) } - private suspend fun FusedAPIImpl.fetchPWACategories( + private suspend fun fetchPWACategories( type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" @@ -965,7 +967,7 @@ class FusedAPIImpl @Inject constructor( return Triple(apiStatus, fusedCategoriesList, errorApplicationCategory) } - private suspend fun FusedAPIImpl.fetchOpenSourceCategories( + private suspend fun fetchOpenSourceCategories( type: CategoryType, ): Triple, String> { var errorApplicationCategory = "" @@ -1100,23 +1102,23 @@ class FusedAPIImpl @Inject constructor( } private suspend fun getPWAsCategories(): Categories? { - return (cleanApkPWARepository.getCategories() as Response).body() + return cleanApkPWARepository.getCategories().body() } private suspend fun getOpenSourceCategories(): Categories? { - return (cleanApkAppsRepository.getCategories() as Response).body() + return cleanApkAppsRepository.getCategories().body() } private suspend fun getOpenSourceAppsResponse(category: String): Search? { - return (cleanApkAppsRepository.getAppsByCategory( + return cleanApkAppsRepository.getAppsByCategory( category, - ) as Response).body() + ).body() } private suspend fun getPWAAppsResponse(category: String): Search? { - return (cleanApkPWARepository.getAppsByCategory( + return cleanApkPWARepository.getAppsByCategory( category, - ) as Response).body() + ).body() } private fun Category.transformToFusedCategory(): FusedCategory { @@ -1135,21 +1137,17 @@ class FusedAPIImpl @Inject constructor( private suspend fun getCleanAPKSearchResults( keyword: String, - source: String = CleanAPKInterface.APP_SOURCE_FOSS, - type: String = CleanAPKInterface.APP_TYPE_ANY, - nres: Int = 20, - page: Int = 1, - by: String? = null + source: String = CleanApkRetrofit.APP_SOURCE_FOSS, ): List { val list = mutableListOf() val response = - (cleanApkAppsRepository.getSearchResult(keyword) as Response).body()?.apps + cleanApkAppsRepository.getSearchResult(keyword).body()?.apps response?.forEach { it.updateStatus() it.updateType() it.source = - if (source.contentEquals(CleanAPKInterface.APP_SOURCE_FOSS)) "Open Source" else "PWA" + if (source.contentEquals(CleanApkRetrofit.APP_SOURCE_FOSS)) "Open Source" else "PWA" list.add(it) } return list @@ -1157,9 +1155,8 @@ class FusedAPIImpl @Inject constructor( private suspend fun getGplaySearchResult( query: String, - authData: AuthData ): Flow, Boolean>> { - val searchResults = gplayRepository.getSearchResult(query) as Flow, Boolean>> + val searchResults = gplayRepository.getSearchResult(query) return searchResults.map { val fusedAppList = it.first.map { app -> replaceWithFDroid(app) } Pair( diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt index 71b1e5372..4af6c8c3c 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIRepository.kt @@ -128,7 +128,6 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII fusedDownload: FusedDownload ) { fusedAPIImpl.updateFusedDownloadWithDownloadingInfo( - authData, origin, fusedDownload ) @@ -138,7 +137,6 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII fusedAPIImpl.getOSSDownloadInfo(id, version) suspend fun getOnDemandModule( - authData: AuthData, packageName: String, moduleName: String, versionCode: Int, @@ -154,7 +152,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII } suspend fun getSearchSuggestions(query: String, authData: AuthData): List { - return fusedAPIImpl.getSearchSuggestions(query, authData) + return fusedAPIImpl.getSearchSuggestions(query) } fun getSearchResults( @@ -165,11 +163,10 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII } suspend fun getNextStreamBundle( - authData: AuthData, homeUrl: String, currentStreamBundle: StreamBundle, ): ResultSupreme { - return fusedAPIImpl.getNextStreamBundle(authData, homeUrl, currentStreamBundle).apply { + return fusedAPIImpl.getNextStreamBundle(homeUrl, currentStreamBundle).apply { if (isValidData()) streamBundle = data!! hasNextStreamBundle = streamBundle.hasNext() clusterPointer = 0 @@ -177,30 +174,27 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII } suspend fun getAdjustedFirstCluster( - authData: AuthData, streamBundle: StreamBundle, pointer: Int = 0, ): ResultSupreme { - return fusedAPIImpl.getAdjustedFirstCluster(authData, streamBundle, pointer) + return fusedAPIImpl.getAdjustedFirstCluster(streamBundle, pointer) } suspend fun getNextStreamCluster( - authData: AuthData, currentStreamCluster: StreamCluster, ): ResultSupreme { - return fusedAPIImpl.getNextStreamCluster(authData, currentStreamCluster) + return fusedAPIImpl.getNextStreamCluster(currentStreamCluster) } suspend fun getAppsListBasedOnCategory( category: String, browseUrl: String, - authData: AuthData, source: String ): ResultSupreme> { return when (source) { "Open Source" -> fusedAPIImpl.getOpenSourceApps(category) "PWA" -> fusedAPIImpl.getPWAApps(category) - else -> fusedAPIImpl.getPlayStoreApps(browseUrl, authData) + else -> fusedAPIImpl.getPlayStoreApps(browseUrl) } } @@ -231,7 +225,6 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII getAppsListBasedOnCategory( category, browseUrl, - authData, source ) } else { @@ -350,7 +343,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII } } } else if (hasNextStreamBundle) { - getNextStreamBundle(authData, browseUrl).run { + getNextStreamBundle(browseUrl).run { if (!isSuccess()) { return ResultSupreme.replicate(this, listOf()) } @@ -401,10 +394,9 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII * @see getNextDataSet */ private suspend fun getNextStreamBundle( - authData: AuthData, browseUrl: String, ): ResultSupreme { - return getNextStreamBundle(authData, browseUrl, streamBundle).apply { + return getNextStreamBundle(browseUrl, streamBundle).apply { if (isValidData()) streamBundle = data!! hasNextStreamBundle = streamBundle.hasNext() clusterPointer = 0 @@ -422,7 +414,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII private suspend fun getAdjustedFirstCluster( authData: AuthData, ): ResultSupreme { - return getAdjustedFirstCluster(authData, streamBundle, clusterPointer) + return getAdjustedFirstCluster(streamBundle, clusterPointer) .apply { if (isValidData()) addNewClusterData(this.data!!) } @@ -439,7 +431,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII private suspend fun getNextStreamCluster( authData: AuthData, ): ResultSupreme { - return getNextStreamCluster(authData, streamCluster).apply { + return getNextStreamCluster(streamCluster).apply { if (isValidData()) addNewClusterData(this.data!!) } } diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt new file mode 100644 index 000000000..2b31ed7eb --- /dev/null +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt @@ -0,0 +1,46 @@ +/* + * 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.api.gplay + +import com.aurora.gplayapi.SearchSuggestEntry +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.Category +import com.aurora.gplayapi.data.models.File +import foundation.e.apps.api.BaseStoreRepository +import foundation.e.apps.api.fused.utils.CategoryType +import kotlinx.coroutines.flow.Flow + +interface GplayStoreRepository : BaseStoreRepository { + suspend fun getSearchResult(query: String): Flow, Boolean>> + suspend fun getSearchSuggestions(query: String): List + suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Any + suspend fun getCategories(type: CategoryType? = null): List + suspend fun getAppsDetails(packageNamesOrIds: List): List + suspend fun getDownloadInfo( + idOrPackageName: String, + versionCode: Any? = null, + offerType: Int = -1 + ): List + suspend fun getOnDemandModule( + packageName: String, + moduleName: String, + versionCode: Int, + offerType: Int + ): List +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt similarity index 95% rename from app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt rename to app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt index 7997c78bf..6184a8737 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt @@ -23,14 +23,10 @@ import com.aurora.gplayapi.SearchSuggestEntry import com.aurora.gplayapi.data.models.* import com.aurora.gplayapi.helpers.* import dagger.hilt.android.qualifiers.ApplicationContext -import foundation.e.apps.api.DownloadInfoFetcher import foundation.e.apps.R -import foundation.e.apps.api.OnDemandModuleFetcher -import foundation.e.apps.api.StoreRepository import foundation.e.apps.api.fused.utils.CategoryType import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository -import foundation.e.apps.manager.database.fusedDownload.FusedDownload import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector @@ -40,11 +36,11 @@ import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext import javax.inject.Inject -class GplayRepository @Inject constructor( +class GplayStoreRepositoryImpl @Inject constructor( @ApplicationContext private val context: Context, private val gPlayHttpClient: GPlayHttpClient, private val loginSourceRepository: LoginSourceRepository -) : StoreRepository, DownloadInfoFetcher, OnDemandModuleFetcher { +) : GplayStoreRepository { private val authData by lazy { loginSourceRepository.gplayAuth!! } @@ -73,7 +69,6 @@ class GplayRepository @Inject constructor( override suspend fun getSearchResult( query: String, - searchBy: String? ): Flow, Boolean>> { return flow { /* @@ -221,9 +216,6 @@ class GplayRepository @Inject constructor( var nextStreamBundleUrl = category /* - * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 - * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 - * * Logic: We start with the browseUrl. * When we call getSubCategoryBundle(), we get a new StreamBundle object, having * StreamClusters, which have app data. @@ -258,12 +250,6 @@ class GplayRepository @Inject constructor( nextStreamBundleUrl = streamBundle.streamNextPageUrl } while (streamBundle.hasNext()) - - // TODO: DEAL WITH DUPLICATE AND LESS ITEMS - /*val streamClusters = categoryHelper.getSubCategoryBundle(browseUrl).streamClusters - streamClusters.values.forEach { - list.addAll(it.clusterAppList) - }*/ } } return list.distinctBy { it.packageName } diff --git a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt index dfbe19b10..982785769 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt @@ -49,7 +49,7 @@ import foundation.e.apps.MainActivity import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.application.model.ApplicationScreenshotsRVAdapter import foundation.e.apps.application.subFrags.ApplicationDialogFragment @@ -364,7 +364,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { sourceTag.text = it.source } if (origin == Origin.CLEANAPK) { - appIcon.load(CleanAPKInterface.ASSET_URL + it.icon_image_path) + appIcon.load(CleanApkRetrofit.ASSET_URL + it.icon_image_path) } else { appIcon.load(it.icon_image_path) } diff --git a/app/src/main/java/foundation/e/apps/application/model/ApplicationScreenshotsRVAdapter.kt b/app/src/main/java/foundation/e/apps/application/model/ApplicationScreenshotsRVAdapter.kt index 17ab706fd..eb121340f 100644 --- a/app/src/main/java/foundation/e/apps/application/model/ApplicationScreenshotsRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/application/model/ApplicationScreenshotsRVAdapter.kt @@ -24,7 +24,7 @@ import androidx.navigation.findNavController import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import coil.load -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.application.ApplicationFragmentDirections import foundation.e.apps.databinding.ApplicationScreenshotsListItemBinding import foundation.e.apps.utils.enums.Origin @@ -53,7 +53,7 @@ class ApplicationScreenshotsRVAdapter( val imageView = holder.binding.imageView when (origin) { Origin.CLEANAPK -> { - imageView.load(CleanAPKInterface.ASSET_URL + oldList[position]) + imageView.load(CleanApkRetrofit.ASSET_URL + oldList[position]) } Origin.GPLAY -> { imageView.load(oldList[position]) diff --git a/app/src/main/java/foundation/e/apps/application/model/ScreenshotRVAdapter.kt b/app/src/main/java/foundation/e/apps/application/model/ScreenshotRVAdapter.kt index 8e76afc43..61f2cb0c9 100644 --- a/app/src/main/java/foundation/e/apps/application/model/ScreenshotRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/application/model/ScreenshotRVAdapter.kt @@ -26,7 +26,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.CircularProgressDrawable import coil.load import foundation.e.apps.R -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.databinding.ScreenshotListItemBinding import foundation.e.apps.utils.enums.Origin @@ -57,7 +57,7 @@ class ScreenshotRVAdapter(private val list: List, private val origin: Or val imageView = holder.binding.imageView when (origin) { Origin.CLEANAPK -> { - imageView.load(CleanAPKInterface.ASSET_URL + list[position]) { + imageView.load(CleanApkRetrofit.ASSET_URL + list[position]) { placeholder(circularProgressDrawable) } } diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt index 216b0335c..3e669f31e 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListRVAdapter.kt @@ -40,7 +40,7 @@ import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.PrivacyInfoViewModel import foundation.e.apps.R -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.databinding.ApplicationListItemBinding @@ -169,7 +169,7 @@ class ApplicationListRVAdapter( } } Origin.CLEANAPK -> { - appIcon.load(CleanAPKInterface.ASSET_URL + searchApp.icon_image_path) { + appIcon.load(CleanApkRetrofit.ASSET_URL + searchApp.icon_image_path) { placeholder(shimmerDrawable) } } diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 64f1ae35b..733dc4d9b 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -25,12 +25,13 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import foundation.e.apps.api.StoreRepository -import foundation.e.apps.api.cleanapk.CleanAPKInterface -import foundation.e.apps.api.cleanapk.CleanApkAppDetailApi -import foundation.e.apps.api.cleanapk.CleanApkAppsRepository +import foundation.e.apps.api.cleanapk.CleanApkRepository +import foundation.e.apps.api.gplay.GplayStoreRepository +import foundation.e.apps.api.cleanapk.CleanApkRetrofit +import foundation.e.apps.api.cleanapk.CleanApkAppDetailsRetrofit +import foundation.e.apps.api.cleanapk.CleanApkAppsRepositoryImpl import foundation.e.apps.api.cleanapk.CleanApkPWARepository -import foundation.e.apps.api.gplay.GplayRepository +import foundation.e.apps.api.gplay.GplayStoreRepositoryImpl import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository import javax.inject.Named @@ -46,27 +47,27 @@ object NamedRepositoryModule { @ApplicationContext context: Context, gPlayHttpClient: GPlayHttpClient, loginSourceRepository: LoginSourceRepository - ): StoreRepository { - return GplayRepository(context, gPlayHttpClient, loginSourceRepository) + ): GplayStoreRepository { + return GplayStoreRepositoryImpl(context, gPlayHttpClient, loginSourceRepository) } @Singleton @Provides @Named("cleanApkAppsRepository") fun getCleanApkAppsRepository( - cleanAPKInterface: CleanAPKInterface, - cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreRepository { - return CleanApkAppsRepository(cleanAPKInterface, cleanApkAppDetailApi) + cleanAPKRetrofit: CleanApkRetrofit, + cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit + ): CleanApkRepository { + return CleanApkAppsRepositoryImpl(cleanAPKRetrofit, cleanApkAppDetailsRetrofit) } @Singleton @Provides @Named("cleanApkPWARepository") fun getCleanApkPWARepository( - cleanAPKInterface: CleanAPKInterface, - cleanApkAppDetailApi: CleanApkAppDetailApi - ): StoreRepository { - return CleanApkPWARepository(cleanAPKInterface, cleanApkAppDetailApi) + cleanAPKRetrofit: CleanApkRetrofit, + cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit + ): CleanApkRepository { + return CleanApkPWARepository(cleanAPKRetrofit, cleanApkAppDetailsRetrofit) } } diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt index 3c59b4e44..548af8d7d 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt @@ -35,7 +35,7 @@ import com.google.android.material.snackbar.Snackbar import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.R -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.databinding.HomeChildListItemBinding @@ -82,7 +82,7 @@ class HomeChildRVAdapter( holder.binding.apply { if (homeApp.origin == Origin.CLEANAPK) { - appIcon.load(CleanAPKInterface.ASSET_URL + homeApp.icon_image_path) { + appIcon.load(CleanApkRetrofit.ASSET_URL + homeApp.icon_image_path) { placeholder(shimmerDrawable) } } else { diff --git a/app/src/main/java/foundation/e/apps/splitinstall/SplitInstallBinder.kt b/app/src/main/java/foundation/e/apps/splitinstall/SplitInstallBinder.kt index f6783a5e5..5ce322d9e 100644 --- a/app/src/main/java/foundation/e/apps/splitinstall/SplitInstallBinder.kt +++ b/app/src/main/java/foundation/e/apps/splitinstall/SplitInstallBinder.kt @@ -97,15 +97,14 @@ class SplitInstallBinder( moduleName: String, versionCode: Int ): String? { - var url = fusedAPIRepository.getOnDemandModule( - authData!!, packageName, moduleName, - versionCode, 1 - ) + var url = fusedAPIRepository.getOnDemandModule(packageName, moduleName, versionCode, 1) if (url == null) { url = fusedAPIRepository.getOnDemandModule( - authData, packageName, "config.$moduleName", - versionCode, 1 + packageName, + "config.$moduleName", + versionCode, + 1 ) } diff --git a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt index 306e4b214..71ea39583 100644 --- a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt +++ b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesWorker.kt @@ -20,7 +20,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.fused.FusedAPIRepository import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.login.LoginSourceRepository @@ -318,7 +318,7 @@ class UpdatesWorker @AssistedInject constructor( private fun getIconImageToBase64(fusedApp: FusedApp): String { val url = - if (fusedApp.origin == Origin.CLEANAPK) "${CleanAPKInterface.ASSET_URL}${fusedApp.icon_image_path}" else fusedApp.icon_image_path + if (fusedApp.origin == Origin.CLEANAPK) "${CleanApkRetrofit.ASSET_URL}${fusedApp.icon_image_path}" else fusedApp.icon_image_path val stream = URL(url).openStream() val bitmap = BitmapFactory.decodeStream(stream) val byteArrayOS = ByteArrayOutputStream() diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index 646b84fad..9183fe120 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -26,7 +26,7 @@ import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category -import foundation.e.apps.api.cleanapk.CleanAPKInterface +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.CleanAPKRepository import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search @@ -622,7 +622,7 @@ class FusedApiImplTest { Mockito.`when`( cleanApkRepository.getCategoriesList( - eq(CleanAPKInterface.APP_TYPE_PWA), eq(CleanAPKInterface.APP_SOURCE_ANY) + eq(CleanApkRetrofit.APP_TYPE_PWA), eq(CleanApkRetrofit.APP_SOURCE_ANY) ) ).thenReturn(response) @@ -646,7 +646,7 @@ class FusedApiImplTest { Mockito.`when`( cleanApkRepository.getCategoriesList( - eq(CleanAPKInterface.APP_TYPE_ANY), eq(CleanAPKInterface.APP_SOURCE_FOSS) + eq(CleanApkRetrofit.APP_TYPE_ANY), eq(CleanApkRetrofit.APP_SOURCE_FOSS) ) ).thenReturn(response) Mockito.`when`(context.getString(eq(R.string.open_source))).thenReturn("Open source") @@ -705,13 +705,13 @@ class FusedApiImplTest { Mockito.`when`( cleanApkRepository.getCategoriesList( - eq(CleanAPKInterface.APP_TYPE_ANY), eq(CleanAPKInterface.APP_SOURCE_FOSS) + eq(CleanApkRetrofit.APP_TYPE_ANY), eq(CleanApkRetrofit.APP_SOURCE_FOSS) ) ).thenReturn(openSourceResponse) Mockito.`when`( cleanApkRepository.getCategoriesList( - eq(CleanAPKInterface.APP_TYPE_PWA), eq(CleanAPKInterface.APP_SOURCE_ANY) + eq(CleanApkRetrofit.APP_TYPE_PWA), eq(CleanApkRetrofit.APP_SOURCE_ANY) ) ).thenReturn(pwaResponse) @@ -813,8 +813,8 @@ class FusedApiImplTest { Mockito.`when`( cleanApkRepository.searchApps( keyword = "com.search.package", - type = CleanAPKInterface.APP_TYPE_PWA, - source = CleanAPKInterface.APP_SOURCE_ANY + type = CleanApkRetrofit.APP_TYPE_PWA, + source = CleanApkRetrofit.APP_SOURCE_ANY ) ).thenReturn(packageNameSearchResponse) -- GitLab From cd97dfc2e33cd648a5c2bddbfcdd150efa0eef71 Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 19 May 2023 16:53:47 +0600 Subject: [PATCH 12/13] refactor: extracted constants --- .../api/cleanapk/CleanApkAppsRepositoryImpl.kt | 8 ++++---- .../cleanapk/CleanApkDownloadInfoFetcher.kt | 18 ++++++++++++++++++ .../apps/api/cleanapk/CleanApkPWARepository.kt | 4 ++-- .../e/apps/api/cleanapk/CleanApkRepository.kt | 3 +++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt index 1deb2c7e5..03852099d 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt @@ -42,8 +42,8 @@ class CleanApkAppsRepositoryImpl( query, CleanApkRetrofit.APP_SOURCE_FOSS, CleanApkRetrofit.APP_TYPE_ANY, - 20, - 1, + NUMBER_OF_ITEMS, + NUMBER_OF_PAGES, searchBy ) } @@ -56,8 +56,8 @@ class CleanApkAppsRepositoryImpl( category, CleanApkRetrofit.APP_SOURCE_FOSS, CleanApkRetrofit.APP_TYPE_ANY, - 20, - 1 + NUMBER_OF_ITEMS, + NUMBER_OF_PAGES ) } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt index 90f5b5346..60562b240 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt @@ -1,3 +1,21 @@ +/* + * 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.api.cleanapk import foundation.e.apps.api.cleanapk.data.download.Download diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt index 5d17d109f..0bb4afa65 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkPWARepository.kt @@ -51,8 +51,8 @@ class CleanApkPWARepository( category, CleanApkRetrofit.APP_SOURCE_ANY, CleanApkRetrofit.APP_TYPE_PWA, - 20, - 1 + NUMBER_OF_ITEMS, + NUMBER_OF_PAGES ) } diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt index 8838b51d6..8319e7d15 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt @@ -24,6 +24,9 @@ import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response +const val NUMBER_OF_ITEMS = 20 + +const val NUMBER_OF_PAGES = 1 interface CleanApkRepository : BaseStoreRepository { suspend fun getSearchResult(query: String, searchBy: String? = null): Response suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Response -- GitLab From 37550ab86ebbdbbdc91d6264e8ec27a6ae43e4fb Mon Sep 17 00:00:00 2001 From: hasibprince Date: Fri, 19 May 2023 18:11:04 +0600 Subject: [PATCH 13/13] fixed: lint error --- .../e/apps/api/BaseStoreRepository.kt | 2 -- .../cleanapk/CleanApkAppsRepositoryImpl.kt | 2 +- .../cleanapk/CleanApkDownloadInfoFetcher.kt | 2 +- .../e/apps/api/cleanapk/CleanApkRepository.kt | 3 +-- .../e/apps/api/fdroid/models/BuildInfo.kt | 2 +- .../e/apps/api/fused/FusedAPIImpl.kt | 22 ++++++++-------- .../e/apps/api/gplay/GplayStoreRepository.kt | 2 +- .../api/gplay/GplayStoreRepositoryImpl.kt | 16 ++++++++++-- .../e/apps/di/NamedRepositoryModule.kt | 7 +++-- .../e/apps/login/AuthDataValidator.kt | 2 +- .../e/apps/login/LoginSourceGPlay.kt | 26 +++++++++---------- .../updates/manager/UpdatesManagerImpl.kt | 12 ++++----- .../foundation/e/apps/FusedApiImplTest.kt | 2 +- 13 files changed, 54 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt b/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt index 0173774d6..d72e5b379 100644 --- a/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/BaseStoreRepository.kt @@ -18,9 +18,7 @@ package foundation.e.apps.api - interface BaseStoreRepository { suspend fun getHomeScreenData(): Any suspend fun getAppDetails(packageNameOrId: String): Any? } - diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt index 03852099d..4fc16cbf3 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkAppsRepositoryImpl.kt @@ -28,7 +28,7 @@ import retrofit2.Response class CleanApkAppsRepositoryImpl( private val cleanApkRetrofit: CleanApkRetrofit, private val cleanApkAppDetailsRetrofit: CleanApkAppDetailsRetrofit -) : CleanApkRepository, CleanApkDownloadInfoFetcher{ +) : CleanApkRepository, CleanApkDownloadInfoFetcher { override suspend fun getHomeScreenData(): Response { return cleanApkRetrofit.getHomeScreenData( diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt index 60562b240..14dcd7f6c 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkDownloadInfoFetcher.kt @@ -23,4 +23,4 @@ import retrofit2.Response interface CleanApkDownloadInfoFetcher { suspend fun getDownloadInfo(idOrPackageName: String, versionCode: Any? = null): Response -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt index 8319e7d15..3959d18eb 100644 --- a/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/cleanapk/CleanApkRepository.kt @@ -20,7 +20,6 @@ package foundation.e.apps.api.cleanapk import foundation.e.apps.api.BaseStoreRepository import foundation.e.apps.api.cleanapk.data.categories.Categories -import foundation.e.apps.api.cleanapk.data.download.Download import foundation.e.apps.api.cleanapk.data.search.Search import retrofit2.Response @@ -31,4 +30,4 @@ interface CleanApkRepository : BaseStoreRepository { suspend fun getSearchResult(query: String, searchBy: String? = null): Response suspend fun getAppsByCategory(category: String, paginationParameter: Any? = null): Response suspend fun getCategories(): Response -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/api/fdroid/models/BuildInfo.kt b/app/src/main/java/foundation/e/apps/api/fdroid/models/BuildInfo.kt index 047395ded..b574a7b9e 100644 --- a/app/src/main/java/foundation/e/apps/api/fdroid/models/BuildInfo.kt +++ b/app/src/main/java/foundation/e/apps/api/fdroid/models/BuildInfo.kt @@ -34,4 +34,4 @@ class BuildInfo() { this.versionCode = versionCode ?: "" this.versionName = versionName ?: "" } -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt index 180b3ecbf..6cc7b55a8 100644 --- a/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt @@ -26,17 +26,17 @@ import androidx.lifecycle.liveData 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.Category -import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.models.StreamBundle -import com.aurora.gplayapi.data.models.Artwork +import com.aurora.gplayapi.data.models.StreamCluster import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.ResultSupreme -import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.CleanApkDownloadInfoFetcher import foundation.e.apps.api.cleanapk.CleanApkRepository +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.data.app.Application import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.home.Home @@ -54,22 +54,22 @@ import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.Constants.timeoutDurationInMillis -import foundation.e.apps.utils.enums.ResultStatus -import foundation.e.apps.utils.enums.Status -import foundation.e.apps.utils.enums.Source -import foundation.e.apps.utils.enums.FilterLevel import foundation.e.apps.utils.enums.AppTag -import foundation.e.apps.utils.enums.isUnFiltered +import foundation.e.apps.utils.enums.FilterLevel import foundation.e.apps.utils.enums.Origin +import foundation.e.apps.utils.enums.ResultStatus +import foundation.e.apps.utils.enums.Source +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Type +import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.Deferred import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map import kotlinx.coroutines.withTimeout import retrofit2.Response import timber.log.Timber @@ -1033,7 +1033,7 @@ class FusedAPIImpl @Inject constructor( private fun getCategoryIconName(category: FusedCategory): String { var categoryTitle = if (category.tag.getOperationalTag() - .contentEquals(AppTag.GPlay().getOperationalTag()) + .contentEquals(AppTag.GPlay().getOperationalTag()) ) category.id else category.title if (categoryTitle.contains(CATEGORY_TITLE_REPLACEABLE_CONJUNCTION)) { diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt index 2b31ed7eb..65651eac0 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepository.kt @@ -43,4 +43,4 @@ interface GplayStoreRepository : BaseStoreRepository { versionCode: Int, offerType: Int ): List -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt index 6184a8737..cd9fcffce 100644 --- a/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt +++ b/app/src/main/java/foundation/e/apps/api/gplay/GplayStoreRepositoryImpl.kt @@ -20,8 +20,20 @@ package foundation.e.apps.api.gplay import android.content.Context import com.aurora.gplayapi.SearchSuggestEntry -import com.aurora.gplayapi.data.models.* -import com.aurora.gplayapi.helpers.* +import com.aurora.gplayapi.data.models.App +import com.aurora.gplayapi.data.models.AuthData +import com.aurora.gplayapi.data.models.Category +import com.aurora.gplayapi.data.models.File +import com.aurora.gplayapi.data.models.SearchBundle +import com.aurora.gplayapi.data.models.StreamBundle +import com.aurora.gplayapi.data.models.StreamCluster +import com.aurora.gplayapi.helpers.AppDetailsHelper +import com.aurora.gplayapi.helpers.CategoryHelper +import com.aurora.gplayapi.helpers.ExpandedBrowseHelper +import com.aurora.gplayapi.helpers.PurchaseHelper +import com.aurora.gplayapi.helpers.SearchHelper +import com.aurora.gplayapi.helpers.StreamHelper +import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.api.fused.utils.CategoryType diff --git a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt index 733dc4d9b..c506d4ff5 100644 --- a/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt +++ b/app/src/main/java/foundation/e/apps/di/NamedRepositoryModule.kt @@ -18,19 +18,18 @@ package foundation.e.apps.di - import android.content.Context import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import foundation.e.apps.api.cleanapk.CleanApkRepository -import foundation.e.apps.api.gplay.GplayStoreRepository -import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.CleanApkAppDetailsRetrofit import foundation.e.apps.api.cleanapk.CleanApkAppsRepositoryImpl import foundation.e.apps.api.cleanapk.CleanApkPWARepository +import foundation.e.apps.api.cleanapk.CleanApkRepository +import foundation.e.apps.api.cleanapk.CleanApkRetrofit +import foundation.e.apps.api.gplay.GplayStoreRepository import foundation.e.apps.api.gplay.GplayStoreRepositoryImpl import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.login.LoginSourceRepository diff --git a/app/src/main/java/foundation/e/apps/login/AuthDataValidator.kt b/app/src/main/java/foundation/e/apps/login/AuthDataValidator.kt index 32bcc7bd7..029558a3e 100644 --- a/app/src/main/java/foundation/e/apps/login/AuthDataValidator.kt +++ b/app/src/main/java/foundation/e/apps/login/AuthDataValidator.kt @@ -23,4 +23,4 @@ import foundation.e.apps.api.ResultSupreme interface AuthDataValidator { suspend fun validateAuthData(): ResultSupreme -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt b/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt index 323ae6e82..c96106aae 100644 --- a/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt +++ b/app/src/main/java/foundation/e/apps/login/LoginSourceGPlay.kt @@ -79,14 +79,14 @@ class LoginSourceGPlay @Inject constructor( val savedAuth = getSavedAuthData() val authData = ( - savedAuth ?: run { - // if no saved data, then generate new auth data. - generateAuthData().let { - if (it.isSuccess()) it.data!! - else return AuthObject.GPlayAuth(it, user) - } + savedAuth ?: run { + // if no saved data, then generate new auth data. + generateAuthData().let { + if (it.isSuccess()) it.data!! + else return AuthObject.GPlayAuth(it, user) } - ) + } + ) val formattedAuthData = formatAuthData(authData) formattedAuthData.locale = locale @@ -239,12 +239,12 @@ class LoginSourceGPlay @Inject constructor( } else { val message = "Validating AuthData failed.\n" + - "Network code: ${playResponse?.code}\n" + - "Success: ${playResponse?.isSuccessful}" + - playResponse?.errorString?.run { - if (isNotBlank()) "\nError message: $this" - else "" - } + "Network code: ${playResponse?.code}\n" + + "Success: ${playResponse?.isSuccessful}" + + playResponse?.errorString?.run { + if (isNotBlank()) "\nError message: $this" + else "" + } ResultSupreme.Error( message, diff --git a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesManagerImpl.kt b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesManagerImpl.kt index 7c4a002b8..0ee9eab62 100644 --- a/app/src/main/java/foundation/e/apps/updates/manager/UpdatesManagerImpl.kt +++ b/app/src/main/java/foundation/e/apps/updates/manager/UpdatesManagerImpl.kt @@ -34,8 +34,8 @@ import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.modules.PreferenceManagerModule -import javax.inject.Inject import timber.log.Timber +import javax.inject.Inject class UpdatesManagerImpl @Inject constructor( @ApplicationContext private val context: Context, @@ -90,7 +90,8 @@ class UpdatesManagerImpl @Inject constructor( // Get GPlay app updates if (getApplicationCategoryPreference().contains(APP_TYPE_ANY) && - gPlayInstalledApps.isNotEmpty()) { + gPlayInstalledApps.isNotEmpty() + ) { status = getUpdatesFromApi({ fusedAPIRepository.getApplicationDetails( @@ -239,8 +240,8 @@ class UpdatesManagerImpl @Inject constructor( Timber.i( "Signature calculated for : ${cleanApkFusedApp.package_name}, " + - "signature version: ${installedVersionSignature}, " + - "is sig blank: ${pgpSignature.isBlank()}" + "signature version: $installedVersionSignature, " + + "is sig blank: ${pgpSignature.isBlank()}" ) return downloadInfo?.signature ?: "" @@ -301,7 +302,6 @@ class UpdatesManagerImpl @Inject constructor( return "" } - // Received list has build info of the latest version at the bottom. // We want it at the top. val builds = fdroidRepository.getBuildVersionInfo(packageName)?.asReversed() ?: return "" @@ -310,7 +310,7 @@ class UpdatesManagerImpl @Inject constructor( it.versionCode == installedVersionCode && it.versionName == installedVersionName }?.run { builds.indexOf(this) - }?: return "" + } ?: return "" Timber.i("Build info match at index: $matchingIndex") diff --git a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt index 9183fe120..136520bb8 100644 --- a/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt +++ b/app/src/test/java/foundation/e/apps/FusedApiImplTest.kt @@ -26,8 +26,8 @@ import com.aurora.gplayapi.Constants import com.aurora.gplayapi.data.models.App import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category -import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.CleanAPKRepository +import foundation.e.apps.api.cleanapk.CleanApkRetrofit import foundation.e.apps.api.cleanapk.data.categories.Categories import foundation.e.apps.api.cleanapk.data.search.Search import foundation.e.apps.api.fdroid.FdroidWebInterface -- GitLab