From fc7727cf85616bfbd28636bd4b3d767ce113e5ec Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 18 May 2026 09:59:20 -0300 Subject: [PATCH] Add a button to clear all installing apps, if they are not progressing anymore --- .../org/fdroid/install/AppInstallManager.kt | 17 +++++++++++ .../kotlin/org/fdroid/ui/apps/MyAppsInfo.kt | 6 +++- .../kotlin/org/fdroid/ui/apps/MyAppsList.kt | 28 +++++++++++++++---- .../org/fdroid/ui/apps/MyAppsViewModel.kt | 6 ++++ .../org/fdroid/ui/utils/PreviewUtils.kt | 2 ++ app/src/main/res/values/strings.xml | 1 + .../kotlin/org/fdroid/ui/apps/MyAppsTest.kt | 8 +++++- .../MyAppsInstalledAndIssues_2ed8e27d_0.png | 4 +-- 8 files changed, 62 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/org/fdroid/install/AppInstallManager.kt b/app/src/main/kotlin/org/fdroid/install/AppInstallManager.kt index 96aae5f43..120cb7473 100644 --- a/app/src/main/kotlin/org/fdroid/install/AppInstallManager.kt +++ b/app/src/main/kotlin/org/fdroid/install/AppInstallManager.kt @@ -488,6 +488,23 @@ constructor( return result } + @UiThread + fun clearInstallingApps() { + apps.update { oldApps -> + oldApps.toMutableMap().apply { + val iterator = entries.iterator() + while (iterator.hasNext()) { + val app = iterator.next() + if (!app.value.showProgress) { + val packageName = app.key + jobs.remove(packageName)?.cancel() + iterator.remove() + } + } + } + } + } + @UiThread fun cleanUp(packageName: String) { val state = apps.value[packageName] ?: return diff --git a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsInfo.kt b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsInfo.kt index b9b9759f3..9e5fddefd 100644 --- a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsInfo.kt +++ b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsInfo.kt @@ -21,7 +21,9 @@ data class MyAppsModel( val networkState: NetworkState, val isSearching: Boolean = false, val appUpdatesBytes: Long? = null, -) +) { + val showClearInstallingAppsButton: Boolean = installingApps.all { !it.installState.showProgress } +} interface MyAppsActions { fun updateAll() @@ -32,6 +34,8 @@ interface MyAppsActions { fun confirmAppInstall(packageName: String, state: InstallConfirmationState) + fun clearInstallingApps() + fun ignoreAppIssue(item: AppWithIssueItem) fun onUpdatesHintSeen() diff --git a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsList.kt b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsList.kt index b4c259650..41459cf30 100644 --- a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsList.kt +++ b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsList.kt @@ -34,6 +34,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.fdroid.R import org.fdroid.database.NotAvailable +import org.fdroid.install.InstallState import org.fdroid.ui.FDroidContent import org.fdroid.ui.utils.MeteredConnectionDialog import org.fdroid.ui.utils.OfflineBar @@ -139,11 +140,21 @@ fun MyAppsList( // Apps currently installing header if (installingApps.isNotEmpty()) { item(key = "B", contentType = "header") { - Text( - text = stringResource(R.string.notification_title_summary_installing), - style = MaterialTheme.typography.titleMedium, - modifier = Modifier.padding(16.dp), - ) + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(R.string.notification_title_summary_installing), + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(16.dp).weight(1f), + ) + if (myAppsInfo.model.showClearInstallingAppsButton) { + TextButton( + onClick = myAppsInfo.actions::clearInstallingApps, + modifier = Modifier.padding(end = 16.dp), + ) { + Text(stringResource(R.string.clear_all)) + } + } + } } // List of currently installing apps items(items = installingApps, key = { it.packageName }, contentType = { "B" }) { app -> @@ -288,7 +299,12 @@ private fun Preview() { getMyAppsInfo( myAppsModel.copy( appUpdates = emptyList(), - installingApps = emptyList(), + installingApps = + listOf( + myAppsModel.installingApps[0].copy( + installState = InstallState.Installed("Installed App", "0.5.2", null, 1337L, null) + ) + ), appsWithIssue = emptyList(), ) ), diff --git a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsViewModel.kt b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsViewModel.kt index 53509b0df..4ce3ced17 100644 --- a/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsViewModel.kt +++ b/app/src/main/kotlin/org/fdroid/ui/apps/MyAppsViewModel.kt @@ -3,6 +3,7 @@ package org.fdroid.ui.apps import android.app.Application import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import androidx.annotation.UiThread import androidx.core.app.ShareCompat import androidx.core.os.LocaleListCompat import androidx.lifecycle.AndroidViewModel @@ -135,6 +136,11 @@ constructor( } } + @UiThread + override fun clearInstallingApps() { + appInstallManager.clearInstallingApps() + } + override fun ignoreAppIssue(item: AppWithIssueItem) { settingsManager.ignoreAppIssue(item.packageName, item.installedVersionCode) updatesManager.loadUpdates() diff --git a/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt b/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt index a1671baea..12623b5e0 100644 --- a/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt +++ b/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt @@ -415,6 +415,8 @@ fun getMyAppsInfo(model: MyAppsModel): MyAppsInfo = override fun confirmAppInstall(packageName: String, state: InstallConfirmationState) {} + override fun clearInstallingApps() {} + override fun ignoreAppIssue(item: AppWithIssueItem) {} override fun onUpdatesHintSeen() {} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d97d5379b..889dcd6d5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,7 @@ Use filters to only show apps from specific categories or repositories. You can also change the sort order. Got it Clear + Clear all Hide Calendars, tasks, clocks & notes diff --git a/app/src/screenshotTest/kotlin/org/fdroid/ui/apps/MyAppsTest.kt b/app/src/screenshotTest/kotlin/org/fdroid/ui/apps/MyAppsTest.kt index 42f08c6ec..13d739b26 100644 --- a/app/src/screenshotTest/kotlin/org/fdroid/ui/apps/MyAppsTest.kt +++ b/app/src/screenshotTest/kotlin/org/fdroid/ui/apps/MyAppsTest.kt @@ -10,6 +10,7 @@ import org.fdroid.install.InstallState import org.fdroid.ui.ScreenshotTest import org.fdroid.ui.utils.getMyAppsInfo import org.fdroid.ui.utils.getPreviewVersion +import org.fdroid.ui.utils.myAppsModel @Composable @PreviewTest @@ -69,7 +70,12 @@ fun MyAppsInstalledAndIssues() { val model = MyAppsModel( appUpdates = emptyList(), - installingApps = emptyList(), + installingApps = + listOf( + myAppsModel.installingApps[0].copy( + installState = InstallState.Installed("Installed App", "0.5.2", null, 1337L, null) + ) + ), appsWithIssue = getAppIssues(), installedApps = getInstalledApps(), showUpdatesHint = false, diff --git a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/apps/MyAppsTestKt/MyAppsInstalledAndIssues_2ed8e27d_0.png b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/apps/MyAppsTestKt/MyAppsInstalledAndIssues_2ed8e27d_0.png index 95c8a682c..f09001233 100644 --- a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/apps/MyAppsTestKt/MyAppsInstalledAndIssues_2ed8e27d_0.png +++ b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/apps/MyAppsTestKt/MyAppsInstalledAndIssues_2ed8e27d_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e8e34dc95d9b2b264fafa4bcf601936dfcb707d11abe3cc05000ae5d0bd0d14 -size 114468 +oid sha256:fbc5717f991caad84edea313031b33dfced41af8ed779112d44ec5bbf5acd8cc +size 130690