Loading app/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMajor = 2 def versionMinor = 4 def versionMinor = 4 def versionPatch = 7 def versionPatch = 9 def getGitHash = { -> def getGitHash = { -> def stdOut = new ByteArrayOutputStream() def stdOut = new ByteArrayOutputStream() Loading app/src/main/java/foundation/e/apps/MainActivity.kt +8 −1 Original line number Original line Diff line number Diff line Loading @@ -55,7 +55,6 @@ import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.modules.CommonUtilsFunctions import foundation.e.apps.utils.modules.CommonUtilsFunctions import foundation.e.apps.utils.modules.CommonUtilsModule import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import kotlinx.coroutines.launch Loading Loading @@ -214,6 +213,14 @@ class MainActivity : AppCompatActivity() { viewModel.updateAppWarningList() viewModel.updateAppWarningList() lifecycleScope.launchWhenResumed { lifecycleScope.launchWhenResumed { EventBus.events.filter { it is AppEvent.AuthUpdateEvent }.collectLatest { Timber.d("Updated AuthObjects") val authObjectMutableList = loginViewModel.authObjects.value?.toMutableList() authObjectMutableList?.removeIf { it.result.data is AuthData } authObjectMutableList?.add(it.data as AuthObject) loginViewModel.authObjects.postValue(authObjectMutableList) } EventBus.events.filter { appEvent -> EventBus.events.filter { appEvent -> appEvent is AppEvent.SignatureMissMatchError appEvent is AppEvent.SignatureMissMatchError }.collectLatest { }.collectLatest { Loading app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +73 −22 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.exceptions.ApiException import com.aurora.gplayapi.helpers.TopChartsHelper import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.R Loading @@ -48,7 +49,10 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.login.AuthObject import foundation.e.apps.login.LoginSourceRepository import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.Constants.timeoutDurationInMillis import foundation.e.apps.utils.Constants.timeoutDurationInMillis Loading @@ -60,6 +64,8 @@ import foundation.e.apps.utils.enums.Source import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException Loading @@ -76,6 +82,7 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, private val fdroidWebInterface: FdroidWebInterface, private val loginSourceRepository: LoginSourceRepository, @ApplicationContext private val context: Context @ApplicationContext private val context: Context ) { ) { Loading Loading @@ -148,7 +155,7 @@ class FusedAPIImpl @Inject constructor( val apiStatus = when (source) { val apiStatus = when (source) { Source.GPLAY -> runCodeBlockWithTimeout({ Source.GPLAY -> runCodeBlockWithTimeout({ priorList.addAll(fetchGPlayHome(authData)) priorList.addAll(fetchGPlayHome(it ?: authData)) }) }) Source.OPEN -> runCodeBlockWithTimeout({ Source.OPEN -> runCodeBlockWithTimeout({ Loading Loading @@ -234,10 +241,11 @@ class FusedAPIImpl @Inject constructor( * for all results to be fetched from network before showing them. * for all results to be fetched from network before showing them. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 */ */ return liveData { return liveData { val packageSpecificResults = ArrayList<FusedApp>() val packageSpecificResults = ArrayList<FusedApp>() fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let { fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let { if (it.data?.second == true) { // if there are no data to load if (it.data?.second == false) { // if there are no data to load emit(it) emit(it) return@liveData return@liveData } } Loading Loading @@ -374,7 +382,7 @@ class FusedAPIImpl @Inject constructor( val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ if (preferenceManagerModule.isGplaySelected()) { if (preferenceManagerModule.isGplaySelected()) { gplayPackageResult = getGplayPackagResult(query, authData) gplayPackageResult = getGplayPackagResult(query, it ?: authData) } } if (preferenceManagerModule.isOpenSourceSelected()) { if (preferenceManagerModule.isOpenSourceSelected()) { Loading @@ -395,7 +403,7 @@ class FusedAPIImpl @Inject constructor( * If there was a timeout, return it and don't try to fetch anything else. * If there was a timeout, return it and don't try to fetch anything else. * Also send true in the pair to signal more results being loaded. * Also send true in the pair to signal more results being loaded. */ */ if (status != ResultStatus.OK) { if (status != ResultStatus.OK || packageSpecificResults.isEmpty()) { return ResultSupreme.create(status, Pair(packageSpecificResults, true)) return ResultSupreme.create(status, Pair(packageSpecificResults, true)) } } return ResultSupreme.create(status, Pair(packageSpecificResults, false)) return ResultSupreme.create(status, Pair(packageSpecificResults, false)) Loading Loading @@ -558,7 +566,7 @@ class FusedAPIImpl @Inject constructor( var streamBundle = StreamBundle() var streamBundle = StreamBundle() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamBundle = streamBundle = gPlayAPIRepository.getNextStreamBundle(authData, homeUrl, currentStreamBundle) gPlayAPIRepository.getNextStreamBundle(it ?: authData, homeUrl, currentStreamBundle) }) }) return ResultSupreme.create(status, streamBundle) return ResultSupreme.create(status, streamBundle) } } Loading @@ -571,7 +579,7 @@ class FusedAPIImpl @Inject constructor( var streamCluster = StreamCluster() var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamCluster = streamCluster = gPlayAPIRepository.getAdjustedFirstCluster(authData, streamBundle, pointer) gPlayAPIRepository.getAdjustedFirstCluster(it ?: authData, streamBundle, pointer) }) }) return ResultSupreme.create(status, streamCluster) return ResultSupreme.create(status, streamCluster) } } Loading @@ -582,7 +590,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme<StreamCluster> { ): ResultSupreme<StreamCluster> { var streamCluster = StreamCluster() var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamCluster = gPlayAPIRepository.getNextStreamCluster(authData, currentStreamCluster) streamCluster = gPlayAPIRepository.getNextStreamCluster(it ?: authData, currentStreamCluster) }) }) return ResultSupreme.create(status, streamCluster) return ResultSupreme.create(status, streamCluster) } } Loading @@ -594,7 +603,7 @@ class FusedAPIImpl @Inject constructor( val list = mutableListOf<FusedApp>() val list = mutableListOf<FusedApp>() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ list.addAll( list.addAll( gPlayAPIRepository.listApps(browseUrl, authData).map { app -> gPlayAPIRepository.listApps(browseUrl, it ?: authData).map { app -> app.transformToFusedApp() app.transformToFusedApp() } } ) ) Loading Loading @@ -706,7 +715,7 @@ class FusedAPIImpl @Inject constructor( * Old code moved from getApplicationDetails() * Old code moved from getApplicationDetails() */ */ val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ gPlayAPIRepository.getAppDetails(packageNameList, authData).forEach { app -> gPlayAPIRepository.getAppDetails(packageNameList, it ?: authData).forEach { app -> /* /* * Some apps are restricted to locations. Example "com.skype.m2". * Some apps are restricted to locations. Example "com.skype.m2". * For restricted apps, check if it is possible to get their specific app info. * For restricted apps, check if it is possible to get their specific app info. Loading Loading @@ -743,9 +752,9 @@ class FusedAPIImpl @Inject constructor( appList: List<App>, appList: List<App>, ): ResultSupreme<List<FusedApp>> { ): ResultSupreme<List<FusedApp>> { val filteredFusedApps = mutableListOf<FusedApp>() val filteredFusedApps = mutableListOf<FusedApp>() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ auth -> appList.forEach { appList.forEach { val filter = getAppFilterLevel(it, authData) val filter = getAppFilterLevel(it, auth ?: authData) if (filter.isUnFiltered()) { if (filter.isUnFiltered()) { filteredFusedApps.add( filteredFusedApps.add( it.transformToFusedApp().apply { it.transformToFusedApp().apply { Loading Loading @@ -837,10 +846,11 @@ class FusedAPIImpl @Inject constructor( var response: FusedApp? = null var response: FusedApp? = null val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ response = if (origin == Origin.CLEANAPK) { response = if (origin == Origin.CLEANAPK) { cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app } else { } else { val app = gPlayAPIRepository.getAppDetails(packageName, authData) val app = gPlayAPIRepository.getAppDetails(packageName, it ?: authData) app?.transformToFusedApp() app?.transformToFusedApp() } } response?.let { response?.let { Loading @@ -850,7 +860,7 @@ class FusedAPIImpl @Inject constructor( it.updateFilterLevel(authData) it.updateFilterLevel(authData) } } }) }) Timber.d("getAppDetails: $status") return Pair(response ?: FusedApp(), status) return Pair(response ?: FusedApp(), status) } } Loading Loading @@ -945,8 +955,11 @@ class FusedAPIImpl @Inject constructor( var errorApplicationCategory = "" var errorApplicationCategory = "" var apiStatus = ResultStatus.OK var apiStatus = ResultStatus.OK val categoryList = mutableListOf<FusedCategory>() val categoryList = mutableListOf<FusedCategory>() runCodeBlockWithTimeout({ runCodeBlockWithTimeout({ val playResponse = gPlayAPIRepository.getCategoriesList(type, authData).map { app -> val playResponse = gPlayAPIRepository.getCategoriesList(type, it ?: authData).map { app -> val category = app.transformToFusedCategory() val category = app.transformToFusedCategory() updateCategoryDrawable(category) updateCategoryDrawable(category) category category Loading Loading @@ -1022,13 +1035,18 @@ class FusedAPIImpl @Inject constructor( * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit. * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit. */ */ private suspend fun runCodeBlockWithTimeout( private suspend fun runCodeBlockWithTimeout( block: suspend () -> Unit, block: suspend (authData: AuthData?) -> Unit, timeoutBlock: (() -> Unit)? = null, timeoutBlock: (() -> Unit)? = null, exceptionBlock: ((e: Exception) -> Unit)? = null, exceptionBlock: ((e: Exception) -> Unit)? = null, ): ResultStatus { ): ResultStatus { return try { return try { var authObject: AuthObject? withTimeout(timeoutDurationInMillis) { withTimeout(timeoutDurationInMillis) { block() authObject = executeBlockHandlingException(block) } authObject?.let { EventBus.invokeEvent(AppEvent.AuthUpdateEvent(it)) } } ResultStatus.OK ResultStatus.OK } catch (e: TimeoutCancellationException) { } catch (e: TimeoutCancellationException) { Loading @@ -1043,6 +1061,35 @@ class FusedAPIImpl @Inject constructor( } } } } private suspend fun FusedAPIImpl.executeBlockHandlingException( block: suspend (authData: AuthData?) -> Unit, ): AuthObject? { return try { block(null) handleUnauthorizedAuthData(block) } catch (e: ApiException.AppNotFound) { Timber.w(e) handleUnauthorizedAuthData(block) ?: throw e } } private suspend fun handleUnauthorizedAuthData( block: suspend (authData: AuthData?) -> Unit ): AuthObject? { if (!GPlayHttpClient.IS_AUTH_VALID) { val loginSources = loginSourceRepository.getAuthObjects() loginSources.find { it is AuthObject.GPlayAuth }?.let { val authData = (it.result.data as AuthData) GPlayHttpClient.IS_AUTH_VALID = true block.invoke(authData) Timber.d("data refreshed with new auth!") return it } } return null } private fun updateCategoryDrawable( private fun updateCategoryDrawable( category: FusedCategory, category: FusedCategory, ) { ) { Loading Loading @@ -1190,7 +1237,8 @@ class FusedAPIImpl @Inject constructor( query: String, query: String, authData: AuthData authData: AuthData ): LiveData<Pair<List<FusedApp>, Boolean>> { ): LiveData<Pair<List<FusedApp>, Boolean>> { val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { return searchResults.map { Pair( Pair( it.first, it.first, Loading Loading @@ -1336,8 +1384,11 @@ class FusedAPIImpl @Inject constructor( updateFilterLevel(authData) updateFilterLevel(authData) } } } } if (result.isNotEmpty()) { list.add(FusedHome(it.key, result)) list.add(FusedHome(it.key, result)) } } } return list return list } } Loading app/src/main/java/foundation/e/apps/api/gplay/utils/GPlayHttpClient.kt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ class GPlayHttpClient @Inject constructor( companion object { companion object { private const val TAG = "GPlayHttpClient" private const val TAG = "GPlayHttpClient" var IS_AUTH_VALID = true } } private val okHttpClient = OkHttpClient().newBuilder() private val okHttpClient = OkHttpClient().newBuilder() Loading Loading @@ -177,6 +178,10 @@ class GPlayHttpClient @Inject constructor( return PlayResponse().apply { return PlayResponse().apply { isSuccessful = response.isSuccessful isSuccessful = response.isSuccessful code = response.code code = response.code Timber.d("GplayHttpClient: Url: ${response.request.url} \n Status: ${response.code}") if (response.code == 401) { IS_AUTH_VALID = false } if (response.body != null) { if (response.body != null) { responseBytes = response.body!!.bytes() responseBytes = response.body!!.bytes() Loading app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package foundation.e.apps.login package foundation.e.apps.login import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.enums.User import javax.inject.Inject import javax.inject.Inject import javax.inject.Singleton import javax.inject.Singleton Loading Loading
app/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -11,7 +11,7 @@ plugins { def versionMajor = 2 def versionMajor = 2 def versionMinor = 4 def versionMinor = 4 def versionPatch = 7 def versionPatch = 9 def getGitHash = { -> def getGitHash = { -> def stdOut = new ByteArrayOutputStream() def stdOut = new ByteArrayOutputStream() Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +8 −1 Original line number Original line Diff line number Diff line Loading @@ -55,7 +55,6 @@ import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.exceptions.GPlayValidationException import foundation.e.apps.utils.modules.CommonUtilsFunctions import foundation.e.apps.utils.modules.CommonUtilsFunctions import foundation.e.apps.utils.modules.CommonUtilsModule import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import kotlinx.coroutines.launch Loading Loading @@ -214,6 +213,14 @@ class MainActivity : AppCompatActivity() { viewModel.updateAppWarningList() viewModel.updateAppWarningList() lifecycleScope.launchWhenResumed { lifecycleScope.launchWhenResumed { EventBus.events.filter { it is AppEvent.AuthUpdateEvent }.collectLatest { Timber.d("Updated AuthObjects") val authObjectMutableList = loginViewModel.authObjects.value?.toMutableList() authObjectMutableList?.removeIf { it.result.data is AuthData } authObjectMutableList?.add(it.data as AuthObject) loginViewModel.authObjects.postValue(authObjectMutableList) } EventBus.events.filter { appEvent -> EventBus.events.filter { appEvent -> appEvent is AppEvent.SignatureMissMatchError appEvent is AppEvent.SignatureMissMatchError }.collectLatest { }.collectLatest { Loading
app/src/main/java/foundation/e/apps/api/fused/FusedAPIImpl.kt +73 −22 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import com.aurora.gplayapi.data.models.AuthData import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.Category import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamBundle import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.data.models.StreamCluster import com.aurora.gplayapi.exceptions.ApiException import com.aurora.gplayapi.helpers.TopChartsHelper import com.aurora.gplayapi.helpers.TopChartsHelper import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext import foundation.e.apps.R import foundation.e.apps.R Loading @@ -48,7 +49,10 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.data.Ratings import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.fused.utils.CategoryUtils import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.api.gplay.GPlayAPIRepository import foundation.e.apps.api.gplay.utils.GPlayHttpClient import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.home.model.HomeChildFusedAppDiffUtil import foundation.e.apps.login.AuthObject import foundation.e.apps.login.LoginSourceRepository import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.manager.pkg.PkgManagerModule import foundation.e.apps.utils.Constants.timeoutDurationInMillis import foundation.e.apps.utils.Constants.timeoutDurationInMillis Loading @@ -60,6 +64,8 @@ import foundation.e.apps.utils.enums.Source import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.enums.Type import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.enums.isUnFiltered import foundation.e.apps.utils.eventBus.AppEvent import foundation.e.apps.utils.eventBus.EventBus import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PWAManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import foundation.e.apps.utils.modules.PreferenceManagerModule import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException Loading @@ -76,6 +82,7 @@ class FusedAPIImpl @Inject constructor( private val pwaManagerModule: PWAManagerModule, private val pwaManagerModule: PWAManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val preferenceManagerModule: PreferenceManagerModule, private val fdroidWebInterface: FdroidWebInterface, private val fdroidWebInterface: FdroidWebInterface, private val loginSourceRepository: LoginSourceRepository, @ApplicationContext private val context: Context @ApplicationContext private val context: Context ) { ) { Loading Loading @@ -148,7 +155,7 @@ class FusedAPIImpl @Inject constructor( val apiStatus = when (source) { val apiStatus = when (source) { Source.GPLAY -> runCodeBlockWithTimeout({ Source.GPLAY -> runCodeBlockWithTimeout({ priorList.addAll(fetchGPlayHome(authData)) priorList.addAll(fetchGPlayHome(it ?: authData)) }) }) Source.OPEN -> runCodeBlockWithTimeout({ Source.OPEN -> runCodeBlockWithTimeout({ Loading Loading @@ -234,10 +241,11 @@ class FusedAPIImpl @Inject constructor( * for all results to be fetched from network before showing them. * for all results to be fetched from network before showing them. * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5171 */ */ return liveData { return liveData { val packageSpecificResults = ArrayList<FusedApp>() val packageSpecificResults = ArrayList<FusedApp>() fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let { fetchPackageSpecificResult(authData, query, packageSpecificResults)?.let { if (it.data?.second == true) { // if there are no data to load if (it.data?.second == false) { // if there are no data to load emit(it) emit(it) return@liveData return@liveData } } Loading Loading @@ -374,7 +382,7 @@ class FusedAPIImpl @Inject constructor( val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ if (preferenceManagerModule.isGplaySelected()) { if (preferenceManagerModule.isGplaySelected()) { gplayPackageResult = getGplayPackagResult(query, authData) gplayPackageResult = getGplayPackagResult(query, it ?: authData) } } if (preferenceManagerModule.isOpenSourceSelected()) { if (preferenceManagerModule.isOpenSourceSelected()) { Loading @@ -395,7 +403,7 @@ class FusedAPIImpl @Inject constructor( * If there was a timeout, return it and don't try to fetch anything else. * If there was a timeout, return it and don't try to fetch anything else. * Also send true in the pair to signal more results being loaded. * Also send true in the pair to signal more results being loaded. */ */ if (status != ResultStatus.OK) { if (status != ResultStatus.OK || packageSpecificResults.isEmpty()) { return ResultSupreme.create(status, Pair(packageSpecificResults, true)) return ResultSupreme.create(status, Pair(packageSpecificResults, true)) } } return ResultSupreme.create(status, Pair(packageSpecificResults, false)) return ResultSupreme.create(status, Pair(packageSpecificResults, false)) Loading Loading @@ -558,7 +566,7 @@ class FusedAPIImpl @Inject constructor( var streamBundle = StreamBundle() var streamBundle = StreamBundle() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamBundle = streamBundle = gPlayAPIRepository.getNextStreamBundle(authData, homeUrl, currentStreamBundle) gPlayAPIRepository.getNextStreamBundle(it ?: authData, homeUrl, currentStreamBundle) }) }) return ResultSupreme.create(status, streamBundle) return ResultSupreme.create(status, streamBundle) } } Loading @@ -571,7 +579,7 @@ class FusedAPIImpl @Inject constructor( var streamCluster = StreamCluster() var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamCluster = streamCluster = gPlayAPIRepository.getAdjustedFirstCluster(authData, streamBundle, pointer) gPlayAPIRepository.getAdjustedFirstCluster(it ?: authData, streamBundle, pointer) }) }) return ResultSupreme.create(status, streamCluster) return ResultSupreme.create(status, streamCluster) } } Loading @@ -582,7 +590,8 @@ class FusedAPIImpl @Inject constructor( ): ResultSupreme<StreamCluster> { ): ResultSupreme<StreamCluster> { var streamCluster = StreamCluster() var streamCluster = StreamCluster() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ streamCluster = gPlayAPIRepository.getNextStreamCluster(authData, currentStreamCluster) streamCluster = gPlayAPIRepository.getNextStreamCluster(it ?: authData, currentStreamCluster) }) }) return ResultSupreme.create(status, streamCluster) return ResultSupreme.create(status, streamCluster) } } Loading @@ -594,7 +603,7 @@ class FusedAPIImpl @Inject constructor( val list = mutableListOf<FusedApp>() val list = mutableListOf<FusedApp>() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ list.addAll( list.addAll( gPlayAPIRepository.listApps(browseUrl, authData).map { app -> gPlayAPIRepository.listApps(browseUrl, it ?: authData).map { app -> app.transformToFusedApp() app.transformToFusedApp() } } ) ) Loading Loading @@ -706,7 +715,7 @@ class FusedAPIImpl @Inject constructor( * Old code moved from getApplicationDetails() * Old code moved from getApplicationDetails() */ */ val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ gPlayAPIRepository.getAppDetails(packageNameList, authData).forEach { app -> gPlayAPIRepository.getAppDetails(packageNameList, it ?: authData).forEach { app -> /* /* * Some apps are restricted to locations. Example "com.skype.m2". * Some apps are restricted to locations. Example "com.skype.m2". * For restricted apps, check if it is possible to get their specific app info. * For restricted apps, check if it is possible to get their specific app info. Loading Loading @@ -743,9 +752,9 @@ class FusedAPIImpl @Inject constructor( appList: List<App>, appList: List<App>, ): ResultSupreme<List<FusedApp>> { ): ResultSupreme<List<FusedApp>> { val filteredFusedApps = mutableListOf<FusedApp>() val filteredFusedApps = mutableListOf<FusedApp>() val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ auth -> appList.forEach { appList.forEach { val filter = getAppFilterLevel(it, authData) val filter = getAppFilterLevel(it, auth ?: authData) if (filter.isUnFiltered()) { if (filter.isUnFiltered()) { filteredFusedApps.add( filteredFusedApps.add( it.transformToFusedApp().apply { it.transformToFusedApp().apply { Loading Loading @@ -837,10 +846,11 @@ class FusedAPIImpl @Inject constructor( var response: FusedApp? = null var response: FusedApp? = null val status = runCodeBlockWithTimeout({ val status = runCodeBlockWithTimeout({ response = if (origin == Origin.CLEANAPK) { response = if (origin == Origin.CLEANAPK) { cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app cleanAPKRepository.getAppOrPWADetailsByID(id).body()?.app } else { } else { val app = gPlayAPIRepository.getAppDetails(packageName, authData) val app = gPlayAPIRepository.getAppDetails(packageName, it ?: authData) app?.transformToFusedApp() app?.transformToFusedApp() } } response?.let { response?.let { Loading @@ -850,7 +860,7 @@ class FusedAPIImpl @Inject constructor( it.updateFilterLevel(authData) it.updateFilterLevel(authData) } } }) }) Timber.d("getAppDetails: $status") return Pair(response ?: FusedApp(), status) return Pair(response ?: FusedApp(), status) } } Loading Loading @@ -945,8 +955,11 @@ class FusedAPIImpl @Inject constructor( var errorApplicationCategory = "" var errorApplicationCategory = "" var apiStatus = ResultStatus.OK var apiStatus = ResultStatus.OK val categoryList = mutableListOf<FusedCategory>() val categoryList = mutableListOf<FusedCategory>() runCodeBlockWithTimeout({ runCodeBlockWithTimeout({ val playResponse = gPlayAPIRepository.getCategoriesList(type, authData).map { app -> val playResponse = gPlayAPIRepository.getCategoriesList(type, it ?: authData).map { app -> val category = app.transformToFusedCategory() val category = app.transformToFusedCategory() updateCategoryDrawable(category) updateCategoryDrawable(category) category category Loading Loading @@ -1022,13 +1035,18 @@ class FusedAPIImpl @Inject constructor( * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit. * @return Instance of [ResultStatus] based on whether [block] was executed within timeout limit. */ */ private suspend fun runCodeBlockWithTimeout( private suspend fun runCodeBlockWithTimeout( block: suspend () -> Unit, block: suspend (authData: AuthData?) -> Unit, timeoutBlock: (() -> Unit)? = null, timeoutBlock: (() -> Unit)? = null, exceptionBlock: ((e: Exception) -> Unit)? = null, exceptionBlock: ((e: Exception) -> Unit)? = null, ): ResultStatus { ): ResultStatus { return try { return try { var authObject: AuthObject? withTimeout(timeoutDurationInMillis) { withTimeout(timeoutDurationInMillis) { block() authObject = executeBlockHandlingException(block) } authObject?.let { EventBus.invokeEvent(AppEvent.AuthUpdateEvent(it)) } } ResultStatus.OK ResultStatus.OK } catch (e: TimeoutCancellationException) { } catch (e: TimeoutCancellationException) { Loading @@ -1043,6 +1061,35 @@ class FusedAPIImpl @Inject constructor( } } } } private suspend fun FusedAPIImpl.executeBlockHandlingException( block: suspend (authData: AuthData?) -> Unit, ): AuthObject? { return try { block(null) handleUnauthorizedAuthData(block) } catch (e: ApiException.AppNotFound) { Timber.w(e) handleUnauthorizedAuthData(block) ?: throw e } } private suspend fun handleUnauthorizedAuthData( block: suspend (authData: AuthData?) -> Unit ): AuthObject? { if (!GPlayHttpClient.IS_AUTH_VALID) { val loginSources = loginSourceRepository.getAuthObjects() loginSources.find { it is AuthObject.GPlayAuth }?.let { val authData = (it.result.data as AuthData) GPlayHttpClient.IS_AUTH_VALID = true block.invoke(authData) Timber.d("data refreshed with new auth!") return it } } return null } private fun updateCategoryDrawable( private fun updateCategoryDrawable( category: FusedCategory, category: FusedCategory, ) { ) { Loading Loading @@ -1190,7 +1237,8 @@ class FusedAPIImpl @Inject constructor( query: String, query: String, authData: AuthData authData: AuthData ): LiveData<Pair<List<FusedApp>, Boolean>> { ): LiveData<Pair<List<FusedApp>, Boolean>> { val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) val searchResults = gPlayAPIRepository.getSearchResults(query, authData, ::replaceWithFDroid) return searchResults.map { return searchResults.map { Pair( Pair( it.first, it.first, Loading Loading @@ -1336,8 +1384,11 @@ class FusedAPIImpl @Inject constructor( updateFilterLevel(authData) updateFilterLevel(authData) } } } } if (result.isNotEmpty()) { list.add(FusedHome(it.key, result)) list.add(FusedHome(it.key, result)) } } } return list return list } } Loading
app/src/main/java/foundation/e/apps/api/gplay/utils/GPlayHttpClient.kt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -47,6 +47,7 @@ class GPlayHttpClient @Inject constructor( companion object { companion object { private const val TAG = "GPlayHttpClient" private const val TAG = "GPlayHttpClient" var IS_AUTH_VALID = true } } private val okHttpClient = OkHttpClient().newBuilder() private val okHttpClient = OkHttpClient().newBuilder() Loading Loading @@ -177,6 +178,10 @@ class GPlayHttpClient @Inject constructor( return PlayResponse().apply { return PlayResponse().apply { isSuccessful = response.isSuccessful isSuccessful = response.isSuccessful code = response.code code = response.code Timber.d("GplayHttpClient: Url: ${response.request.url} \n Status: ${response.code}") if (response.code == 401) { IS_AUTH_VALID = false } if (response.body != null) { if (response.body != null) { responseBytes = response.body!!.bytes() responseBytes = response.body!!.bytes() Loading
app/src/main/java/foundation/e/apps/login/LoginSourceRepository.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package foundation.e.apps.login package foundation.e.apps.login import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.utils.enums.User import foundation.e.apps.utils.enums.User import javax.inject.Inject import javax.inject.Inject import javax.inject.Singleton import javax.inject.Singleton Loading