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

Verified Commit 20b30d80 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

fix: update status labels correctly while app gets downloaded/installed

parent ea9be74d
Loading
Loading
Loading
Loading
+27 −20
Original line number Original line Diff line number Diff line
@@ -113,30 +113,37 @@ class AppManagerWrapper @Inject constructor(
            val appDownload = getDownloadList()
            val appDownload = getDownloadList()
                .singleOrNull { it.id.contentEquals(app._id) && it.packageName.contentEquals(app.package_name) }
                .singleOrNull { it.id.contentEquals(app._id) && it.packageName.contentEquals(app.package_name) }
                ?: return 0
                ?: return 0

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

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


            val downloadingMap = progress.totalSizeBytes.filter { item ->
    suspend fun calculateProgress(
                appDownload.downloadIdMap.keys.contains(item.key) && item.value > 0
        appInstall: AppInstall,
        progress: DownloadProgress
    ): Int {
        val downloadIds = appInstall.downloadIdMap.keys
        if (downloadIds.isEmpty()) {
            // Download request exists but ids not yet populated; show 0% instead of dropping percent.
            return 0
        }
        }


            if (appDownload.downloadIdMap.size > downloadingMap.size) { // All files for download are not ready yet
        val totalSizeBytes = progress.totalSizeBytes
            .filterKeys { downloadIds.contains(it) }
            .values
            .sum()
        if (totalSizeBytes <= 0) {
            return 0
            return 0
        }
        }


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

        }
        return ((downloadedSoFar / totalSizeBytes.toDouble()) * 100)
        return 0
            .toInt()
            .coerceIn(0, 100)
    }
    }


    private suspend fun isProgressValidForApp(
    private suspend fun isProgressValidForApp(
+3 −2
Original line number Original line Diff line number Diff line
@@ -57,8 +57,8 @@ import androidx.compose.ui.unit.dp
import coil.compose.rememberImagePainter
import coil.compose.rememberImagePainter
import foundation.e.apps.R
import foundation.e.apps.R
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.ui.compose.theme.AppTheme
import foundation.e.apps.ui.compose.state.InstallButtonAction
import foundation.e.apps.ui.compose.state.InstallButtonAction
import foundation.e.apps.ui.compose.theme.AppTheme


@Composable
@Composable
fun SearchResultListItem(
fun SearchResultListItem(
@@ -303,7 +303,8 @@ private fun PrivacyBadge(
        Button(
        Button(
            onClick = onPrimaryClick,
            onClick = onPrimaryClick,
            enabled = uiState.enabled,
            enabled = uiState.enabled,
            modifier = Modifier.height(40.dp),
            modifier = Modifier
                .height(40.dp),
            shape = RoundedCornerShape(4.dp),
            shape = RoundedCornerShape(4.dp),
            colors = ButtonDefaults.buttonColors(
            colors = ButtonDefaults.buttonColors(
                containerColor = when {
                containerColor = when {
+19 −5
Original line number Original line Diff line number Diff line
@@ -35,7 +35,7 @@ class InstallStatusReconciler @Inject constructor(
        // Prefer matching active download
        // Prefer matching active download
        val activeDownload = snapshot.downloads.find { matches(app, it) }
        val activeDownload = snapshot.downloads.find { matches(app, it) }
        if (activeDownload != null) {
        if (activeDownload != null) {
            val progressPercent = progressPercent(app, progress)
            val progressPercent = progressPercent(activeDownload, progress)
            app.status = activeDownload.status
            app.status = activeDownload.status
            return Result(app, progressPercent)
            return Result(app, progressPercent)
        }
        }
@@ -46,15 +46,29 @@ class InstallStatusReconciler @Inject constructor(
    }
    }


    private fun matches(app: Application, install: AppInstall): Boolean {
    private fun matches(app: Application, install: AppInstall): Boolean {
        return install.packageName == app.package_name || install.id == app._id
        val pkg = app.package_name
        val id = app._id
        return install.packageName == pkg ||
            install.id == id ||
            install.id == pkg
    }
    }


    private suspend fun progressPercent(
    private suspend fun progressPercent(
        app: Application,
        activeDownload: AppInstall,
        progress: DownloadProgress?
        progress: DownloadProgress?
    ): Int? {
    ): Int? {
        if (progress == null) return null
        if (progress == null) return null
        val percent = appManagerWrapper.calculateProgress(app, progress)
        val percent = appManagerWrapper.calculateProgress(activeDownload, progress)
        return percent.takeIf { it in 0..100 }
        if (percent in 0..100) return percent

        // Fallback: compute from the last downloadId emitted by DownloadProgress
        val id = progress.downloadId.takeIf { it != -1L }
        if (id != null && activeDownload.downloadIdMap.containsKey(id)) {
            val total = progress.totalSizeBytes[id] ?: return null
            if (total <= 0) return null
            val done = progress.bytesDownloadedSoFar[id] ?: 0L
            return ((done / total.toDouble()) * 100).toInt().coerceIn(0, 100)
        }
        return null
    }
    }
}
}
+4 −7
Original line number Original line Diff line number Diff line
@@ -18,8 +18,8 @@


package foundation.e.apps.ui.search.v2
package foundation.e.apps.ui.search.v2


import android.content.SharedPreferences
import android.content.Context
import android.content.Context
import android.content.SharedPreferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import androidx.paging.PagingData
@@ -33,25 +33,23 @@ import foundation.e.apps.data.Constants.PREFERENCE_SHOW_PWA
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.data.Application
import foundation.e.apps.data.application.utils.toApplication
import foundation.e.apps.data.application.utils.toApplication
import foundation.e.apps.data.cleanapk.CleanApkRetrofit
import foundation.e.apps.data.cleanapk.CleanApkRetrofit
import foundation.e.apps.data.enums.Status
import foundation.e.apps.data.preference.AppLoungePreference
import foundation.e.apps.data.preference.AppLoungePreference
import foundation.e.apps.data.search.CleanApkSearchParams
import foundation.e.apps.data.search.CleanApkSearchParams
import foundation.e.apps.data.search.PlayStorePagingRepository
import foundation.e.apps.data.search.PlayStorePagingRepository
import foundation.e.apps.data.search.SearchPagingRepository
import foundation.e.apps.data.search.SearchPagingRepository
import foundation.e.apps.install.download.data.DownloadProgress
import foundation.e.apps.install.download.data.DownloadProgress
import foundation.e.apps.ui.compose.state.InstallButtonAction
import foundation.e.apps.ui.compose.state.InstallStatusReconciler
import foundation.e.apps.ui.compose.state.InstallStatusReconciler
import foundation.e.apps.ui.compose.state.InstallStatusStream
import foundation.e.apps.ui.compose.state.InstallStatusStream
import foundation.e.apps.ui.compose.state.StatusSnapshot
import foundation.e.apps.ui.compose.state.StatusSnapshot
import androidx.lifecycle.asFlow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOf
@@ -60,9 +58,8 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Inject
import foundation.e.apps.data.enums.Status


private const val SUGGESTION_DEBOUNCE_MS = 200L
private const val SUGGESTION_DEBOUNCE_MS = 500L


enum class SearchTabType {
enum class SearchTabType {
    STANDARD_APPS,
    STANDARD_APPS,