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

Commit c1fe865c authored by Hasib Prince's avatar Hasib Prince
Browse files

refactoring applistviewmodel & privacyinfoviewmodel

parent 4d0f4f1f
Loading
Loading
Loading
Loading
Loading
+5 −53
Original line number Diff line number Diff line
@@ -8,10 +8,7 @@ import foundation.e.apps.api.Result
import foundation.e.apps.api.exodus.models.AppPrivacyInfo
import foundation.e.apps.api.exodus.repositories.IAppPrivacyInfoRepository
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL
import javax.inject.Inject
import kotlin.math.ceil
import kotlin.math.round

@HiltViewModel
class PrivacyInfoViewModel @Inject constructor(
@@ -27,40 +24,17 @@ class PrivacyInfoViewModel @Inject constructor(
    private suspend fun fetchEmitAppPrivacyInfo(
        fusedApp: FusedApp
    ): Result<AppPrivacyInfo> {
        if (fusedApp.trackers.isNotEmpty() && fusedApp.permsFromExodus.isNotEmpty()) {
            val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.permsFromExodus)
            return Result.success(appInfo)
        }
        val appPrivacyPrivacyInfoResult =
            privacyInfoRepository.getAppPrivacyInfo(fusedApp.package_name)
        return handleAppPrivacyInfoResult(appPrivacyPrivacyInfoResult, fusedApp)
            privacyInfoRepository.getAppPrivacyInfo(fusedApp, fusedApp.package_name)
        return handleAppPrivacyInfoResult(appPrivacyPrivacyInfoResult)
    }

    private fun handleAppPrivacyInfoResult(
        appPrivacyPrivacyInfoResult: Result<AppPrivacyInfo>,
        fusedApp: FusedApp
    ): Result<AppPrivacyInfo> {
        return if (appPrivacyPrivacyInfoResult.isSuccess()) {
            handleAppPrivacyInfoSuccess(appPrivacyPrivacyInfoResult, fusedApp)
        } else {
        return if (!appPrivacyPrivacyInfoResult.isSuccess()) {
            Result.error("Tracker not found!")
        }
    }

    private fun handleAppPrivacyInfoSuccess(
        appPrivacyPrivacyInfoResult: Result<AppPrivacyInfo>,
        fusedApp: FusedApp
    ): Result<AppPrivacyInfo> {
        fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: LIST_OF_NULL
        fusedApp.permsFromExodus = appPrivacyPrivacyInfoResult.data?.permissionList ?: LIST_OF_NULL
        if (fusedApp.perms.isEmpty() && fusedApp.permsFromExodus != LIST_OF_NULL) {
            /*
             * fusedApp.perms is generally populated from remote source like Play Store.
             * If it is empty then set the value from permissions from exodus api.
             */
            fusedApp.perms = fusedApp.permsFromExodus
        }
        return appPrivacyPrivacyInfoResult
        } else appPrivacyPrivacyInfoResult
    }

    fun getTrackerListText(fusedApp: FusedApp?): String {
@@ -74,30 +48,8 @@ class PrivacyInfoViewModel @Inject constructor(

    fun getPrivacyScore(fusedApp: FusedApp?): Int {
        fusedApp?.let {
            return calculatePrivacyScore(it)
            return privacyInfoRepository.calculatePrivacyScore(it)
        }
        return -1
    }

    fun calculatePrivacyScore(fusedApp: FusedApp): Int {
        if (fusedApp.permsFromExodus == LIST_OF_NULL) {
            return -1
        }
        val calculateTrackersScore = calculateTrackersScore(fusedApp.trackers.size)
        val calculatePermissionsScore = calculatePermissionsScore(
            countAndroidPermissions(fusedApp)
        )
        return calculateTrackersScore + calculatePermissionsScore
    }

    private fun countAndroidPermissions(fusedApp: FusedApp) =
        fusedApp.permsFromExodus.filter { it.contains("android.permission") }.size

    private fun calculateTrackersScore(numberOfTrackers: Int): Int {
        return if (numberOfTrackers > 5) 0 else 9 - numberOfTrackers
    }

    private fun calculatePermissionsScore(numberOfPermission: Int): Int {
        return if (numberOfPermission > 9) 0 else round(0.2 * ceil((10 - numberOfPermission) / 2.0)).toInt()
    }
}
+49 −2
Original line number Diff line number Diff line
@@ -6,10 +6,13 @@ import foundation.e.apps.api.exodus.Report
import foundation.e.apps.api.exodus.Tracker
import foundation.e.apps.api.exodus.TrackerDao
import foundation.e.apps.api.exodus.models.AppPrivacyInfo
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.getResult
import foundation.e.apps.utils.modules.CommonUtilsModule.LIST_OF_NULL
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.ceil
import kotlin.math.round

@Singleton
class AppPrivacyInfoRepositoryImpl @Inject constructor(
@@ -18,14 +21,36 @@ class AppPrivacyInfoRepositoryImpl @Inject constructor(
) : IAppPrivacyInfoRepository {
    private var trackers: List<Tracker> = listOf()

    override suspend fun getAppPrivacyInfo(appHandle: String): Result<AppPrivacyInfo> {
    override suspend fun getAppPrivacyInfo(fusedApp: FusedApp, appHandle: String): Result<AppPrivacyInfo> {
        if (fusedApp.trackers.isNotEmpty() && fusedApp.permsFromExodus.isNotEmpty()) {
            val appInfo = AppPrivacyInfo(fusedApp.trackers, fusedApp.permsFromExodus)
            return Result.success(appInfo)
        }

        val appTrackerInfoResult = getResult { exodusTrackerApi.getTrackerInfoOfApp(appHandle) }
        if (appTrackerInfoResult.isSuccess()) {
            return handleAppPrivacyInfoResultSuccess(appTrackerInfoResult)
            val appPrivacyPrivacyInfoResult = handleAppPrivacyInfoResultSuccess(appTrackerInfoResult)
            updateFusedApp(fusedApp, appPrivacyPrivacyInfoResult)
            return appPrivacyPrivacyInfoResult
        }
        return Result.error(extractErrorMessage(appTrackerInfoResult))
    }

    private fun updateFusedApp(
        fusedApp: FusedApp,
        appPrivacyPrivacyInfoResult: Result<AppPrivacyInfo>
    ) {
        fusedApp.trackers = appPrivacyPrivacyInfoResult.data?.trackerList ?: LIST_OF_NULL
        fusedApp.permsFromExodus = appPrivacyPrivacyInfoResult.data?.permissionList ?: LIST_OF_NULL
        if (fusedApp.perms.isEmpty() && fusedApp.permsFromExodus != LIST_OF_NULL) {
            /*
                 * fusedApp.perms is generally populated from remote source like Play Store.
                 * If it is empty then set the value from permissions from exodus api.
                 */
            fusedApp.perms = fusedApp.permsFromExodus
        }
    }

    private suspend fun handleAppPrivacyInfoResultSuccess(
        appTrackerResult: Result<List<Report>>,
    ): Result<AppPrivacyInfo> {
@@ -95,4 +120,26 @@ class AppPrivacyInfoRepositoryImpl @Inject constructor(
            sortedTrackerData[0].trackers.contains(it.id)
        }.map { it.name }
    }

    override fun calculatePrivacyScore(fusedApp: FusedApp): Int {
        if (fusedApp.permsFromExodus == LIST_OF_NULL) {
            return -1
        }
        val calculateTrackersScore = calculateTrackersScore(fusedApp.trackers.size)
        val calculatePermissionsScore = calculatePermissionsScore(
            countAndroidPermissions(fusedApp)
        )
        return calculateTrackersScore + calculatePermissionsScore
    }

    private fun countAndroidPermissions(fusedApp: FusedApp) =
        fusedApp.permsFromExodus.filter { it.contains("android.permission") }.size

    private fun calculateTrackersScore(numberOfTrackers: Int): Int {
        return if (numberOfTrackers > 5) 0 else 9 - numberOfTrackers
    }

    private fun calculatePermissionsScore(numberOfPermission: Int): Int {
        return if (numberOfPermission > 9) 0 else round(0.2 * ceil((10 - numberOfPermission) / 2.0)).toInt()
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -2,7 +2,9 @@ package foundation.e.apps.api.exodus.repositories

import foundation.e.apps.api.Result
import foundation.e.apps.api.exodus.models.AppPrivacyInfo
import foundation.e.apps.api.fused.data.FusedApp

interface IAppPrivacyInfoRepository {
    suspend fun getAppPrivacyInfo(appHandle: String): Result<AppPrivacyInfo>
    suspend fun getAppPrivacyInfo(fusedApp: FusedApp, appHandle: String): Result<AppPrivacyInfo>
    fun calculatePrivacyScore(fusedApp: FusedApp): Int
}
+1 −4
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ 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.Status
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

@@ -343,7 +342,6 @@ class FusedAPIRepository @Inject constructor(
        authData: AuthData,
        browseUrl: String,
    ): ResultSupreme<List<FusedApp>> {
        Timber.d("hasNextStreamCluster: $hasNextStreamCluster hasNextStreamBundle: $hasNextStreamBundle clusterPointer: $clusterPointer: streambundleSize: ${streamBundle.streamClusters.size} streamClusterSize: ${streamCluster.clusterAppList.size}")
        if (hasNextStreamCluster) {
            getNextStreamCluster(authData).run {
                if (!isSuccess()) {
@@ -369,7 +367,6 @@ class FusedAPIRepository @Inject constructor(
                }
            }
        }
        Timber.d("===> calling last segment")
        return filterRestrictedGPlayApps(authData, streamCluster.clusterAppList)
    }

+0 −33
Original line number Diff line number Diff line
@@ -22,16 +22,12 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aurora.gplayapi.data.models.AuthData
import com.aurora.gplayapi.data.models.StreamBundle
import com.aurora.gplayapi.data.models.StreamCluster
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.utils.enums.Origin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
@@ -44,7 +40,6 @@ class ApplicationListViewModel @Inject constructor(
    var isLoading = false

    fun getList(category: String, browseUrl: String, authData: AuthData, source: String) {
        Timber.d("===> getlist: $isLoading")
        if (isLoading) {
            return
        }
@@ -53,7 +48,6 @@ class ApplicationListViewModel @Inject constructor(
            fusedAPIRepository.getAppList(category, browseUrl, authData, source).apply {
                isLoading = false
                appListLiveData.postValue(this)
                Timber.d("final result: ${this.data?.size}")
            }
        }
    }
@@ -68,33 +62,6 @@ class ApplicationListViewModel @Inject constructor(
        return fusedAPIRepository.isAnyFusedAppUpdated(newFusedApps, oldFusedApps)
    }

    /**
     * Add a placeholder app at the end if more data can be loaded.
     * "Placeholder" app shows a simple progress bar in the RecyclerView, indicating that
     * more apps are being loaded.
     *
     * Note that it mutates the [ResultSupreme] object passed to it.
     *
     * Issue: https://gitlab.e.foundation/e/backlog/-/issues/5131 [2]
     *
     * @param result object from [getNextDataSet]. Data of this object will be updated
     * if [canLoadMore] is true.
     *
     * @return true if a placeholder app was added, false otherwise.
     */
    private fun addPlaceHolderAppIfNeeded(result: ResultSupreme<List<FusedApp>>): Boolean {
        result.apply {
            if (isSuccess() && fusedAPIRepository.canLoadMore()) {
                // Add an empty app at the end if more data can be loaded on scroll
                val newData = data!!.toMutableList()
                newData.add(FusedApp(isPlaceHolder = true))
                setData(newData)
                return true
            }
        }
        return false
    }

    fun loadMore(authData: AuthData, browseUrl: String) {
        viewModelScope.launch {
            if (isLoading) {
Loading