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

Commit 3732f83d authored by Sayantan Roychowdhury's avatar Sayantan Roychowdhury
Browse files

Merge branch '5131-load_category_apps_on_scroll' into 'main'

Issue 5131 [part 2]: Load category apps on scrolling

See merge request !148
parents c3ceff84 231390ef
Loading
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -45,8 +45,8 @@ import foundation.e.apps.setup.signin.SignInViewModel
import foundation.e.apps.updates.UpdatesNotifier
import foundation.e.apps.updates.UpdatesNotifier
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.enums.User
import foundation.e.apps.utils.parentFragment.TimeoutFragment
import foundation.e.apps.utils.modules.CommonUtilsModule
import foundation.e.apps.utils.modules.CommonUtilsModule
import foundation.e.apps.utils.parentFragment.TimeoutFragment
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
import java.io.File
import java.io.File
import java.util.UUID
import java.util.UUID
@@ -143,8 +143,11 @@ class MainActivity : AppCompatActivity() {
                        Log.d(TAG, "Timeout validating auth data!")
                        Log.d(TAG, "Timeout validating auth data!")
                        val lastFragment = navHostFragment.childFragmentManager.fragments[0]
                        val lastFragment = navHostFragment.childFragmentManager.fragments[0]
                        if (lastFragment is TimeoutFragment) {
                        if (lastFragment is TimeoutFragment) {
                            Log.d(TAG, "Displaying timeout from MainActivity on fragment: "
                            Log.d(
                                    + lastFragment::class.java.name)
                                TAG,
                                "Displaying timeout from MainActivity on fragment: " +
                                    lastFragment::class.java.name
                            )
                            lastFragment.onTimeout()
                            lastFragment.onTimeout()
                        }
                        }
                    }
                    }
