From 021ebb76164e019f768d497f4685d76dbc2a3199 Mon Sep 17 00:00:00 2001 From: dev-12 Date: Thu, 15 Jan 2026 12:53:42 +0530 Subject: [PATCH] fix: enable/disable 'update all' button correctly It wasn't re-enabled when user triggered job failed, because it was listening to background job status. --- .../e/apps/ui/updates/UpdatesFragment.kt | 102 +++++++++--------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt index 1760cd43e..5ebc7c9e2 100644 --- a/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/updates/UpdatesFragment.kt @@ -33,6 +33,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.work.WorkInfo import androidx.work.WorkManager +import androidx.work.WorkQuery import dagger.hilt.android.AndroidEntryPoint import foundation.e.apps.R import foundation.e.apps.data.ResultSupreme @@ -49,7 +50,7 @@ import foundation.e.apps.di.CommonUtilsModule.safeNavigate import foundation.e.apps.install.download.data.DownloadProgress import foundation.e.apps.install.pkg.PwaManager import foundation.e.apps.install.updates.UpdatesWorkManager -import foundation.e.apps.install.workmanager.InstallWorkManager.INSTALL_WORK_NAME +import foundation.e.apps.install.workmanager.InstallWorkManager import foundation.e.apps.ui.AppInfoFetchViewModel import foundation.e.apps.ui.AppProgressViewModel import foundation.e.apps.ui.MainActivityViewModel @@ -63,6 +64,7 @@ import foundation.e.apps.utils.toast import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch +import timber.log.Timber import java.util.Locale import javax.inject.Inject @@ -123,7 +125,7 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI adapter = listAdapter layoutManager = LinearLayoutManager(view.context) } - observeAppInstallationWork() + observeJobStates() observeUpdateList(listAdapter) viewLifecycleOwner.lifecycleScope.launch { @@ -142,7 +144,7 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI listAdapter?.setData(appsToDisplay) if (!isDownloadObserverAdded) { - handleStateNoUpdates(appsUpdateList) + updateButtonAvailability() observeDownloadList() isDownloadObserverAdded = true } @@ -156,40 +158,57 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI } } - private fun handleStateNoUpdates(list: List?) { - if (!list.isNullOrEmpty()) { - binding.button.isEnabled = true - initUpdateAllButton() - binding.noUpdates.visibility = View.GONE - } else { - binding.noUpdates.visibility = View.VISIBLE - binding.button.isEnabled = false - } - } - - private fun observeAppInstallationWork() { + private fun observeJobStates() { WorkManager.getInstance(requireContext()) - .getWorkInfosForUniqueWorkLiveData(INSTALL_WORK_NAME) - .observe(viewLifecycleOwner) { workInfoList -> + .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.entries)) + .observe(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.RESUMED) { - binding.button.isEnabled = shouldUpdateButtonEnable(workInfoList) + updateButtonAvailability() } } } } - private fun shouldUpdateButtonEnable(workInfoList: List) = - updatesViewModel.updatesList.value?.isNotEmpty() == true && - ( - workInfoList.isNullOrEmpty() || - ( - !updatesViewModel.checkWorkInfoListHasAnyUpdatableWork( - workInfoList - ) && - updatesViewModel.hasAnyUpdatableApp() - ) + private fun setButtonEnabled(isEnabled: Boolean) { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + binding.button.isEnabled = isEnabled + } + } + } + + private fun updateButtonAvailability() { + val areUpdatesAvailable = updatesViewModel.hasAnyUpdatableApp() + if (!areUpdatesAvailable) { + setButtonEnabled(false) + Timber.d("update are not available disabling update all button") + return + } + val alreadyUpdating = updatesViewModel.hasAnyPendingAppsForUpdate() + if (alreadyUpdating) { + Timber.d("update are in progress disabling update all button") + setButtonEnabled(false) + return + } + + val noUpdateJobIsRunning = WorkManager.getInstance(requireContext()) + .getWorkInfos( + WorkQuery.fromTags( + UpdatesWorkManager.TAG, + UpdatesWorkManager.USER_TAG ) + ).get() + .none { it.state == WorkInfo.State.RUNNING } + val noInstallJobIsRunning = WorkManager.getInstance(requireContext()) + .getWorkInfosForUniqueWork(InstallWorkManager.INSTALL_WORK_NAME) + .get() + .none { listOf(WorkInfo.State.ENQUEUED, WorkInfo.State.RUNNING).contains(it.state) } + + Timber.d("no update jobs are running : $noUpdateJobIsRunning") + Timber.d("no install jobs are running : $noInstallJobIsRunning") + setButtonEnabled(noUpdateJobIsRunning && noInstallJobIsRunning) + } private fun handleUpdateEvent(appEvent: AppEvent) { val event = appEvent.data as ResultSupreme.WorkError<*> @@ -280,40 +299,19 @@ class UpdatesFragment : TimeoutFragment(R.layout.fragment_updates), ApplicationI showLoadingUI() updatesViewModel.loadUpdates() initUpdateAllButton() + updateButtonAvailability() } } private fun initUpdateAllButton() { binding.button.setOnClickListener { UpdatesWorkManager.startUpdateAllWork(requireContext()) - observeUpdateWork() - binding.button.isEnabled = false + updateButtonAvailability() } } - private fun observeUpdateWork() { - WorkManager.getInstance(requireContext()) - .getWorkInfosByTagLiveData(UpdatesWorkManager.TAG) - .observe(viewLifecycleOwner) { - binding.button.isEnabled = hasAnyPendingUpdates(it) - } - } - - private fun hasAnyPendingUpdates( - workInfoList: List - ): Boolean { - val errorStates = listOf( - WorkInfo.State.FAILED, - WorkInfo.State.BLOCKED, - WorkInfo.State.CANCELLED, - WorkInfo.State.SUCCEEDED - ) - return !workInfoList.isNullOrEmpty() && errorStates.contains(workInfoList.last().state) && - updatesViewModel.hasAnyUpdatableApp() && !updatesViewModel.hasAnyPendingAppsForUpdate() - } - override fun showLoadingUI() { - binding.button.isEnabled = false + updateButtonAvailability() binding.noUpdates.visibility = View.GONE binding.progressBar.visibility = View.VISIBLE binding.recyclerView.visibility = View.INVISIBLE -- GitLab