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

Commit 5a6718a6 authored by dev-12's avatar dev-12
Browse files

Merge branch '3943-fix-update-button-status' into 'main'

fix: enable/disable 'update all' button correctly

See merge request !666
parents f0455d48 021ebb76
Loading
Loading
Loading
Loading
Loading
+50 −52
Original line number Diff line number Diff line
@@ -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<Application>?) {
        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 observeJobStates() {
        WorkManager.getInstance(requireContext())
            .getWorkInfosLiveData(WorkQuery.fromStates(WorkInfo.State.entries))
            .observe(viewLifecycleOwner) {
                viewLifecycleOwner.lifecycleScope.launch {
                    repeatOnLifecycle(Lifecycle.State.RESUMED) {
                        updateButtonAvailability()
                    }
                }
            }
    }

    private fun observeAppInstallationWork() {
        WorkManager.getInstance(requireContext())
            .getWorkInfosForUniqueWorkLiveData(INSTALL_WORK_NAME)
            .observe(viewLifecycleOwner) { workInfoList ->
    private fun setButtonEnabled(isEnabled: Boolean) {
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.RESUMED) {
                        binding.button.isEnabled = shouldUpdateButtonEnable(workInfoList)
                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
        }

    private fun shouldUpdateButtonEnable(workInfoList: List<WorkInfo>) =
        updatesViewModel.updatesList.value?.isNotEmpty() == true &&
            (
                workInfoList.isNullOrEmpty() ||
                    (
                        !updatesViewModel.checkWorkInfoListHasAnyUpdatableWork(
                            workInfoList
                        ) &&
                            updatesViewModel.hasAnyUpdatableApp()
                        )
        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
        }
    }

    private fun observeUpdateWork() {
        WorkManager.getInstance(requireContext())
            .getWorkInfosByTagLiveData(UpdatesWorkManager.TAG)
            .observe(viewLifecycleOwner) {
                binding.button.isEnabled = hasAnyPendingUpdates(it)
            updateButtonAvailability()
        }
    }

    private fun hasAnyPendingUpdates(
        workInfoList: List<WorkInfo>
    ): 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