+0 −1
Original line number Original line Diff line number Diff line
@@ -40,7 +40,6 @@ import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository
import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository
import foundation.e.apps.api.ecloud.EcloudRepository
import foundation.e.apps.api.ecloud.EcloudRepository
import foundation.e.apps.api.fused.FusedAPIImpl
import foundation.e.apps.api.fused.FusedAPIRepository
import foundation.e.apps.api.fused.FusedAPIRepository
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
+9 −7
Original line number Original line Diff line number Diff line
@@ -161,8 +161,10 @@ sealed class ResultSupreme<T> {
                is Timeout -> ResultStatus.TIMEOUT
                is Timeout -> ResultStatus.TIMEOUT
                is Error -> ResultStatus.UNKNOWN
                is Error -> ResultStatus.UNKNOWN
            }
            }
            return create(status, newData, message ?: result.message,
            return create(
                exception ?: result.exception)
                status, newData, message ?: result.message,
                exception ?: result.exception
            )
        }
        }
    }
    }
}
}
+81 −49
Original line number Original line Diff line number Diff line
@@ -27,9 +27,12 @@ import com.aurora.gplayapi.data.models.App
import com.aurora.gplayapi.data.models.Artwork
import com.aurora.gplayapi.data.models.Artwork
import com.aurora.gplayapi.data.models.AuthData
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.StreamCluster
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
import foundation.e.apps.api.ResultSupreme
import foundation.e.apps.api.cleanapk.CleanAPKInterface
import foundation.e.apps.api.cleanapk.CleanAPKInterface
import foundation.e.apps.api.cleanapk.CleanAPKRepository
import foundation.e.apps.api.cleanapk.CleanAPKRepository
import foundation.e.apps.api.cleanapk.data.categories.Categories
import foundation.e.apps.api.cleanapk.data.categories.Categories
@@ -45,9 +48,9 @@ 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.enums.AppTag
import foundation.e.apps.utils.enums.AppTag
import foundation.e.apps.utils.enums.Origin
import foundation.e.apps.utils.enums.Origin
import foundation.e.apps.utils.enums.ResultStatus
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.ResultStatus
import foundation.e.apps.utils.modules.CommonUtilsModule.timeoutDurationInMillis
import foundation.e.apps.utils.modules.CommonUtilsModule.timeoutDurationInMillis
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
@@ -273,30 +276,8 @@ class FusedAPIImpl @Inject constructor(
        fusedDownload.downloadURLList = list
        fusedDownload.downloadURLList = list
    }
    }


    suspend fun listApps(category: String, browseUrl: String, authData: AuthData): List<FusedApp>? {
    suspend fun getPWAApps(category: String): ResultSupreme<List<FusedApp>> {
        val preferredApplicationType = preferenceManagerModule.preferredApplicationType()
        val list = mutableListOf<FusedApp>()

        if (preferredApplicationType != "any") {
            val response = if (preferredApplicationType == "open") {
                getOpenSourceAppsResponse(category)
            } else {
                getPWAAppsResponse(category)
            }
            response?.apps?.forEach {
                it.updateStatus()
                it.updateType()
            }
            return response?.apps
        } else {
            val listApps = gPlayAPIRepository.listApps(browseUrl, authData)
            return listApps.map { app ->
                app.transformToFusedApp()
            }
        }
    }

    suspend fun getPWAApps(category: String): Pair<List<FusedApp>, ResultStatus> {
        var list = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            val response = getPWAAppsResponse(category)
            val response = getPWAAppsResponse(category)
            response?.apps?.forEach {
            response?.apps?.forEach {
@@ -305,10 +286,10 @@ class FusedAPIImpl @Inject constructor(
                list.add(it)
                list.add(it)
            }
            }
        })
        })
        return Pair(list, status)
        return ResultSupreme.create(status, list)
    }
    }


    suspend fun getOpenSourceApps(category: String): Pair<List<FusedApp>, ResultStatus> {
    suspend fun getOpenSourceApps(category: String): ResultSupreme<List<FusedApp>> {
        val list = mutableListOf<FusedApp>()
        val list = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            val response = getOpenSourceAppsResponse(category)
            val response = getOpenSourceAppsResponse(category)
@@ -318,36 +299,54 @@ class FusedAPIImpl @Inject constructor(
                list.add(it)
                list.add(it)
            }
            }
        })
        })
        return Pair(list, status)
        return ResultSupreme.create(status, list)
    }
    }


    suspend fun getPlayStoreApps(browseUrl: String, authData: AuthData): Pair<List<FusedApp>, ResultStatus> {
    suspend fun getNextStreamBundle(
        var list = mutableListOf<FusedApp>()
        authData: AuthData,
        homeUrl: String,
        currentStreamBundle: StreamBundle,
    ): ResultSupreme<StreamBundle> {
        var streamBundle = StreamBundle()
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            list.addAll(gPlayAPIRepository.listApps(browseUrl, authData).map { app ->
            streamBundle = gPlayAPIRepository.getNextStreamBundle(authData, homeUrl, currentStreamBundle)
                app.transformToFusedApp()
        })
        })
        })
        return ResultSupreme.create(status, streamBundle)
        return Pair(list, status)
    }
    }


    suspend fun getPlayStoreAppCategoryUrls(browseUrl: String, authData: AuthData): List<String> {
    suspend fun getAdjustedFirstCluster(
        return gPlayAPIRepository.listAppCategoryUrls(browseUrl, authData)
        authData: AuthData,
        streamBundle: StreamBundle,
        pointer: Int = 0,
    ): ResultSupreme<StreamCluster> {
        var streamCluster = StreamCluster()
        val status = runCodeBlockWithTimeout({
            streamCluster = gPlayAPIRepository.getAdjustedFirstCluster(authData, streamBundle, pointer)
        })
        return ResultSupreme.create(status, streamCluster)
    }
    }


    suspend fun getAppsAndNextClusterUrl(
    suspend fun getNextStreamCluster(
        browseUrl: String,
        authData: AuthData,
        authData: AuthData
        currentStreamCluster: StreamCluster,
    ): Triple<List<FusedApp>, String, ResultStatus> {
    ): ResultSupreme<StreamCluster> {
        val appsList = mutableListOf<FusedApp>()
        var streamCluster = StreamCluster()
        var nextUrl = ""
        val status = runCodeBlockWithTimeout({
        val status = runCodeBlockWithTimeout({
            val gPlayResult = gPlayAPIRepository.getAppsAndNextClusterUrl(browseUrl, authData)
            streamCluster = gPlayAPIRepository.getNextStreamCluster(authData, currentStreamCluster)
            appsList.addAll(gPlayResult.first.map { app -> app.transformToFusedApp() })
            nextUrl = gPlayResult.second
        })
        })
        return ResultSupreme.create(status, streamCluster)
    }


        return Triple(appsList, nextUrl, status)
    suspend fun getPlayStoreApps(browseUrl: String, authData: AuthData): ResultSupreme<List<FusedApp>> {
        val list = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
            list.addAll(
                gPlayAPIRepository.listApps(browseUrl, authData).map { app ->
                    app.transformToFusedApp()
                }
            )
        })
        return ResultSupreme.create(status, list)
    }
    }


    suspend fun getApplicationDetails(
    suspend fun getApplicationDetails(
@@ -450,6 +449,39 @@ class FusedAPIImpl @Inject constructor(
        return Pair(fusedAppList, status)
        return Pair(fusedAppList, status)
    }
    }


    /**
     * Filter out apps which are restricted, whose details cannot be fetched.
     * If an app is restricted, we do try to fetch the app details inside a
     * try-catch block. If that fails, we remove the app, else we keep it even
     * if it is restricted.
     *
     * Popular example: "com.skype.m2"
     *
     * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5174
     * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2]
     */
    suspend fun filterRestrictedGPlayApps(
        authData: AuthData,
        appList: List<App>,
    ): ResultSupreme<List<FusedApp>> {
        val filteredFusedApps = mutableListOf<FusedApp>()
        val status = runCodeBlockWithTimeout({
            appList.forEach {
                if (it.restriction != Constants.Restriction.NOT_RESTRICTED) {
                    try {
                        gPlayAPIRepository.getAppDetails(it.packageName, authData)?.let { app ->
                            filteredFusedApps.add(app.transformToFusedApp())
                        }
                    } catch (e: Exception) {}
                } else {
                    filteredFusedApps.add(it.transformToFusedApp())
                }
            }
        })

        return ResultSupreme.create(status, filteredFusedApps)
    }

    suspend fun getApplicationDetails(
    suspend fun getApplicationDetails(
        id: String,
        id: String,
        packageName: String,
        packageName: String,
@@ -555,7 +587,6 @@ class FusedAPIImpl @Inject constructor(
            apiStatus = ResultStatus.UNKNOWN
            apiStatus = ResultStatus.UNKNOWN
        })
        })



        /*
        /*
         * Try within timeout limit to get PWA categories
         * Try within timeout limit to get PWA categories
         */
         */
