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

Commit 2c5953bc authored by Hasib Prince's avatar Hasib Prince
Browse files

App Lounge: showing downloading progress in applist

parent 6677f20b
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@ package foundation.e.apps

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import foundation.e.apps.api.fused.FusedAPIRepository
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.manager.download.data.DownloadProgress
import foundation.e.apps.manager.download.data.DownloadProgressLD
@@ -17,16 +16,24 @@ class AppProgressViewModel @Inject constructor(

    val downloadProgress = downloadProgressLD

    suspend fun calculateProgress(fusedApp: FusedApp?, progress: DownloadProgress): Pair<Long, Long> {
    suspend fun calculateProgress(
        fusedApp: FusedApp?,
        progress: DownloadProgress
    ): Pair<Long, Long> {
        fusedApp?.let { app ->
            val appDownload = fusedManagerRepository.getDownloadList()
                .singleOrNull { it.id.contentEquals(app._id) }
                .singleOrNull { it.id.contentEquals(app._id) && it.package_name.contentEquals(app.package_name) }
                ?: return Pair(1, 0)

            if (!appDownload.id.contentEquals(app._id) || !appDownload.package_name.contentEquals(app.package_name)) {
                return@let
            }
            val downloadingMap = progress.totalSizeBytes.filter { item ->
                appDownload?.downloadIdMap?.keys?.contains(item.key) == true
                appDownload.downloadIdMap.keys.contains(item.key)
            }
            val totalSizeBytes = downloadingMap.values.sum()
            val downloadedSoFar = progress.bytesDownloadedSoFar.filter { item ->
                appDownload?.downloadIdMap?.keys?.contains(item.key) == true
                appDownload.downloadIdMap.keys.contains(item.key)
            }.values.sum()

            return Pair(totalSizeBytes, downloadedSoFar)
+12 −4
Original line number Diff line number Diff line
@@ -261,7 +261,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) {
            val fusedApp = applicationViewModel.fusedApp.value ?: FusedApp()

            when (status) {
                Status.INSTALLED -> handleInstalled(installButton, view, fusedApp)
                Status.INSTALLED -> handleInstalled(installButton, view, fusedApp, downloadPB, appSize)
                Status.UPDATABLE -> handleUpdatable(
                    installButton,
                    view,
@@ -270,7 +270,7 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) {
                    appSize
                )
                Status.UNAVAILABLE -> handleUnavaiable(installButton, fusedApp, downloadPB, appSize)
                Status.QUEUED -> handleQueued(installButton, fusedApp)
                Status.QUEUED, Status.AWAITING -> handleQueued(installButton, fusedApp, downloadPB, appSize)
                Status.DOWNLOADING -> handleDownloading(
                    installButton,
                    fusedApp,
@@ -367,8 +367,12 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) {

    private fun handleQueued(
        installButton: MaterialButton,
        fusedApp: FusedApp
        fusedApp: FusedApp,
        downloadPB: RelativeLayout,
        appSize: MaterialTextView
    ) {
        downloadPB.visibility = View.GONE
        appSize.visibility = View.VISIBLE
        installButton.apply {
            text = getString(R.string.cancel)
            setOnClickListener {
@@ -420,8 +424,12 @@ class ApplicationFragment : Fragment(R.layout.fragment_application) {
    private fun handleInstalled(
        installButton: MaterialButton,
        view: View,
        fusedApp: FusedApp
        fusedApp: FusedApp,
        downloadPB: RelativeLayout,
        appSize: MaterialTextView
    ) {
        downloadPB.visibility = View.GONE
        appSize.visibility = View.VISIBLE
        installButton.apply {
            isEnabled = true
            text = getString(R.string.open)
+42 −36
Original line number Diff line number Diff line
@@ -56,21 +56,10 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu

    private var _binding: FragmentApplicationListBinding? = null
    private val binding get() = _binding!!
    private var isDownloadObserverAdded = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mainActivityViewModel.internetConnection.observe(this) { isInternetConnection ->
            mainActivityViewModel.authData.value?.let { authData ->
                if (isInternetConnection) {
                    viewModel.getList(
                        args.category,
                        args.browseUrl,
                        authData,
                        args.source
                    )
                }
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -83,8 +72,33 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu
                view.findNavController().navigate(R.id.categoriesFragment)
            }
        }
    }

    private fun observeDownloadList() {
        mainActivityViewModel.downloadList.observe(viewLifecycleOwner) { list ->
            val categoryList = viewModel.appListLiveData.value?.toMutableList()
            if (!categoryList.isNullOrEmpty()) {
                list.forEach {
                    categoryList.find { app ->
                        app.origin == it.origin && (app.package_name == it.package_name || app._id == it.id)
                    }?.status = it.status
                }
                viewModel.appListLiveData.value = categoryList
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onResume() {
        super.onResume()
        binding.shimmerLayout.startShimmer()

        val recyclerView = binding.recyclerView
        recyclerView.recycledViewPool.setMaxRecycledViews(0, 0)
        val listAdapter =
            findNavController().currentDestination?.id?.let {
                ApplicationListRVAdapter(
@@ -97,46 +111,38 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu
                    appProgressViewModel
                )
            }

        recyclerView.apply {
            adapter = listAdapter
            layoutManager = LinearLayoutManager(view.context)
            layoutManager = LinearLayoutManager(view?.context)
        }

        observeDownloadList()

        viewModel.appListLiveData.observe(viewLifecycleOwner) {
            listAdapter?.setData(it)

            if (!isDownloadObserverAdded) {
                observeDownloadList()
                isDownloadObserverAdded = true
            }
            binding.shimmerLayout.visibility = View.GONE
            recyclerView.visibility = View.VISIBLE
        }
    }

    private fun observeDownloadList() {
        mainActivityViewModel.downloadList.observe(viewLifecycleOwner) { list ->
            val categoryList = viewModel.appListLiveData.value?.toMutableList()
            if (!categoryList.isNullOrEmpty()) {
                list.forEach {
                    categoryList.find { app ->
                        app.origin == it.origin && (app.package_name == it.package_name || app._id == it.id)
                    }?.status = it.status
                }
                viewModel.appListLiveData.value = categoryList
        mainActivityViewModel.internetConnection.observe(viewLifecycleOwner) { isInternetConnection ->
            mainActivityViewModel.authData.value?.let { authData ->
                if (isInternetConnection) {
                    viewModel.getList(
                        args.category,
                        args.browseUrl,
                        authData,
                        args.source
                    )
                }
            }
        }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onResume() {
        super.onResume()
        binding.shimmerLayout.startShimmer()
    }

    override fun onPause() {
        isDownloadObserverAdded = false
        binding.shimmerLayout.stopShimmer()
        super.onPause()
    }
+9 −4
Original line number Diff line number Diff line
@@ -51,10 +51,15 @@ class ApplicationListViewModel @Inject constructor(
                source
            ).map { it.package_name }

            val applicationDetails = fusedAPIRepository.getApplicationDetails(
            val applicationDetails = if (!source.contentEquals("PWA")) {
                fusedAPIRepository.getApplicationDetails(
                    packageNames, authData,
                    getOrigin(source)
                )
            } else {
                fusedAPIRepository.getAppsListBasedOnCategory(category, browseUrl, authData, source)
            }

            appListLiveData.postValue(applicationDetails)
        }
    }
+76 −16
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.viewModelScope
import androidx.navigation.findNavController
import androidx.recyclerview.widget.ListAdapter
@@ -41,7 +43,6 @@ import foundation.e.apps.R
import foundation.e.apps.api.cleanapk.CleanAPKInterface
import foundation.e.apps.api.fused.FusedAPIInterface
import foundation.e.apps.api.fused.data.FusedApp
import foundation.e.apps.application.ApplicationViewModel
import foundation.e.apps.applicationlist.ApplicationListFragmentDirections
import foundation.e.apps.databinding.ApplicationListItemBinding
import foundation.e.apps.manager.pkg.PkgManagerModule
@@ -75,7 +76,54 @@ class ApplicationListRVAdapter(
        .build()

    inner class ViewHolder(val binding: ApplicationListItemBinding) :
        RecyclerView.ViewHolder(binding.root)
        RecyclerView.ViewHolder(binding.root), LifecycleOwner {

        private val lifecycleRegistry = LifecycleRegistry(this)

        init {
            lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
        }

        fun onAppear() {
            lifecycleRegistry.currentState = Lifecycle.State.RESUMED
        }

        fun onDisappear() {
            lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
        }

        override fun getLifecycle(): Lifecycle {
            return lifecycleRegistry
        }
    }

    override fun onViewAttachedToWindow(holder: ViewHolder) {
        super.onViewAttachedToWindow(holder)
        Log.d(TAG, "onViewAttachedToWindow: Appeared: ${holder.absoluteAdapterPosition}")
        holder.onAppear()
    }

    override fun onViewDetachedFromWindow(holder: ViewHolder) {
        holder.onDisappear()
        Log.d(TAG, "onViewAttachedToWindow: Disappeared: ${holder.absoluteAdapterPosition}")
        super.onViewDetachedFromWindow(holder)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        Log.d(TAG, "onDetachedFromRecyclerView: ")
        for (i in 0..recyclerView.childCount) {
            val view = recyclerView.getChildAt(i)
            if (view != null) {
                val holder =
                    recyclerView.getChildViewHolder(view)
                holder?.let {
                    appProgressViewModel.downloadProgress.removeObservers(holder as LifecycleOwner)
                    (holder as ViewHolder).onDisappear()
                }
            }
        }
        super.onDetachedFromRecyclerView(recyclerView)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
@@ -156,28 +204,27 @@ class ApplicationListRVAdapter(
                }
                else -> Log.wtf(TAG, "${searchApp.package_name} is from an unknown origin")
            }
            Log.d(TAG, "onBindViewHolder: ${searchApp.name} : ${searchApp.status}")
            when (searchApp.status) {
                Status.INSTALLED -> {
                    handleInstalled(view, searchApp)
                    handleInstalled(view, searchApp, holder)
                }
                Status.UPDATABLE -> {
                    handleUpdatable(view, searchApp)
                }
                Status.UNAVAILABLE -> {
                    handleUnavailable(view, searchApp)
                    handleUnavailable(view, searchApp, holder)
                }
                Status.QUEUED, Status.AWAITING, Status.DOWNLOADING -> {
                    handleDownloading(view, searchApp)
                    handleDownloading(view, searchApp, holder)
                }
                Status.INSTALLING, Status.UNINSTALLING -> {
                    handleInstalling(view)
                    handleInstalling(view, holder)
                }
                Status.BLOCKED -> {
                    handleBlocked(view)
                }
                Status.INSTALLATION_ISSUE -> {
                    handleInstallationIssue(view, searchApp)
                    handleInstallationIssue(view, searchApp, holder)
                }
            }

@@ -187,8 +234,10 @@ class ApplicationListRVAdapter(

    private fun ApplicationListItemBinding.handleInstallationIssue(
        view: View,
        searchApp: FusedApp
        searchApp: FusedApp,
        holder: ViewHolder
    ) {
        appProgressViewModel.downloadProgress.removeObservers(holder)
        installButton.apply {
            isEnabled = true
            text = view.context.getString(R.string.retry)
@@ -268,7 +317,8 @@ class ApplicationListRVAdapter(
        appPrivacyScore.visibility = View.VISIBLE
    }

    private fun ApplicationListItemBinding.handleInstalling(view: View) {
    private fun ApplicationListItemBinding.handleInstalling(view: View, holder: ViewHolder) {
        appProgressViewModel.downloadProgress.removeObservers(holder)
        installButton.apply {
            isEnabled = false
            setTextColor(context.getColor(R.color.light_grey))
@@ -278,7 +328,11 @@ class ApplicationListRVAdapter(
        }
    }

    private fun ApplicationListItemBinding.handleDownloading(view: View, searchApp: FusedApp) {
    private fun ApplicationListItemBinding.handleDownloading(
        view: View,
        searchApp: FusedApp,
        holder: ViewHolder
    ) {
        installButton.apply {
            isEnabled = true
            text = context.getString(R.string.cancel)
@@ -286,11 +340,10 @@ class ApplicationListRVAdapter(
            backgroundTintList =
                ContextCompat.getColorStateList(view.context, android.R.color.transparent)
            strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent)
            appProgressViewModel.downloadProgress.observe(lifecycleOwner) {
            appProgressViewModel.downloadProgress.observe(holder) {
                appProgressViewModel.viewModelScope.launch {
                    val progress = appProgressViewModel.calculateProgress(searchApp, it)
                    Log.d(TAG, "app Progress: $progress")
                    if(progress.second > 0) {
                    if (progress.second > 0 && progress.second <= progress.first) {
                        text = "${((progress.second / progress.first.toDouble()) * 100).toInt()}%"
                    }
                }
@@ -301,7 +354,11 @@ class ApplicationListRVAdapter(
        }
    }

    private fun ApplicationListItemBinding.handleUnavailable(view: View, searchApp: FusedApp) {
    private fun ApplicationListItemBinding.handleUnavailable(
        view: View,
        searchApp: FusedApp,
        holder: ViewHolder
    ) {
        installButton.apply {
            isEnabled = true
            text = context.getString(R.string.install)
@@ -309,6 +366,7 @@ class ApplicationListRVAdapter(
            backgroundTintList =
                ContextCompat.getColorStateList(view.context, android.R.color.transparent)
            strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent)
            appProgressViewModel.downloadProgress.removeObservers(holder)
            setOnClickListener {
                installApplication(searchApp, appIcon)
            }
@@ -333,7 +391,8 @@ class ApplicationListRVAdapter(

    private fun ApplicationListItemBinding.handleInstalled(
        view: View,
        searchApp: FusedApp
        searchApp: FusedApp,
        holder: ViewHolder
    ) {
        installButton.apply {
            isEnabled = true
@@ -341,6 +400,7 @@ class ApplicationListRVAdapter(
            setTextColor(Color.WHITE)
            backgroundTintList = ContextCompat.getColorStateList(view.context, R.color.colorAccent)
            strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent)
            appProgressViewModel.downloadProgress.removeObservers(holder)
            setOnClickListener {
                context.startActivity(pkgManagerModule.getLaunchIntent(searchApp.package_name))
            }
Loading