diff --git a/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt b/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt index d64afd821343078c8d7315ed226693cbf376ce4b..856674c7117cb91ed71340a61cb19a0fc42abe6b 100644 --- a/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt +++ b/app/src/main/java/foundation/e/apps/api/ResultSupreme.kt @@ -140,7 +140,7 @@ sealed class ResultSupreme { if (isUnknownError()) { this.data = data } else { - this.message = message + this.message = message.ifBlank { status.message } this.exception = exception } } 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 afdb7e5ee75ed8d99f13056ac2d5bcb7c4d0c24b..564e6263177a3cfccf9fcf8052d856e9214049b7 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 @@ -21,6 +21,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 com.aurora.gplayapi.Constants @@ -54,6 +55,7 @@ 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 @@ -93,19 +95,6 @@ class FusedAPIImpl @Inject constructor( private var TAG = FusedAPIImpl::class.java.simpleName - /** - * Pass list of FusedHome and status. - * Second argument can be of [ResultStatus.TIMEOUT] to indicate timeout. - * - * Issue: - * https://gitlab.e.foundation/e/backlog/-/issues/5404 - * https://gitlab.e.foundation/e/backlog/-/issues/5413 - */ - suspend fun getHomeScreenData(authData: AuthData): Pair, ResultStatus> { - val preferredApplicationType = preferenceManagerModule.preferredApplicationType() - return getHomeScreenDataBasedOnApplicationType(authData, preferredApplicationType) - } - /** * Check if list in all the FusedHome is empty. * If any list is not empty, send false. @@ -122,44 +111,74 @@ class FusedAPIImpl @Inject constructor( return preferenceManagerModule.preferredApplicationType() } - /* - * Offload fetching application to a different method to dynamically fallback to a different - * app source if the user selected app source times out. - * - * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5404 - */ - private suspend fun getHomeScreenDataBasedOnApplicationType( + suspend fun getHomeScreenData( authData: AuthData, - applicationType: String - ): Pair, ResultStatus> { + ): LiveData>> { + val list = mutableListOf() - val apiStatus = runCodeBlockWithTimeout({ + return liveData { if (preferenceManagerModule.isGplaySelected()) { - list.addAll(fetchGPlayHome(authData)) + loadHomeData(list, Source.GPLAY, authData, this) } if (preferenceManagerModule.isOpenSourceSelected()) { + loadHomeData(list, Source.OPEN, authData, this) + } + + if (preferenceManagerModule.isPWASelected()) { + loadHomeData(list, Source.PWA, authData, this) + } + } + } + + private suspend fun loadHomeData( + priorList: MutableList, + source: Source, + authData: AuthData, + scope: LiveDataScope>>, + ) { + + val apiStatus = when (source) { + + Source.GPLAY -> runCodeBlockWithTimeout({ + priorList.addAll(fetchGPlayHome(authData)) + }) + + Source.OPEN -> runCodeBlockWithTimeout({ val response = cleanAPKRepository.getHomeScreenData( CleanAPKInterface.APP_TYPE_ANY, CleanAPKInterface.APP_SOURCE_FOSS ).body() response?.home?.let { - list.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) + priorList.addAll(generateCleanAPKHome(it, APP_TYPE_OPEN)) } - } + }) - if (preferenceManagerModule.isPWASelected()) { + Source.PWA -> runCodeBlockWithTimeout({ val response = cleanAPKRepository.getHomeScreenData( CleanAPKInterface.APP_TYPE_PWA, CleanAPKInterface.APP_SOURCE_ANY ).body() response?.home?.let { - list.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) + priorList.addAll(generateCleanAPKHome(it, APP_TYPE_PWA)) } + }) + } + + setHomeErrorMessage(apiStatus, source) + + scope.emit(ResultSupreme.create(apiStatus, priorList)) + } + + private fun setHomeErrorMessage(apiStatus: ResultStatus, source: Source) { + if (apiStatus != ResultStatus.OK) { + apiStatus.message = when (source) { + Source.GPLAY -> ("GPlay home loading error\n" + apiStatus.message).trim() + Source.OPEN -> ("Open Source home loading error\n" + apiStatus.message).trim() + Source.PWA -> ("PWA home loading error\n" + apiStatus.message).trim() } - }) - return Pair(list, apiStatus) + } } /* 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 6e99241b9a16c93a61efdfbb6173266347b54c9a..270f65a9e98f77da1f7df45965295f70f544f347 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 @@ -78,7 +78,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII var hasNextStreamCluster = false private set - suspend fun getHomeScreenData(authData: AuthData): Pair, ResultStatus> { + suspend fun getHomeScreenData(authData: AuthData): LiveData>> { return fusedAPIImpl.getHomeScreenData(authData) } 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 c575c14647ef522e14208d392d6aa66fc32e24c5..5fac54cdf2a0555bf69293e199c624f805ff87ac 100644 --- a/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/application/ApplicationFragment.kt @@ -713,7 +713,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { return } val downloadedSize = "${ - Formatter.formatFileSize(requireContext(), progressResult.second).substringBefore(" MB") + Formatter.formatFileSize(requireContext(), progressResult.second).substringBefore(" MB") }/${Formatter.formatFileSize(requireContext(), progressResult.first)}" val progressPercentage = ((progressResult.second / progressResult.first.toDouble()) * 100f).toInt() diff --git a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt index 31dc533114dc8ff96b272a9b4d15db9b41145a7e..db1a5a3fb25ebe6e1fb5de176ecf08a10a0aa834 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt @@ -33,6 +33,7 @@ import foundation.e.apps.AppInfoFetchViewModel import foundation.e.apps.AppProgressViewModel import foundation.e.apps.MainActivityViewModel import foundation.e.apps.R +import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedHome @@ -43,7 +44,6 @@ import foundation.e.apps.home.model.HomeParentRVAdapter import foundation.e.apps.login.AuthObject import foundation.e.apps.manager.download.data.DownloadProgress import foundation.e.apps.manager.pkg.PkgManagerModule -import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.exceptions.GPlayException import foundation.e.apps.utils.exceptions.GPlayLoginException @@ -94,7 +94,7 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface private fun observeHomeScreenData() { homeViewModel.homeScreenData.observe(viewLifecycleOwner) { stopLoadingUI() - if (it.second != ResultStatus.OK) { + if (!it.isSuccess()) { return@observe } @@ -102,7 +102,7 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface return@observe } - homeParentRVAdapter?.setData(it.first) + homeParentRVAdapter?.setData(it.data!!) } } @@ -147,9 +147,9 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface ).show(childFragmentManager, "HomeFragment") } - private fun isHomeDataUpdated(homeScreenResult: Pair, ResultStatus>) = + private fun isHomeDataUpdated(homeScreenResult: ResultSupreme>) = homeParentRVAdapter?.currentList?.isEmpty() == true || homeViewModel.isHomeDataUpdated( - homeScreenResult.first, + homeScreenResult.data!!, homeParentRVAdapter?.currentList as List ) @@ -195,7 +195,7 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface } override fun loadData(authObjectList: List) { - homeViewModel.loadData(authObjectList) { _ -> + homeViewModel.loadData(authObjectList, viewLifecycleOwner) { _ -> clearAndRestartGPlayLogin() true } diff --git a/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt b/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt index 25cb14b7a1826e456f4a6bc0972b2e1ab0d6ff12..d42e4dce0ab5f36682f81464d75bc36a2f9eb37d 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeViewModel.kt @@ -18,15 +18,16 @@ package foundation.e.apps.home +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.lifecycle.HiltViewModel +import foundation.e.apps.api.ResultSupreme import foundation.e.apps.api.fused.FusedAPIRepository import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.login.AuthObject -import foundation.e.apps.utils.enums.ResultStatus import foundation.e.apps.utils.exceptions.CleanApkException import foundation.e.apps.utils.exceptions.GPlayException import foundation.e.apps.utils.parentFragment.LoadingViewModel @@ -44,43 +45,46 @@ class HomeViewModel @Inject constructor( * * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5404 */ - var homeScreenData: MutableLiveData, ResultStatus>> = MutableLiveData() + var homeScreenData: MutableLiveData>> = MutableLiveData() fun loadData( authObjectList: List, + lifecycleOwner: LifecycleOwner, retryBlock: (failedObjects: List) -> Boolean, ) { super.onLoadData(authObjectList, { successAuthList, _ -> successAuthList.find { it is AuthObject.GPlayAuth }?.run { - getHomeScreenData(result.data!! as AuthData) + getHomeScreenData(result.data!! as AuthData, lifecycleOwner) return@onLoadData } successAuthList.find { it is AuthObject.CleanApk }?.run { - getHomeScreenData(AuthData("", "")) + getHomeScreenData(AuthData("", ""), lifecycleOwner) return@onLoadData } }, retryBlock) } - fun getHomeScreenData(authData: AuthData) { + fun getHomeScreenData( + authData: AuthData, + lifecycleOwner: LifecycleOwner, + ) { viewModelScope.launch { - val screenData = fusedAPIRepository.getHomeScreenData(authData) - homeScreenData.postValue(screenData) + fusedAPIRepository.getHomeScreenData(authData).observe(lifecycleOwner) { + homeScreenData.postValue(it) - val status = screenData.second + if (it.isSuccess()) return@observe - if (status != ResultStatus.OK) { val exception = if (authData.aasToken.isNotBlank() || authData.authToken.isNotBlank()) GPlayException( - screenData.second == ResultStatus.TIMEOUT, - status.message.ifBlank { "Data load error" } + it.isTimeout(), + it.message.ifBlank { "Data load error" } ) else CleanApkException( - screenData.second == ResultStatus.TIMEOUT, - status.message.ifBlank { "Data load error" } + it.isTimeout(), + it.message.ifBlank { "Data load error" } ) exceptionsList.add(exception) @@ -94,7 +98,7 @@ class HomeViewModel @Inject constructor( } fun isFusedHomesEmpty(): Boolean { - return homeScreenData.value?.first?.let { + return homeScreenData.value?.data?.let { fusedAPIRepository.isFusedHomesEmpty(it) } ?: true } diff --git a/app/src/main/java/foundation/e/apps/utils/enums/Source.kt b/app/src/main/java/foundation/e/apps/utils/enums/Source.kt new file mode 100644 index 0000000000000000000000000000000000000000..07780704e6dc1e66553b27fb4b2dbb968f594300 --- /dev/null +++ b/app/src/main/java/foundation/e/apps/utils/enums/Source.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019-2022 MURENA SAS + * + * 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.utils.enums + +enum class Source { + GPLAY, + OPEN, + PWA, +}