Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cbbdb71f authored by Sayantan Roychowdhury's avatar Sayantan Roychowdhury
Browse files

Issue 5508: Load home info dynamically

parent 8eac9d80
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ sealed class ResultSupreme<T> {
                if (isUnknownError()) {
                    this.data = data
                } else {
                    this.message = message
                    this.message = message.ifBlank { status.message }
                    this.exception = exception
                }
            }
+49 −30
Original line number Diff line number Diff line
@@ -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<List<FusedHome>, 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<List<FusedHome>, ResultStatus> {
    ): LiveData<ResultSupreme<List<FusedHome>>> {

        val list = mutableListOf<FusedHome>()
        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<FusedHome>,
        source: Source,
        authData: AuthData,
        scope: LiveDataScope<ResultSupreme<List<FusedHome>>>,
    ) {

        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))
                }
            })
        return Pair(list, apiStatus)
        }

        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()
            }
        }
    }

    /*
+1 −1
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ class FusedAPIRepository @Inject constructor(private val fusedAPIImpl: FusedAPII
    var hasNextStreamCluster = false
        private set

    suspend fun getHomeScreenData(authData: AuthData): Pair<List<FusedHome>, ResultStatus> {
    suspend fun getHomeScreenData(authData: AuthData): LiveData<ResultSupreme<List<FusedHome>>> {
        return fusedAPIImpl.getHomeScreenData(authData)
    }

+6 −6
Original line number Diff line number Diff line
@@ -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<List<FusedHome>, ResultStatus>) =
    private fun isHomeDataUpdated(homeScreenResult: ResultSupreme<List<FusedHome>>) =
        homeParentRVAdapter?.currentList?.isEmpty() == true || homeViewModel.isHomeDataUpdated(
            homeScreenResult.first,
            homeScreenResult.data!!,
            homeParentRVAdapter?.currentList as List<FusedHome>
        )

@@ -195,7 +195,7 @@ class HomeFragment : TimeoutFragment(R.layout.fragment_home), FusedAPIInterface
    }

    override fun loadData(authObjectList: List<AuthObject>) {
        homeViewModel.loadData(authObjectList) { _ ->
        homeViewModel.loadData(authObjectList, viewLifecycleOwner) { _ ->
            clearAndRestartGPlayLogin()
            true
        }
+18 −14
Original line number Diff line number Diff line
@@ -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<Pair<List<FusedHome>, ResultStatus>> = MutableLiveData()
    var homeScreenData: MutableLiveData<ResultSupreme<List<FusedHome>>> = MutableLiveData()

    fun loadData(
        authObjectList: List<AuthObject>,
        lifecycleOwner: LifecycleOwner,
        retryBlock: (failedObjects: List<AuthObject>) -> 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
    }
Loading