@@ -922,7 +953,8 @@ class FusedAPIImpl @Inject constructor(
            originalSize = this.size,
            originalSize = this.size,
            appSize = Formatter.formatFileSize(context, this.size),
            appSize = Formatter.formatFileSize(context, this.size),
            isFree = this.isFree,
            isFree = this.isFree,
            price = this.price
            price = this.price,
            restriction = this.restriction,
        )
        )
        app.updateStatus()
        app.updateStatus()
        return app
        return app
+30 −8
Original line number Original line Diff line number Diff line
@@ -19,14 +19,18 @@
package foundation.e.apps.api.fused
package foundation.e.apps.api.fused


import com.aurora.gplayapi.SearchSuggestEntry
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.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.StreamCluster
import foundation.e.apps.api.ResultSupreme
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.fused.data.FusedCategory
import foundation.e.apps.api.fused.data.FusedCategory
import foundation.e.apps.api.fused.data.FusedHome
import foundation.e.apps.api.fused.data.FusedHome
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.manager.database.fusedDownload.FusedDownload
import foundation.e.apps.utils.enums.ResultStatus
import foundation.e.apps.utils.enums.Origin
import foundation.e.apps.utils.enums.Origin
import foundation.e.apps.utils.enums.ResultStatus
import foundation.e.apps.utils.enums.Status
import foundation.e.apps.utils.enums.Status
import javax.inject.Inject
import javax.inject.Inject
import javax.inject.Singleton
import javax.inject.Singleton
@@ -59,6 +63,13 @@ class FusedAPIRepository @Inject constructor(
        return fusedAPIImpl.getApplicationDetails(packageNameList, authData, origin)
        return fusedAPIImpl.getApplicationDetails(packageNameList, authData, origin)
    }
    }


    suspend fun filterRestrictedGPlayApps(
        authData: AuthData,
        appList: List<App>,
    ): ResultSupreme<List<FusedApp>> {
        return fusedAPIImpl.filterRestrictedGPlayApps(authData, appList)
    }

    suspend fun getApplicationDetails(
    suspend fun getApplicationDetails(
        id: String,
        id: String,
        packageName: String,
        packageName: String,
@@ -100,16 +111,27 @@ class FusedAPIRepository @Inject constructor(
        return fusedAPIImpl.getSearchResults(query, authData)
        return fusedAPIImpl.getSearchResults(query, authData)
    }
    }


    suspend fun listApps(category: String, browseUrl: String, authData: AuthData): List<FusedApp>? {
    suspend fun getNextStreamBundle(
        return fusedAPIImpl.listApps(category, browseUrl, authData)
        authData: AuthData,
        homeUrl: String,
        currentStreamBundle: StreamBundle,
    ): ResultSupreme<StreamBundle> {
        return fusedAPIImpl.getNextStreamBundle(authData, homeUrl, currentStreamBundle)
    }
    }


    suspend fun getPlayStoreAppCategoryUrls(browseUrl: String, authData: AuthData): List<String> {
    suspend fun getAdjustedFirstCluster(
        return fusedAPIImpl.getPlayStoreAppCategoryUrls(browseUrl, authData)
        authData: AuthData,
        streamBundle: StreamBundle,
        pointer: Int = 0,
    ): ResultSupreme<StreamCluster> {
        return fusedAPIImpl.getAdjustedFirstCluster(authData, streamBundle, pointer)
    }
    }


    suspend fun getAppsAndNextClusterUrl(browseUrl: String, authData: AuthData): Triple<List<FusedApp>, String, ResultStatus> {
    suspend fun getNextStreamCluster(
        return fusedAPIImpl.getAppsAndNextClusterUrl(browseUrl, authData)
        authData: AuthData,
        currentStreamCluster: StreamCluster,
    ): ResultSupreme<StreamCluster> {
        return fusedAPIImpl.getNextStreamCluster(authData, currentStreamCluster)
    }
    }


    suspend fun getAppsListBasedOnCategory(
    suspend fun getAppsListBasedOnCategory(
@@ -117,7 +139,7 @@ class FusedAPIRepository @Inject constructor(
        browseUrl: String,
        browseUrl: String,
        authData: AuthData,
        authData: AuthData,
        source: String
        source: String
    ): Pair<List<FusedApp>, ResultStatus> {
    ): ResultSupreme<List<FusedApp>> {
        return when (source) {
        return when (source) {
            "Open Source" -> fusedAPIImpl.getOpenSourceApps(category)
            "Open Source" -> fusedAPIImpl.getOpenSourceApps(category)
            "PWA" -> fusedAPIImpl.getPWAApps(category)
            "PWA" -> fusedAPIImpl.getPWAApps(category)
Loading