From e2388fbc519007e6bfc751d818e102d556bb2898 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Fri, 25 Mar 2022 19:00:43 +0600 Subject: [PATCH 1/2] App Lounge: strategy changed of showing progress in homepage --- .../foundation/e/apps/home/HomeFragment.kt | 1 + .../e/apps/home/model/HomeChildRVAdapter.kt | 49 ++++--------------- .../e/apps/home/model/HomeParentRVAdapter.kt | 27 +++++++++- .../download/data/DownloadProgressLD.kt | 1 - 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt index 5b910a640..bc4ee23e7 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt @@ -24,6 +24,7 @@ import android.widget.ImageView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt index bda203ba4..4c9e1e0f7 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt @@ -19,6 +19,7 @@ package foundation.e.apps.home.model import android.graphics.Color +import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import android.widget.ImageView @@ -70,7 +71,12 @@ class HomeChildRVAdapter( lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED } + fun onCreated() { + lifecycleRegistry.currentState = Lifecycle.State.CREATED + } + fun onAppear() { + lifecycleRegistry.currentState = Lifecycle.State.STARTED lifecycleRegistry.currentState = Lifecycle.State.RESUMED } @@ -83,38 +89,15 @@ class HomeChildRVAdapter( } } - override fun onViewAttachedToWindow(holder: HomeChildRVAdapter.ViewHolder) { - super.onViewAttachedToWindow(holder) - holder.onAppear() - } - - override fun onViewDetachedFromWindow(holder: HomeChildRVAdapter.ViewHolder) { - holder.onDisappear() - super.onViewDetachedFromWindow(holder) - } - - override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { - 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 HomeChildRVAdapter.ViewHolder).onDisappear() - } - } - } - super.onDetachedFromRecyclerView(recyclerView) - } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder( + val viewHolder = ViewHolder( HomeChildListItemBinding.inflate( LayoutInflater.from(parent.context), parent, false ) ) + return viewHolder } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -141,9 +124,9 @@ class HomeChildRVAdapter( ) holder.itemView.findNavController().navigate(action) } + when (homeApp.status) { Status.INSTALLED -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { isEnabled = true text = context.getString(R.string.open) @@ -158,7 +141,6 @@ class HomeChildRVAdapter( } } Status.UPDATABLE -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { text = context.getString(R.string.update) setTextColor(Color.WHITE) @@ -172,7 +154,6 @@ class HomeChildRVAdapter( } } Status.UNAVAILABLE -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { text = context.getString(R.string.install) setTextColor(context.getColor(R.color.colorAccent)) @@ -198,22 +179,12 @@ class HomeChildRVAdapter( strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) - appProgressViewModel.downloadProgress.observe(holder) { - appProgressViewModel.viewModelScope.launch { - val progress = appProgressViewModel.calculateProgress(homeApp, it) - if (progress.second > 0 && progress.second <= progress.first) { - text = "${((progress.second / progress.first.toDouble()) * 100).toInt()}%" - } - } - } - setOnClickListener { cancelDownload(homeApp) } } } Status.INSTALLING, Status.UNINSTALLING -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { isEnabled = false setTextColor(context.getColor(R.color.light_grey)) @@ -226,7 +197,6 @@ class HomeChildRVAdapter( } } Status.BLOCKED -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.setOnClickListener { val errorMsg = when (user) { User.ANONYMOUS, @@ -239,7 +209,6 @@ class HomeChildRVAdapter( } } Status.INSTALLATION_ISSUE -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { text = view.context.getString(R.string.retry) setTextColor(context.getColor(R.color.colorAccent)) diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt index b31b68e60..83bde0513 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt @@ -18,9 +18,11 @@ package foundation.e.apps.home.model +import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.viewModelScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView @@ -32,7 +34,9 @@ import foundation.e.apps.api.fused.data.FusedHome import foundation.e.apps.databinding.HomeParentListItemBinding import foundation.e.apps.manager.database.fusedDownload.FusedDownload import foundation.e.apps.manager.pkg.PkgManagerModule +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User +import kotlinx.coroutines.launch class HomeParentRVAdapter( private val fusedAPIInterface: FusedAPIInterface, @@ -56,7 +60,8 @@ class HomeParentRVAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val fusedHome = getItem(position) - val homeChildRVAdapter = HomeChildRVAdapter(fusedAPIInterface, pkgManagerModule, user, appProgressViewModel) + val homeChildRVAdapter = + HomeChildRVAdapter(fusedAPIInterface, pkgManagerModule, user, appProgressViewModel) homeChildRVAdapter.setData(fusedHome.list) holder.binding.titleTV.text = fusedHome.title @@ -71,6 +76,26 @@ class HomeParentRVAdapter( ) setRecycledViewPool(viewPool) } + + appProgressViewModel.downloadProgress.observe(lifecycleOwner) { + val childRV = holder.binding.childRV + val adapter = childRV.adapter as HomeChildRVAdapter + appProgressViewModel.viewModelScope.launch { + adapter.currentList.forEach { fusedApp -> + if(fusedApp.status == Status.DOWNLOADING) { + val progress = appProgressViewModel.calculateProgress(fusedApp, it) + val downloadProgress = + ((progress.second / progress.first.toDouble()) * 100).toInt() + Log.d("HomeParentAdapter", "download progress of ===> ${fusedApp.name} : $downloadProgress") + val viewHolder = childRV.findViewHolderForAdapterPosition(adapter.currentList.indexOf(fusedApp)) + viewHolder?.let { + (viewHolder as HomeChildRVAdapter.ViewHolder).binding.installButton.text = "$downloadProgress%" + } + } + } + + } + } observeAppInstall(fusedHome, homeChildRVAdapter) } diff --git a/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt b/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt index 8fe3a037f..efeb58da0 100644 --- a/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt +++ b/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt @@ -14,7 +14,6 @@ import javax.inject.Inject import javax.inject.Singleton import kotlin.coroutines.CoroutineContext -@Singleton class DownloadProgressLD @Inject constructor( private val downloadManager: DownloadManager, private val downloadManagerQuery: DownloadManager.Query, -- GitLab From b4e3c6a22330e0f9876e73a5ba6cb8c1c33e5990 Mon Sep 17 00:00:00 2001 From: Hasib Prince Date: Mon, 28 Mar 2022 09:20:20 +0600 Subject: [PATCH 2/2] App lounge: showing percentage strategy app list Showing percentage strategy is changed. lifecycle awrare list item views are removed as they are error prone and creates memory leaks fixed showing percentage from different category of homepage fixed livedata isActive issue due to job cancellation refactoring --- .../ApplicationListFragment.kt | 41 ++++++++- .../model/ApplicationListRVAdapter.kt | 74 ++-------------- .../foundation/e/apps/home/HomeFragment.kt | 52 ++++++++++- .../e/apps/home/model/HomeChildRVAdapter.kt | 28 +----- .../e/apps/home/model/HomeParentRVAdapter.kt | 26 +----- .../download/data/DownloadProgressLD.kt | 87 +++++++++++-------- .../e/apps/search/SearchFragment.kt | 26 +++++- .../e/apps/updates/UpdatesFragment.kt | 37 +++++++- 8 files changed, 210 insertions(+), 161 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt index 93210b92d..b03c208be 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/ApplicationListFragment.kt @@ -19,15 +19,18 @@ package foundation.e.apps.applicationlist import android.os.Bundle +import android.util.Log import android.view.View import android.widget.ImageView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppProgressViewModel import foundation.e.apps.MainActivityViewModel @@ -37,8 +40,12 @@ import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.applicationlist.model.ApplicationListRVAdapter import foundation.e.apps.databinding.FragmentApplicationListBinding +import foundation.e.apps.home.model.HomeChildRVAdapter +import foundation.e.apps.manager.download.data.DownloadProgress import foundation.e.apps.manager.pkg.PkgManagerModule +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User +import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint @@ -107,8 +114,7 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu it, pkgManagerModule, User.valueOf(mainActivityViewModel.userType.value ?: User.UNAVAILABLE.name), - viewLifecycleOwner, - appProgressViewModel + viewLifecycleOwner ) } @@ -117,6 +123,10 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu layoutManager = LinearLayoutManager(view?.context) } + appProgressViewModel.downloadProgress.observe(viewLifecycleOwner) { + updateProgressOfDownloadingItems(recyclerView, it) + } + viewModel.appListLiveData.observe(viewLifecycleOwner) { listAdapter?.setData(it) if (!isDownloadObserverAdded) { @@ -141,6 +151,33 @@ class ApplicationListFragment : Fragment(R.layout.fragment_application_list), Fu } } + private fun updateProgressOfDownloadingItems( + recyclerView: RecyclerView, + it: DownloadProgress + ) { + val adapter = recyclerView.adapter as ApplicationListRVAdapter + lifecycleScope.launch { + adapter.currentList.forEach { fusedApp -> + if (fusedApp.status == Status.DOWNLOADING) { + val progress = appProgressViewModel.calculateProgress(fusedApp, it) + val downloadProgress = + ((progress.second / progress.first.toDouble()) * 100).toInt() + Log.d( + "HomeParentAdapter", + "download progress of ===> ${fusedApp.name} : $downloadProgress" + ) + val viewHolder = recyclerView.findViewHolderForAdapterPosition( + adapter.currentList.indexOf(fusedApp) + ) + viewHolder?.let { + (viewHolder as ApplicationListRVAdapter.ViewHolder).binding.installButton.text = + "$downloadProgress%" + } + } + } + } + } + override fun onPause() { isDownloadObserverAdded = false binding.shimmerLayout.stopShimmer() diff --git a/app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt index e1862fbd8..65deacdb8 100644 --- a/app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/applicationlist/model/ApplicationListRVAdapter.kt @@ -62,7 +62,6 @@ class ApplicationListRVAdapter( private val pkgManagerModule: PkgManagerModule, private val user: User, private val lifecycleOwner: LifecycleOwner, - private val appProgressViewModel: AppProgressViewModel ) : ListAdapter(ApplicationDiffUtil()) { private val TAG = ApplicationListRVAdapter::class.java.simpleName @@ -76,54 +75,7 @@ class ApplicationListRVAdapter( .build() inner class ViewHolder(val binding: ApplicationListItemBinding) : - 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) - } + RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( @@ -206,16 +158,16 @@ class ApplicationListRVAdapter( } when (searchApp.status) { Status.INSTALLED -> { - handleInstalled(view, searchApp, holder) + handleInstalled(view, searchApp) } Status.UPDATABLE -> { handleUpdatable(view, searchApp) } Status.UNAVAILABLE -> { - handleUnavailable(view, searchApp, holder) + handleUnavailable(view, searchApp) } Status.QUEUED, Status.AWAITING, Status.DOWNLOADING -> { - handleDownloading(view, searchApp, holder) + handleDownloading(view, searchApp) } Status.INSTALLING, Status.UNINSTALLING -> { handleInstalling(view, holder) @@ -224,7 +176,7 @@ class ApplicationListRVAdapter( handleBlocked(view) } Status.INSTALLATION_ISSUE -> { - handleInstallationIssue(view, searchApp, holder) + handleInstallationIssue(view, searchApp) } } @@ -235,9 +187,7 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstallationIssue( view: View, searchApp: FusedApp, - holder: ViewHolder ) { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { isEnabled = true text = view.context.getString(R.string.retry) @@ -318,7 +268,6 @@ class ApplicationListRVAdapter( } private fun ApplicationListItemBinding.handleInstalling(view: View, holder: ViewHolder) { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { isEnabled = false setTextColor(context.getColor(R.color.light_grey)) @@ -331,7 +280,6 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleDownloading( view: View, searchApp: FusedApp, - holder: ViewHolder ) { installButton.apply { isEnabled = true @@ -340,14 +288,6 @@ class ApplicationListRVAdapter( backgroundTintList = ContextCompat.getColorStateList(view.context, android.R.color.transparent) strokeColor = ContextCompat.getColorStateList(view.context, R.color.colorAccent) - appProgressViewModel.downloadProgress.observe(holder) { - appProgressViewModel.viewModelScope.launch { - val progress = appProgressViewModel.calculateProgress(searchApp, it) - if (progress.second > 0 && progress.second <= progress.first) { - text = "${((progress.second / progress.first.toDouble()) * 100).toInt()}%" - } - } - } setOnClickListener { cancelDownload(searchApp) } @@ -357,7 +297,6 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleUnavailable( view: View, searchApp: FusedApp, - holder: ViewHolder ) { installButton.apply { isEnabled = true @@ -366,7 +305,6 @@ 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) } @@ -392,7 +330,6 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.handleInstalled( view: View, searchApp: FusedApp, - holder: ViewHolder ) { installButton.apply { isEnabled = true @@ -400,7 +337,6 @@ 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)) } diff --git a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt index bc4ee23e7..7773a4537 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt @@ -27,6 +27,7 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppProgressViewModel import foundation.e.apps.MainActivityViewModel @@ -34,9 +35,13 @@ import foundation.e.apps.R import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.databinding.FragmentHomeBinding +import foundation.e.apps.home.model.HomeChildRVAdapter import foundation.e.apps.home.model.HomeParentRVAdapter +import foundation.e.apps.manager.download.data.DownloadProgress import foundation.e.apps.manager.pkg.PkgManagerModule +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User +import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint @@ -78,7 +83,7 @@ class HomeFragment : Fragment(R.layout.fragment_home), FusedAPIInterface { this, pkgManagerModule, User.valueOf(mainActivityViewModel.userType.value ?: User.UNAVAILABLE.name), - mainActivityViewModel, viewLifecycleOwner, appProgressViewModel + mainActivityViewModel, viewLifecycleOwner ) binding.parentRV.apply { @@ -91,6 +96,51 @@ class HomeFragment : Fragment(R.layout.fragment_home), FusedAPIInterface { binding.shimmerLayout.visibility = View.GONE binding.parentRV.visibility = View.VISIBLE } + + appProgressViewModel.downloadProgress.observe(viewLifecycleOwner) { + updateProgressOfDownloadingAppItemViews(homeParentRVAdapter, it) + } + } + + private fun updateProgressOfDownloadingAppItemViews( + homeParentRVAdapter: HomeParentRVAdapter, + downloadProgress: DownloadProgress + ) { + homeParentRVAdapter.currentList.forEach { fusedHome -> + val viewHolder = binding.parentRV.findViewHolderForAdapterPosition( + homeParentRVAdapter.currentList.indexOf(fusedHome) + ) + viewHolder?.let { parentViewHolder -> + val childRV = + (parentViewHolder as HomeParentRVAdapter.ViewHolder).binding.childRV + val adapter = childRV.adapter as HomeChildRVAdapter + findDownloadingItemsToShowProgress(adapter, downloadProgress, childRV) + } + } + } + + private fun findDownloadingItemsToShowProgress( + adapter: HomeChildRVAdapter, + downloadProgress: DownloadProgress, + childRV: RecyclerView + ) { + lifecycleScope.launch { + adapter.currentList.forEach { fusedApp -> + if (fusedApp.status == Status.DOWNLOADING) { + val progress = + appProgressViewModel.calculateProgress(fusedApp, downloadProgress) + val downloadProgress = + ((progress.second / progress.first.toDouble()) * 100).toInt() + val childViewHolder = childRV.findViewHolderForAdapterPosition( + adapter.currentList.indexOf(fusedApp) + ) + childViewHolder?.let { + (childViewHolder as HomeChildRVAdapter.ViewHolder).binding.installButton.text = + "$downloadProgress%" + } + } + } + } } override fun onResume() { diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt index 4c9e1e0f7..194639b52 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeChildRVAdapter.kt @@ -51,8 +51,7 @@ import kotlinx.coroutines.launch class HomeChildRVAdapter( private val fusedAPIInterface: FusedAPIInterface, private val pkgManagerModule: PkgManagerModule, - private val user: User, - private val appProgressViewModel: AppProgressViewModel + private val user: User ) : ListAdapter(HomeChildFusedAppDiffUtil()) { private val shimmer = Shimmer.ColorHighlightBuilder() @@ -64,30 +63,7 @@ class HomeChildRVAdapter( .build() inner class ViewHolder(val binding: HomeChildListItemBinding) : - RecyclerView.ViewHolder(binding.root), LifecycleOwner { - private val lifecycleRegistry = LifecycleRegistry(this) - - init { - lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED - } - - fun onCreated() { - lifecycleRegistry.currentState = Lifecycle.State.CREATED - } - - fun onAppear() { - lifecycleRegistry.currentState = Lifecycle.State.STARTED - lifecycleRegistry.currentState = Lifecycle.State.RESUMED - } - - fun onDisappear() { - lifecycleRegistry.currentState = Lifecycle.State.DESTROYED - } - - override fun getLifecycle(): Lifecycle { - return lifecycleRegistry - } - } + RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val viewHolder = ViewHolder( diff --git a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt index 83bde0513..0c971d51c 100644 --- a/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/home/model/HomeParentRVAdapter.kt @@ -18,7 +18,6 @@ package foundation.e.apps.home.model -import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import androidx.lifecycle.LifecycleOwner @@ -43,8 +42,7 @@ class HomeParentRVAdapter( private val pkgManagerModule: PkgManagerModule, private val user: User, private val mainActivityViewModel: MainActivityViewModel, - private val lifecycleOwner: LifecycleOwner, - private val appProgressViewModel: AppProgressViewModel + private val lifecycleOwner: LifecycleOwner ) : ListAdapter(FusedHomeDiffUtil()) { private val viewPool = RecyclerView.RecycledViewPool() @@ -61,7 +59,7 @@ class HomeParentRVAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val fusedHome = getItem(position) val homeChildRVAdapter = - HomeChildRVAdapter(fusedAPIInterface, pkgManagerModule, user, appProgressViewModel) + HomeChildRVAdapter(fusedAPIInterface, pkgManagerModule, user) homeChildRVAdapter.setData(fusedHome.list) holder.binding.titleTV.text = fusedHome.title @@ -76,26 +74,6 @@ class HomeParentRVAdapter( ) setRecycledViewPool(viewPool) } - - appProgressViewModel.downloadProgress.observe(lifecycleOwner) { - val childRV = holder.binding.childRV - val adapter = childRV.adapter as HomeChildRVAdapter - appProgressViewModel.viewModelScope.launch { - adapter.currentList.forEach { fusedApp -> - if(fusedApp.status == Status.DOWNLOADING) { - val progress = appProgressViewModel.calculateProgress(fusedApp, it) - val downloadProgress = - ((progress.second / progress.first.toDouble()) * 100).toInt() - Log.d("HomeParentAdapter", "download progress of ===> ${fusedApp.name} : $downloadProgress") - val viewHolder = childRV.findViewHolderForAdapterPosition(adapter.currentList.indexOf(fusedApp)) - viewHolder?.let { - (viewHolder as HomeChildRVAdapter.ViewHolder).binding.installButton.text = "$downloadProgress%" - } - } - } - - } - } observeAppInstall(fusedHome, homeChildRVAdapter) } diff --git a/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt b/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt index efeb58da0..b6d983508 100644 --- a/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt +++ b/app/src/main/java/foundation/e/apps/manager/download/data/DownloadProgressLD.kt @@ -1,7 +1,10 @@ package foundation.e.apps.manager.download.data import android.app.DownloadManager +import android.util.Log +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer import foundation.e.apps.manager.fused.FusedManagerRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -20,64 +23,73 @@ class DownloadProgressLD @Inject constructor( private val fusedManagerRepository: FusedManagerRepository ) : LiveData(), CoroutineScope { - private val job = Job() + private lateinit var job: Job private var downloadProgress = DownloadProgress() override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job + override fun observe(owner: LifecycleOwner, observer: Observer) { + job = Job() + super.observe(owner, observer) + } + override fun onActive() { super.onActive() launch { - while (isActive) { val downloads = fusedManagerRepository.getDownloadList() - val downloadingList = downloads.map { it.downloadIdMap }.filter { it.values.contains(false) } + val downloadingList = + downloads.map { it.downloadIdMap }.filter { it.values.contains(false) } val downloadingIds = mutableListOf() downloadingList.forEach { downloadingIds.addAll(it.keys) } if (downloadingIds.isEmpty()) { delay(500) continue } - downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds.toLongArray())) - .use { cursor -> - cursor.moveToFirst() - while (!cursor.isAfterLast) { - val id = - cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)) - val status = - cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) - val totalSizeBytes = - cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) - val bytesDownloadedSoFar = - cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) - - if (!downloadProgress.totalSizeBytes.containsKey(id) || - downloadProgress.totalSizeBytes[id] != totalSizeBytes - ) { - downloadProgress.totalSizeBytes[id] = totalSizeBytes - } + try { + downloadManager.query(downloadManagerQuery.setFilterById(*downloadingIds.toLongArray())) + .use { cursor -> + cursor.moveToFirst() + while (!cursor.isAfterLast) { + val id = + cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID)) + val status = + cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)) + val totalSizeBytes = + cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)) + val bytesDownloadedSoFar = + cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)) - if (!downloadProgress.bytesDownloadedSoFar.containsKey(id) || - downloadProgress.bytesDownloadedSoFar[id] != bytesDownloadedSoFar - ) { - downloadProgress.bytesDownloadedSoFar[id] = bytesDownloadedSoFar - } + if (!downloadProgress.totalSizeBytes.containsKey(id) || + downloadProgress.totalSizeBytes[id] != totalSizeBytes + ) { + downloadProgress.totalSizeBytes[id] = totalSizeBytes + } - downloadProgress.status[id] = - status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED + if (!downloadProgress.bytesDownloadedSoFar.containsKey(id) || + downloadProgress.bytesDownloadedSoFar[id] != bytesDownloadedSoFar + ) { + downloadProgress.bytesDownloadedSoFar[id] = bytesDownloadedSoFar + } - if (downloadingIds.size == cursor.count) { - postValue(downloadProgress) - } + downloadProgress.status[id] = + status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED + + if (downloadingIds.size == cursor.count) { + postValue(downloadProgress) + } - if (downloadingIds.isEmpty()) { - clearDownload() - cancel() + if (downloadingIds.isEmpty()) { + clearDownload() + cancel() + } + cursor.moveToNext() } - cursor.moveToNext() } - } + } catch (e: Exception) { + Log.e(TAG, "downloading Ids: $downloadingIds ${e.localizedMessage}") + } delay(20) } } @@ -89,6 +101,9 @@ class DownloadProgressLD @Inject constructor( } companion object { + + const val TAG = "DownloadProgressLD" + var downloadId = mutableListOf() fun setDownloadId(id: Long) { diff --git a/app/src/main/java/foundation/e/apps/search/SearchFragment.kt b/app/src/main/java/foundation/e/apps/search/SearchFragment.kt index 01f87c1b4..3bd089bce 100644 --- a/app/src/main/java/foundation/e/apps/search/SearchFragment.kt +++ b/app/src/main/java/foundation/e/apps/search/SearchFragment.kt @@ -22,6 +22,7 @@ import android.app.Activity import android.database.MatrixCursor import android.os.Bundle import android.provider.BaseColumns +import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager import android.widget.ImageView @@ -32,6 +33,7 @@ import androidx.cursoradapter.widget.SimpleCursorAdapter import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -46,8 +48,11 @@ import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.applicationlist.model.ApplicationListRVAdapter import foundation.e.apps.databinding.FragmentSearchBinding +import foundation.e.apps.home.model.HomeChildRVAdapter import foundation.e.apps.manager.pkg.PkgManagerModule +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User +import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint @@ -113,8 +118,7 @@ class SearchFragment : it, pkgManagerModule, User.valueOf(mainActivityViewModel.userType.value ?: User.UNAVAILABLE.name), - viewLifecycleOwner, - appProgressViewModel + viewLifecycleOwner ) } @@ -123,6 +127,24 @@ class SearchFragment : layoutManager = LinearLayoutManager(view.context) } + appProgressViewModel.downloadProgress.observe(viewLifecycleOwner) { + val adapter = recyclerView?.adapter as ApplicationListRVAdapter + lifecycleScope.launch { + adapter.currentList.forEach { fusedApp -> + if(fusedApp.status == Status.DOWNLOADING) { + val progress = appProgressViewModel.calculateProgress(fusedApp, it) + val downloadProgress = + ((progress.second / progress.first.toDouble()) * 100).toInt() + Log.d("HomeParentAdapter", "download progress of ===> ${fusedApp.name} : $downloadProgress") + val viewHolder = recyclerView?.findViewHolderForAdapterPosition(adapter.currentList.indexOf(fusedApp)) + viewHolder?.let { + (viewHolder as ApplicationListRVAdapter.ViewHolder).binding.installButton.text = "$downloadProgress%" + } + } + } + } + } + mainActivityViewModel.downloadList.observe(viewLifecycleOwner) { list -> val searchResult = searchViewModel.searchResult.value?.toMutableList() if (!searchResult.isNullOrEmpty()) { diff --git a/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt b/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt index b20e8cfa1..9004f8408 100644 --- a/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt +++ b/app/src/main/java/foundation/e/apps/updates/UpdatesFragment.kt @@ -19,13 +19,16 @@ package foundation.e.apps.updates import android.os.Bundle +import android.util.Log import android.view.View import android.widget.ImageView import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppProgressViewModel import foundation.e.apps.MainActivityViewModel @@ -35,8 +38,12 @@ import foundation.e.apps.api.fused.FusedAPIInterface import foundation.e.apps.api.fused.data.FusedApp import foundation.e.apps.applicationlist.model.ApplicationListRVAdapter import foundation.e.apps.databinding.FragmentUpdatesBinding +import foundation.e.apps.home.model.HomeChildRVAdapter +import foundation.e.apps.manager.download.data.DownloadProgress import foundation.e.apps.manager.pkg.PkgManagerModule +import foundation.e.apps.utils.enums.Status import foundation.e.apps.utils.enums.User +import kotlinx.coroutines.launch import javax.inject.Inject @AndroidEntryPoint @@ -81,7 +88,6 @@ class UpdatesFragment : Fragment(R.layout.fragment_updates), FusedAPIInterface { pkgManagerModule, User.valueOf(mainActivityViewModel.userType.value ?: User.UNAVAILABLE.name), viewLifecycleOwner, - appProgressViewModel ) } @@ -90,6 +96,11 @@ class UpdatesFragment : Fragment(R.layout.fragment_updates), FusedAPIInterface { layoutManager = LinearLayoutManager(view.context) } + appProgressViewModel.downloadProgress.observe(viewLifecycleOwner) { + updateProgressOfDownloadingItems(recyclerView, it) + + } + mainActivityViewModel.downloadList.observe(viewLifecycleOwner) { list -> val updatesList = updatesViewModel.updatesList.value?.toMutableList() if (!updatesList.isNullOrEmpty()) { @@ -116,6 +127,30 @@ class UpdatesFragment : Fragment(R.layout.fragment_updates), FusedAPIInterface { } } + private fun updateProgressOfDownloadingItems( + recyclerView: RecyclerView, + downloadProgress: DownloadProgress + ) { + val adapter = recyclerView.adapter as ApplicationListRVAdapter + lifecycleScope.launch { + adapter.currentList.forEach { fusedApp -> + if (fusedApp.status == Status.DOWNLOADING) { + val progress = + appProgressViewModel.calculateProgress(fusedApp, downloadProgress) + val downloadProgress = + ((progress.second / progress.first.toDouble()) * 100).toInt() + val viewHolder = recyclerView.findViewHolderForAdapterPosition( + adapter.currentList.indexOf(fusedApp) + ) + viewHolder?.let { + (viewHolder as ApplicationListRVAdapter.ViewHolder).binding.installButton.text = + "$downloadProgress%" + } + } + } + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null -- GitLab