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 93210b92de493a9eab40ea30eb37e741b00198a1..b03c208bea288f63c402eb1bbad55b30f1bad57a 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 e1862fbd8aeb016991635bd8eaaafdde92c06cb3..65deacdb8784692ec2d2af212062497f4180dbd1 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 5b910a640ef05a0d3787a706c299c763d26da486..7773a453780a56904e2afa1770c053f79700ed6d 100644 --- a/app/src/main/java/foundation/e/apps/home/HomeFragment.kt +++ b/app/src/main/java/foundation/e/apps/home/HomeFragment.kt @@ -24,8 +24,10 @@ 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 androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.AppProgressViewModel import foundation.e.apps.MainActivityViewModel @@ -33,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 @@ -77,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 { @@ -90,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 bda203ba43b1cedee89bd3ccebc8baa76001621b..194639b5206867dcd602f04ddf4bfe3fd1732d7e 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 @@ -50,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() @@ -63,58 +63,17 @@ 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 onAppear() { - lifecycleRegistry.currentState = Lifecycle.State.RESUMED - } - - fun onDisappear() { - lifecycleRegistry.currentState = Lifecycle.State.DESTROYED - } - - override fun getLifecycle(): Lifecycle { - return lifecycleRegistry - } - } - - 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) - } + RecyclerView.ViewHolder(binding.root) 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 +100,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 +117,6 @@ class HomeChildRVAdapter( } } Status.UPDATABLE -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.apply { text = context.getString(R.string.update) setTextColor(Color.WHITE) @@ -172,7 +130,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 +155,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 +173,6 @@ class HomeChildRVAdapter( } } Status.BLOCKED -> { - appProgressViewModel.downloadProgress.removeObservers(holder) installButton.setOnClickListener { val errorMsg = when (user) { User.ANONYMOUS, @@ -239,7 +185,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 b31b68e606cf723772011831865e7a233940f9fb..0c971d51c52d50e3b77ebda832bd594b8f00cc1c 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 @@ -21,6 +21,7 @@ package foundation.e.apps.home.model 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,15 +33,16 @@ 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, 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() @@ -56,7 +58,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) homeChildRVAdapter.setData(fusedHome.list) holder.binding.titleTV.text = fusedHome.title 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 8fe3a037fcc7e67ae408b3a47b3e383b57236522..b6d98350874cf4548e39fda398d84dfbb5bdc3c9 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 @@ -14,71 +17,79 @@ 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, 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) } } @@ -90,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 01f87c1b480a59a38001ca1eb9a05df5943384d5..3bd089bce1db9e52430bfa625ba620e6dd9af686 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 b20e8cfa1ee90ad0f21f1eea1095770702e3b9fc..9004f840859b27af7a3024e17747c3c46292e182 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