diff --git a/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromContentUriWorker.kt b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromContentUriWorker.kt
index bee2f350d..ffe443605 100644
--- a/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromContentUriWorker.kt
+++ b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromContentUriWorker.kt
@@ -380,7 +380,7 @@ class UploadFileFromContentUriWorker(
}
if (totalSize <= 0) return
- val percent: Int = (100.0 * offset.toDouble() / totalSize.toDouble()).toInt()
+ val percent: Int = UploadProgressCalculator.percent(offset, totalSize)
if (percent == lastPercent) return
CoroutineScope(Dispatchers.IO).launch {
@@ -479,7 +479,7 @@ class UploadFileFromContentUriWorker(
}
}
- val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt()
+ val percent: Int = UploadProgressCalculator.percent(totalTransferredSoFar, totalToTransfer)
if (percent == lastPercent) return
// Set current progress. Observers will listen.
diff --git a/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromFileSystemWorker.kt b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromFileSystemWorker.kt
index 91296f842..6c01a1567 100644
--- a/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromFileSystemWorker.kt
+++ b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadFileFromFileSystemWorker.kt
@@ -347,7 +347,7 @@ class UploadFileFromFileSystemWorker(
}
if (totalSize <= 0) return
- val percent: Int = (100.0 * offset.toDouble() / totalSize.toDouble()).toInt()
+ val percent: Int = UploadProgressCalculator.percent(offset, totalSize)
if (percent == lastPercent) return
CoroutineScope(Dispatchers.IO).launch {
@@ -480,7 +480,7 @@ class UploadFileFromFileSystemWorker(
}
}
- val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt()
+ val percent: Int = UploadProgressCalculator.percent(totalTransferredSoFar, totalToTransfer)
if (percent == lastPercent) return
// Set current progress. Observers will listen.
diff --git a/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadProgressCalculator.kt b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadProgressCalculator.kt
new file mode 100644
index 000000000..06229862d
--- /dev/null
+++ b/opencloudApp/src/main/java/eu/opencloud/android/workers/UploadProgressCalculator.kt
@@ -0,0 +1,27 @@
+/**
+ * openCloud Android client application
+ *
+ * Copyright (C) 2026 OpenCloud GmbH.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package eu.opencloud.android.workers
+
+internal object UploadProgressCalculator {
+ fun percent(transferred: Long, total: Long): Int =
+ if (total <= 0L || transferred <= 0L) {
+ 0
+ } else {
+ (100.0 * transferred.toDouble() / total.toDouble()).toInt().coerceIn(0, 100)
+ }
+}
diff --git a/opencloudApp/src/test/java/eu/opencloud/android/workers/UploadProgressCalculatorTest.kt b/opencloudApp/src/test/java/eu/opencloud/android/workers/UploadProgressCalculatorTest.kt
new file mode 100644
index 000000000..afeaa75d9
--- /dev/null
+++ b/opencloudApp/src/test/java/eu/opencloud/android/workers/UploadProgressCalculatorTest.kt
@@ -0,0 +1,45 @@
+/**
+ * openCloud Android client application
+ *
+ * Copyright (C) 2026 OpenCloud GmbH.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package eu.opencloud.android.workers
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class UploadProgressCalculatorTest {
+ @Test
+ fun `percent returns zero when total is unknown or zero`() {
+ assertEquals(0, UploadProgressCalculator.percent(transferred = 25, total = -1))
+ assertEquals(0, UploadProgressCalculator.percent(transferred = 25, total = 0))
+ }
+
+ @Test
+ fun `percent returns zero when transferred is zero or negative`() {
+ assertEquals(0, UploadProgressCalculator.percent(transferred = 0, total = 100))
+ assertEquals(0, UploadProgressCalculator.percent(transferred = -1, total = 100))
+ }
+
+ @Test
+ fun `percent calculates normal progress`() {
+ assertEquals(25, UploadProgressCalculator.percent(transferred = 25, total = 100))
+ }
+
+ @Test
+ fun `percent clamps over complete progress`() {
+ assertEquals(100, UploadProgressCalculator.percent(transferred = 125, total = 100))
+ }
+}