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

Commit 6da4e723 authored by Hasib Prince's avatar Hasib Prince
Browse files

Merge branch '5847-refactor_viewmodels_fragments' into 'main'

5847 refactor viewmodels fragments

See merge request !179
parents 7b658333 e30b3f2d
Loading
Loading
Loading
Loading
Loading
+3 −40
Original line number Diff line number Diff line
package foundation.e.apps

import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import com.aurora.gplayapi.data.models.AuthData
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel
import foundation.e.apps.api.cleanapk.blockedApps.BlockedAppRepository
import foundation.e.apps.api.faultyApps.FaultyAppRepository
import foundation.e.apps.api.fdroid.FdroidRepository
import foundation.e.apps.api.fdroid.models.FdroidEntity
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.api.gplay.GPlayAPIRepository
import foundation.e.apps.utils.enums.Origin
import foundation.e.apps.utils.modules.DataStoreModule
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject

/**
@@ -34,39 +27,9 @@ class AppInfoFetchViewModel @Inject constructor(
    private val gson: Gson
) : ViewModel() {

    private val fdroidEntries = mutableMapOf<String, FdroidEntity?>()

    fun setAuthorNameIfNeeded(textView: TextView, fusedApp: FusedApp) {
        viewModelScope.launch {
            var authorNameToDisplay = textView.text
            withContext(Dispatchers.Default) {
                fusedApp.run {
                    try {
                        if (author == "unknown" && origin == Origin.CLEANAPK) {

                            withContext(Dispatchers.Main) {
                                textView.text = FdroidEntity.DEFAULT_FDROID_AUTHOR_NAME
                            }

                            var result = fdroidEntries[package_name]
                            if (result == null) {
                                result = fdroidRepository.getFdroidInfo(package_name)?.also {
                                    fdroidEntries[package_name] = it
                                }
                            }
                            result?.authorName?.let {
                                authorNameToDisplay = it
                            }
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
            withContext(Dispatchers.Main) {
                textView.text = authorNameToDisplay
            }
        }
    fun getAuthorName(fusedApp: FusedApp) = liveData {
        val authorName = fdroidRepository.getAuthorName(fusedApp)
        emit(authorName)
    }

    fun isAppPurchased(app: FusedApp): LiveData<Boolean> {
+1 −36
Original line number Diff line number Diff line
@@ -38,41 +38,6 @@ class AppProgressViewModel @Inject constructor(
        fusedApp: FusedApp?,
        progress: DownloadProgress
    ): Int {
        fusedApp?.let { app ->
            val appDownload = fusedManagerRepository.getDownloadList()
                .singleOrNull { it.id.contentEquals(app._id) && it.packageName.contentEquals(app.package_name) }
                ?: return 0

            if (!appDownload.id.contentEquals(app._id) || !appDownload.packageName.contentEquals(app.package_name)) {
                return@let
            }

            if (!isProgressValidForApp(fusedApp, progress)) {
                return -1
            }

            val downloadingMap = progress.totalSizeBytes.filter { item ->
                appDownload.downloadIdMap.keys.contains(item.key) && item.value > 0
            }

            if (appDownload.downloadIdMap.size > downloadingMap.size) { // All files for download are not ready yet
                return 0
            }

            val totalSizeBytes = downloadingMap.values.sum()
            val downloadedSoFar = progress.bytesDownloadedSoFar.filter { item ->
                appDownload.downloadIdMap.keys.contains(item.key)
            }.values.sum()
            return ((downloadedSoFar / totalSizeBytes.toDouble()) * 100).toInt()
        }
        return 0
    }

    private suspend fun isProgressValidForApp(
        fusedApp: FusedApp,
        downloadProgress: DownloadProgress
    ): Boolean {
        val download = fusedManagerRepository.getFusedDownload(downloadProgress.downloadId)
        return download.id == fusedApp._id
        return fusedManagerRepository.calculateProgress(fusedApp, progress)
    }
}
+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()
    }
}
+67 −2
Original line number Diff line number Diff line
@@ -6,26 +6,67 @@ 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(
    private val exodusTrackerApi: ExodusTrackerApi,
    private val trackerDao: TrackerDao
) : IAppPrivacyInfoRepository {

    companion object {
        private const val MAX_TRACKER_SCORE = 9
        private const val MIN_TRACKER_SCORE = 0
        private const val MAX_PERMISSION_SCORE = 10
        private const val MIN_PERMISSION_SCORE = 0
        private const val THRESHOLD_OF_NON_ZERO_TRACKER_SCORE = 5
        private const val THRESHOLD_OF_NON_ZERO_PERMISSION_SCORE = 9
        private const val FACTOR_OF_PERMISSION_SCORE = 0.2
        private const val DIVIDER_OF_PERMISSION_SCORE = 2.0
    }

    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 +136,28 @@ 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 > THRESHOLD_OF_NON_ZERO_TRACKER_SCORE) MIN_TRACKER_SCORE else MAX_TRACKER_SCORE - numberOfTrackers
    }

    private fun calculatePermissionsScore(numberOfPermission: Int): Int {
        return if (numberOfPermission > THRESHOLD_OF_NON_ZERO_PERMISSION_SCORE) MIN_PERMISSION_SCORE else round(
            FACTOR_OF_PERMISSION_SCORE * ceil((MAX_PERMISSION_SCORE - numberOfPermission) / DIVIDER_OF_PERMISSION_SCORE)
        ).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
}
Loading