Sfoglia il codice sorgente

Merge pull request #12907 from nextcloud/feature/unify-notifications

Unify Notifications
Alper Öztürk 1 anno fa
parent
commit
9c00c616c8
29 ha cambiato i file con 329 aggiunte e 321 eliminazioni
  1. 25 82
      app/src/main/java/com/nextcloud/client/jobs/download/DownloadNotificationManager.kt
  2. 19 15
      app/src/main/java/com/nextcloud/client/jobs/download/FileDownloadWorker.kt
  3. 76 0
      app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt
  4. 62 45
      app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt
  5. 41 59
      app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt
  6. 96 74
      app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java
  7. 2 2
      app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java
  8. 0 2
      app/src/main/res/values-ar/strings.xml
  9. 0 2
      app/src/main/res/values-b+en+001/strings.xml
  10. 0 2
      app/src/main/res/values-cs-rCZ/strings.xml
  11. 0 2
      app/src/main/res/values-de/strings.xml
  12. 0 2
      app/src/main/res/values-es-rMX/strings.xml
  13. 0 2
      app/src/main/res/values-es/strings.xml
  14. 0 2
      app/src/main/res/values-eu/strings.xml
  15. 0 2
      app/src/main/res/values-fa/strings.xml
  16. 0 2
      app/src/main/res/values-fr/strings.xml
  17. 0 2
      app/src/main/res/values-it/strings.xml
  18. 0 2
      app/src/main/res/values-nb-rNO/strings.xml
  19. 0 2
      app/src/main/res/values-nl/strings.xml
  20. 0 2
      app/src/main/res/values-pt-rBR/strings.xml
  21. 0 2
      app/src/main/res/values-ru/strings.xml
  22. 0 2
      app/src/main/res/values-sk-rSK/strings.xml
  23. 0 2
      app/src/main/res/values-sr/strings.xml
  24. 0 2
      app/src/main/res/values-sv/strings.xml
  25. 0 2
      app/src/main/res/values-tr/strings.xml
  26. 0 2
      app/src/main/res/values-zh-rCN/strings.xml
  27. 0 2
      app/src/main/res/values-zh-rHK/strings.xml
  28. 0 2
      app/src/main/res/values-zh-rTW/strings.xml
  29. 8 2
      app/src/main/res/values/strings.xml

+ 25 - 82
app/src/main/java/com/nextcloud/client/jobs/download/DownloadNotificationManager.kt

@@ -7,71 +7,43 @@
  */
 package com.nextcloud.client.jobs.download
 
-import android.app.Notification
-import android.app.NotificationManager
 import android.app.PendingIntent
 import android.content.Context
 import android.content.Intent
-import android.graphics.BitmapFactory
-import android.os.Build
-import android.os.Handler
-import android.os.Looper
-import androidx.core.app.NotificationCompat
+import com.nextcloud.client.jobs.notification.WorkerNotificationManager
 import com.owncloud.android.R
-import com.owncloud.android.lib.resources.files.FileUtils
 import com.owncloud.android.operations.DownloadFileOperation
-import com.owncloud.android.ui.notifications.NotificationUtils
 import com.owncloud.android.utils.theme.ViewThemeUtils
 import java.io.File
 import java.security.SecureRandom
 
 @Suppress("TooManyFunctions")
 class DownloadNotificationManager(
-    private val id: Int,
+    id: Int,
     private val context: Context,
-    private val viewThemeUtils: ViewThemeUtils
-) {
-    private var notification: Notification
-    private var notificationBuilder: NotificationCompat.Builder
-    private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
-    init {
-        notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
-            setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker))
-            setTicker(context.getString(R.string.downloader_download_in_progress_ticker))
-            setSmallIcon(R.drawable.notification_icon)
-            setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
-
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD)
-            }
-        }
-
-        notification = notificationBuilder.build()
-    }
+    viewThemeUtils: ViewThemeUtils
+) : WorkerNotificationManager(id, context, viewThemeUtils, R.string.downloader_download_in_progress_ticker) {
 
     @Suppress("MagicNumber")
-    fun prepareForStart(operation: DownloadFileOperation) {
-        notificationBuilder = NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
-            setSmallIcon(R.drawable.notification_icon)
-            setOngoing(true)
-            setProgress(100, 0, operation.size < 0)
-            setContentText(
-                String.format(
-                    context.getString(R.string.downloader_download_in_progress), 0,
-                    File(operation.savePath).name
-                )
+    fun prepareForStart(operation: DownloadFileOperation, currentDownloadIndex: Int, totalDownloadSize: Int) {
+        currentOperationTitle = if (totalDownloadSize > 1) {
+            String.format(
+                context.getString(R.string.downloader_notification_manager_download_text),
+                currentDownloadIndex,
+                totalDownloadSize,
+                File(operation.savePath).name
             )
+        } else {
+            File(operation.savePath).name
+        }
 
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD)
-            }
-
-            notificationManager.notify(
-                id,
-                this.build()
-            )
+        notificationBuilder.run {
+            setContentTitle(currentOperationTitle)
+            setOngoing(false)
+            setProgress(100, 0, operation.size < 0)
         }
+
+        showNotification()
     }
 
     fun prepareForResult() {
@@ -82,23 +54,14 @@ class DownloadNotificationManager(
     }
 
     @Suppress("MagicNumber")
-    fun updateDownloadProgress(filePath: String, percent: Int, totalToTransfer: Long) {
-        notificationBuilder.run {
-            setProgress(100, percent, totalToTransfer < 0)
-            val fileName: String = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1)
-            val text =
-                String.format(context.getString(R.string.downloader_download_in_progress), percent, fileName)
-            val title =
-                context.getString(R.string.downloader_download_in_progress_ticker)
-            updateNotificationText(title, text)
-        }
+    fun updateDownloadProgress(percent: Int, totalToTransfer: Long) {
+        setProgress(percent, R.string.downloader_notification_manager_in_progress_text, totalToTransfer < 0)
+        showNotification()
     }
 
     @Suppress("MagicNumber")
     fun dismissNotification() {
-        Handler(Looper.getMainLooper()).postDelayed({
-            notificationManager.cancel(id)
-        }, 2000)
+        dismissNotification(2000)
     }
 
     fun showNewNotification(text: String) {
@@ -106,24 +69,12 @@ class DownloadNotificationManager(
 
         notificationBuilder.run {
             setProgress(0, 0, false)
-            setContentTitle(null)
-            setContentText(text)
+            setContentTitle(text)
             setOngoing(false)
             notificationManager.notify(notifyId, this.build())
         }
     }
 
-    private fun updateNotificationText(title: String?, text: String) {
-        notificationBuilder.run {
-            title?.let {
-                setContentTitle(title)
-            }
-
-            setContentText(text)
-            notificationManager.notify(id, this.build())
-        }
-    }
-
     fun setContentIntent(intent: Intent, flag: Int) {
         notificationBuilder.setContentIntent(
             PendingIntent.getActivity(
@@ -134,12 +85,4 @@ class DownloadNotificationManager(
             )
         )
     }
-
-    fun getId(): Int {
-        return id
-    }
-
-    fun getNotification(): Notification {
-        return notificationBuilder.build()
-    }
 }

+ 19 - 15
app/src/main/java/com/nextcloud/client/jobs/download/FileDownloadWorker.kt

@@ -126,8 +126,8 @@ class FileDownloadWorker(
             )
             setForegroundAsync(foregroundInfo)
 
-            requestDownloads.forEach {
-                downloadFile(it)
+            requestDownloads.forEachIndexed { currentDownloadIndex, requestedDownload ->
+                downloadFile(requestedDownload, currentDownloadIndex, requestDownloads.size)
             }
 
             downloadError?.let {
@@ -254,7 +254,7 @@ class FileDownloadWorker(
     }
 
     @Suppress("TooGenericExceptionCaught", "DEPRECATION")
-    private fun downloadFile(downloadKey: String) {
+    private fun downloadFile(downloadKey: String, currentDownloadIndex: Int, totalDownloadSize: Int) {
         currentDownload = pendingDownloads.get(downloadKey)
 
         if (currentDownload == null) {
@@ -270,7 +270,13 @@ class FileDownloadWorker(
             return
         }
 
-        notifyDownloadStart(currentDownload!!)
+        lastPercent = 0
+
+        notificationManager.run {
+            prepareForStart(currentDownload!!, currentDownloadIndex + 1, totalDownloadSize)
+            setContentIntent(intents.detailsIntent(currentDownload!!), PendingIntent.FLAG_IMMUTABLE)
+        }
+
         var downloadResult: RemoteOperationResult<*>? = null
         try {
             val ocAccount = getOCAccountForDownload()
@@ -291,15 +297,6 @@ class FileDownloadWorker(
         }
     }
 
-    private fun notifyDownloadStart(download: DownloadFileOperation) {
-        lastPercent = 0
-
-        notificationManager.run {
-            prepareForStart(download)
-            setContentIntent(intents.detailsIntent(download), PendingIntent.FLAG_IMMUTABLE)
-        }
-    }
-
     @Suppress("DEPRECATION")
     private fun getOCAccountForDownload(): OwnCloudAccount {
         val currentDownloadAccount = currentDownload?.user?.toPlatformAccount()
@@ -369,6 +366,7 @@ class FileDownloadWorker(
             FileDownloadError.Cancelled -> {
                 context.getString(R.string.downloader_file_download_cancelled)
             }
+
             FileDownloadError.Failed -> {
                 context.getString(R.string.downloader_file_download_failed)
             }
@@ -408,6 +406,10 @@ class FileDownloadWorker(
         }
     }
 
+    @Suppress("MagicNumber")
+    private val minProgressUpdateInterval = 750
+    private var lastUpdateTime = 0L
+
     @Suppress("MagicNumber")
     override fun onTransferProgress(
         progressRate: Long,
@@ -416,11 +418,13 @@ class FileDownloadWorker(
         filePath: String
     ) {
         val percent: Int = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt()
+        val currentTime = System.currentTimeMillis()
 
-        if (percent != lastPercent) {
+        if (percent != lastPercent && (currentTime - lastUpdateTime) >= minProgressUpdateInterval) {
             notificationManager.run {
-                updateDownloadProgress(filePath, percent, totalToTransfer)
+                updateDownloadProgress(percent, totalToTransfer)
             }
+            lastUpdateTime = currentTime
         }
 
         lastPercent = percent

+ 76 - 0
app/src/main/java/com/nextcloud/client/jobs/notification/WorkerNotificationManager.kt

@@ -0,0 +1,76 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+package com.nextcloud.client.jobs.notification
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.os.Build
+import android.os.Handler
+import android.os.Looper
+import androidx.core.app.NotificationCompat
+import com.owncloud.android.R
+import com.owncloud.android.ui.notifications.NotificationUtils
+import com.owncloud.android.utils.theme.ViewThemeUtils
+
+open class WorkerNotificationManager(
+    private val id: Int,
+    private val context: Context,
+    viewThemeUtils: ViewThemeUtils,
+    private val tickerId: Int
+) {
+    var currentOperationTitle: String? = null
+
+    val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+    var notificationBuilder: NotificationCompat.Builder =
+        NotificationUtils.newNotificationBuilder(context, "WorkerNotificationManager", viewThemeUtils).apply {
+            setTicker(context.getString(tickerId))
+            setSmallIcon(R.drawable.notification_icon)
+            setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
+            setStyle(NotificationCompat.BigTextStyle())
+            setPriority(NotificationCompat.PRIORITY_LOW)
+
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD)
+            }
+        }
+
+    fun showNotification() {
+        notificationManager.notify(id, notificationBuilder.build())
+    }
+
+    @Suppress("MagicNumber")
+    fun setProgress(percent: Int, progressTextId: Int, indeterminate: Boolean) {
+        val progressText = String.format(
+            context.getString(progressTextId),
+            percent
+        )
+
+        notificationBuilder.run {
+            setProgress(100, percent, indeterminate)
+            setContentTitle(currentOperationTitle)
+            setContentText(progressText)
+        }
+    }
+
+    fun dismissNotification(delay: Long = 0) {
+        Handler(Looper.getMainLooper()).postDelayed({
+            notificationManager.cancel(id)
+        }, delay)
+    }
+
+    fun getId(): Int {
+        return id
+    }
+
+    fun getNotification(): Notification {
+        return notificationBuilder.build()
+    }
+}

+ 62 - 45
app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt

@@ -56,7 +56,6 @@ class FileUploadWorker(
         val TAG: String = FileUploadWorker::class.java.simpleName
 
         const val NOTIFICATION_ERROR_ID: Int = 413
-        private const val MAX_PROGRESS: Int = 100
         const val ACCOUNT = "data_account"
         var currentUploadFileOperation: UploadFileOperation? = null
 
@@ -101,9 +100,10 @@ class FileUploadWorker(
             backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class))
             val result = retrievePagesBySortingUploadsByID()
             backgroundJobManager.logEndOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class), result)
+            notificationManager.dismissNotification()
             result
         } catch (t: Throwable) {
-            Log_OC.e(TAG, "Error caught at FileUploadWorker " + t.localizedMessage)
+            Log_OC.e(TAG, "Error caught at FileUploadWorker $t")
             Result.failure()
         }
     }
@@ -113,7 +113,7 @@ class FileUploadWorker(
 
         setIdleWorkerState()
         currentUploadFileOperation?.cancel(null)
-        notificationManager.dismissWorkerNotifications()
+        notificationManager.dismissNotification()
 
         super.onStopped()
     }
@@ -129,11 +129,12 @@ class FileUploadWorker(
     @Suppress("ReturnCount")
     private fun retrievePagesBySortingUploadsByID(): Result {
         val accountName = inputData.getString(ACCOUNT) ?: return Result.failure()
-        var currentPage = uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(-1, accountName)
+        var uploadsPerPage = uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(-1, accountName)
+        val totalUploadSize = uploadsStorageManager.getTotalUploadSize(accountName)
 
-        notificationManager.dismissWorkerNotifications()
+        Log_OC.d(TAG, "Total upload size: $totalUploadSize")
 
-        while (currentPage.isNotEmpty() && !isStopped) {
+        while (uploadsPerPage.isNotEmpty() && !isStopped) {
             if (preferences.isGlobalUploadPaused) {
                 Log_OC.d(TAG, "Upload is paused, skip uploading files!")
                 notificationManager.notifyPaused(
@@ -142,10 +143,10 @@ class FileUploadWorker(
                 return Result.success()
             }
 
-            Log_OC.d(TAG, "Handling ${currentPage.size} uploads for account $accountName")
-            val lastId = currentPage.last().uploadId
-            uploadFiles(currentPage, accountName)
-            currentPage =
+            Log_OC.d(TAG, "Handling ${uploadsPerPage.size} uploads for account $accountName")
+            val lastId = uploadsPerPage.last().uploadId
+            uploadFiles(totalUploadSize, uploadsPerPage, accountName)
+            uploadsPerPage =
                 uploadsStorageManager.getCurrentAndPendingUploadsForAccountPageAscById(lastId, accountName)
         }
 
@@ -157,31 +158,43 @@ class FileUploadWorker(
         return Result.success()
     }
 
-    private fun uploadFiles(uploads: List<OCUpload>, accountName: String) {
+    private fun uploadFiles(totalUploadSize: Int, uploadsPerPage: List<OCUpload>, accountName: String) {
         val user = userAccountManager.getUser(accountName)
-        setWorkerState(user.get(), uploads)
+        setWorkerState(user.get(), uploadsPerPage)
 
-        for (upload in uploads) {
-            if (isStopped) {
-                break
-            }
+        run uploads@{
+            uploadsPerPage.forEachIndexed { currentUploadIndex, upload ->
+                if (isStopped) {
+                    return@uploads
+                }
 
-            if (user.isPresent) {
-                val uploadFileOperation = createUploadFileOperation(upload, user.get())
+                if (user.isPresent) {
+                    val uploadFileOperation = createUploadFileOperation(upload, user.get())
 
-                currentUploadFileOperation = uploadFileOperation
-                val result = upload(uploadFileOperation, user.get())
-                currentUploadFileOperation = null
+                    currentUploadFileOperation = uploadFileOperation
 
-                fileUploaderDelegate.sendBroadcastUploadFinished(
-                    uploadFileOperation,
-                    result,
-                    uploadFileOperation.oldFile?.storagePath,
-                    context,
-                    localBroadcastManager
-                )
-            } else {
-                uploadsStorageManager.removeUpload(upload.uploadId)
+                    notificationManager.prepareForStart(
+                        uploadFileOperation,
+                        cancelPendingIntent = intents.startIntent(uploadFileOperation),
+                        startIntent = intents.notificationStartIntent(uploadFileOperation),
+                        currentUploadIndex = currentUploadIndex + 1,
+                        totalUploadSize = totalUploadSize
+                    )
+
+                    val result = upload(uploadFileOperation, user.get())
+
+                    currentUploadFileOperation = null
+
+                    fileUploaderDelegate.sendBroadcastUploadFinished(
+                        uploadFileOperation,
+                        result,
+                        uploadFileOperation.oldFile?.storagePath,
+                        context,
+                        localBroadcastManager
+                    )
+                } else {
+                    uploadsStorageManager.removeUpload(upload.uploadId)
+                }
             }
         }
     }
@@ -210,12 +223,6 @@ class FileUploadWorker(
     private fun upload(uploadFileOperation: UploadFileOperation, user: User): RemoteOperationResult<Any?> {
         lateinit var result: RemoteOperationResult<Any?>
 
-        notificationManager.prepareForStart(
-            uploadFileOperation,
-            cancelPendingIntent = intents.startIntent(uploadFileOperation),
-            intents.notificationStartIntent(uploadFileOperation)
-        )
-
         try {
             val storageManager = uploadFileOperation.storageManager
             val ocAccount = OwnCloudAccount(user.toPlatformAccount(), context)
@@ -240,7 +247,6 @@ class FileUploadWorker(
         if (!isStopped || !result.isCancelled) {
             uploadsStorageManager.updateDatabaseUploadResult(result, uploadFileOperation)
             notifyUploadResult(uploadFileOperation, result)
-            notificationManager.dismissWorkerNotifications()
         }
     }
 
@@ -303,31 +309,41 @@ class FileUploadWorker(
                 null
             }
 
-            notifyForFailedResult(uploadResult.code, conflictResolveIntent, credentialIntent, errorMessage)
-            showNewNotification(uploadFileOperation)
+            notifyForFailedResult(
+                uploadFileOperation,
+                uploadResult.code,
+                conflictResolveIntent,
+                credentialIntent,
+                errorMessage
+            )
         }
     }
 
+    @Suppress("MagicNumber")
+    private val minProgressUpdateInterval = 750
+    private var lastUpdateTime = 0L
+
+    @Suppress("MagicNumber")
     override fun onTransferProgress(
         progressRate: Long,
         totalTransferredSoFar: Long,
         totalToTransfer: Long,
         fileAbsoluteName: String
     ) {
-        val percent = (MAX_PROGRESS * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt()
+        val percent = (100.0 * totalTransferredSoFar.toDouble() / totalToTransfer.toDouble()).toInt()
+        val currentTime = System.currentTimeMillis()
 
-        if (percent != lastPercent) {
+        if (percent != lastPercent && (currentTime - lastUpdateTime) >= minProgressUpdateInterval) {
             notificationManager.run {
                 val accountName = currentUploadFileOperation?.user?.accountName
                 val remotePath = currentUploadFileOperation?.remotePath
-                val filename = currentUploadFileOperation?.fileName ?: ""
 
-                updateUploadProgress(filename, percent, currentUploadFileOperation)
+                updateUploadProgress(percent, currentUploadFileOperation)
 
                 if (accountName != null && remotePath != null) {
-                    val key: String =
-                        FileUploadHelper.buildRemoteName(accountName, remotePath)
+                    val key: String = FileUploadHelper.buildRemoteName(accountName, remotePath)
                     val boundListener = FileUploadHelper.mBoundListeners[key]
+                    val filename = currentUploadFileOperation?.fileName ?: ""
 
                     boundListener?.onTransferProgress(
                         progressRate,
@@ -339,6 +355,7 @@ class FileUploadWorker(
 
                 dismissOldErrorNotification(currentUploadFileOperation)
             }
+            lastUpdateTime = currentTime
         }
 
         lastPercent = percent

+ 41 - 59
app/src/main/java/com/nextcloud/client/jobs/upload/UploadNotificationManager.kt

@@ -7,59 +7,51 @@
  */
 package com.nextcloud.client.jobs.upload
 
-import android.app.Notification
-import android.app.NotificationManager
 import android.app.PendingIntent
 import android.content.Context
-import android.graphics.BitmapFactory
-import android.os.Build
-import androidx.core.app.NotificationCompat
+import com.nextcloud.client.jobs.notification.WorkerNotificationManager
 import com.owncloud.android.R
 import com.owncloud.android.lib.common.operations.RemoteOperationResult
 import com.owncloud.android.operations.UploadFileOperation
 import com.owncloud.android.ui.notifications.NotificationUtils
 import com.owncloud.android.utils.theme.ViewThemeUtils
 
-class UploadNotificationManager(private val context: Context, viewThemeUtils: ViewThemeUtils) {
+class UploadNotificationManager(private val context: Context, viewThemeUtils: ViewThemeUtils) :
+    WorkerNotificationManager(ID, context, viewThemeUtils, R.string.foreground_service_upload) {
+
     companion object {
         private const val ID = 411
     }
 
-    private var notification: Notification? = null
-    private var notificationBuilder: NotificationCompat.Builder =
-        NotificationUtils.newNotificationBuilder(context, viewThemeUtils).apply {
-            setContentTitle(context.getString(R.string.foreground_service_upload))
-            setSmallIcon(R.drawable.notification_icon)
-            setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon))
-
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
-            }
-        }
-    private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
-    init {
-        notification = notificationBuilder.build()
-    }
-
     @Suppress("MagicNumber")
     fun prepareForStart(
         uploadFileOperation: UploadFileOperation,
         cancelPendingIntent: PendingIntent,
-        startIntent: PendingIntent
+        startIntent: PendingIntent,
+        currentUploadIndex: Int,
+        totalUploadSize: Int
     ) {
-        notificationBuilder.run {
-            setContentTitle(context.getString(R.string.uploader_upload_in_progress_ticker))
-            setContentText(
-                String.format(
-                    context.getString(R.string.uploader_upload_in_progress),
-                    0,
-                    uploadFileOperation.fileName
-                )
+        currentOperationTitle = if (totalUploadSize > 1) {
+            String.format(
+                context.getString(R.string.upload_notification_manager_start_text),
+                currentUploadIndex,
+                totalUploadSize,
+                uploadFileOperation.fileName
             )
-            setTicker(context.getString(R.string.foreground_service_upload))
+        } else {
+            uploadFileOperation.fileName
+        }
+
+        val progressText = String.format(
+            context.getString(R.string.upload_notification_manager_upload_in_progress_text),
+            0
+        )
+
+        notificationBuilder.run {
             setProgress(100, 0, false)
-            setOngoing(true)
+            setContentTitle(currentOperationTitle)
+            setContentText(progressText)
+            setOngoing(false)
             clearActions()
 
             addAction(
@@ -76,13 +68,21 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
         }
     }
 
+    @Suppress("MagicNumber")
+    fun updateUploadProgress(percent: Int, currentOperation: UploadFileOperation?) {
+        setProgress(percent, R.string.upload_notification_manager_upload_in_progress_text, false)
+        showNotification()
+        dismissOldErrorNotification(currentOperation)
+    }
+
     fun notifyForFailedResult(
+        uploadFileOperation: UploadFileOperation,
         resultCode: RemoteOperationResult.ResultCode,
         conflictsResolveIntent: PendingIntent?,
         credentialIntent: PendingIntent?,
         errorMessage: String
     ) {
-        val textId = resultTitle(resultCode)
+        val textId = getFailedResultTitleId(resultCode)
 
         notificationBuilder.run {
             setTicker(context.getString(textId))
@@ -106,9 +106,11 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
 
             setContentText(errorMessage)
         }
+
+        showNewNotification(uploadFileOperation)
     }
 
-    private fun resultTitle(resultCode: RemoteOperationResult.ResultCode): Int {
+    private fun getFailedResultTitleId(resultCode: RemoteOperationResult.ResultCode): Int {
         val needsToUpdateCredentials = (resultCode == RemoteOperationResult.ResultCode.UNAUTHORIZED)
 
         return if (needsToUpdateCredentials) {
@@ -128,7 +130,7 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
         )
     }
 
-    fun showNewNotification(operation: UploadFileOperation) {
+    private fun showNewNotification(operation: UploadFileOperation) {
         notificationManager.notify(
             NotificationUtils.createUploadNotificationTag(operation.file),
             FileUploadWorker.NOTIFICATION_ERROR_ID,
@@ -136,22 +138,6 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
         )
     }
 
-    private fun showNotification() {
-        notificationManager.notify(ID, notificationBuilder.build())
-    }
-
-    @Suppress("MagicNumber")
-    fun updateUploadProgress(filename: String, percent: Int, currentOperation: UploadFileOperation?) {
-        notificationBuilder.run {
-            setProgress(100, percent, false)
-            val text = String.format(context.getString(R.string.uploader_upload_in_progress), percent, filename)
-            setContentText(text)
-
-            showNotification()
-            dismissOldErrorNotification(currentOperation)
-        }
-    }
-
     fun dismissOldErrorNotification(operation: UploadFileOperation?) {
         if (operation == null) {
             return
@@ -171,15 +157,11 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
         )
     }
 
-    fun dismissWorkerNotifications() {
-        notificationManager.cancel(ID)
-    }
-
     fun notifyPaused(intent: PendingIntent) {
-        notificationBuilder.apply {
+        notificationBuilder.run {
             setContentTitle(context.getString(R.string.upload_global_pause_title))
             setTicker(context.getString(R.string.upload_global_pause_title))
-            setOngoing(true)
+            setOngoing(false)
             setAutoCancel(false)
             setProgress(0, 0, false)
             clearActions()

+ 96 - 74
app/src/main/java/com/owncloud/android/datamodel/UploadsStorageManager.java

@@ -54,7 +54,11 @@ import androidx.annotation.VisibleForTesting;
 public class UploadsStorageManager extends Observable {
     private static final String TAG = UploadsStorageManager.class.getSimpleName();
 
+    private static final String IS_EQUAL =  "== ?";
+    private static final String EQUAL =  "==";
+    private static final String OR =  " OR ";
     private static final String AND = " AND ";
+    private static final String ANGLE_BRACKETS = "<>";
     private static final int SINGLE_RESULT = 1;
 
     private static final long QUERY_PAGE_SIZE = 100;
@@ -464,11 +468,45 @@ public class UploadsStorageManager extends Observable {
 
     @NonNull
     private List<OCUpload> getUploadPage(final long afterId, @Nullable String selection, @Nullable String... selectionArgs) {
-        return getUploadPage(afterId, true, selection, selectionArgs);
+        return getUploadPage(QUERY_PAGE_SIZE, afterId, true, selection, selectionArgs);
+    }
+
+    private String getInProgressUploadsSelection() {
+        return "( " + ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_IN_PROGRESS.value +
+            OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+            EQUAL + UploadResult.DELAYED_FOR_WIFI.getValue() +
+            OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+            EQUAL + UploadResult.LOCK_FAILED.getValue() +
+            OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+            EQUAL + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+            OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+            EQUAL + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+            " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL;
+    }
+
+    public int getTotalUploadSize(@Nullable String... selectionArgs) {
+        final String selection = getInProgressUploadsSelection();
+        int totalSize = 0;
+
+        Cursor cursor = getDB().query(
+            ProviderTableMeta.CONTENT_URI_UPLOADS,
+            new String[]{"COUNT(*) AS count"},
+            selection,
+            selectionArgs,
+            null);
+
+        if (cursor != null) {
+            if (cursor.moveToFirst()) {
+                totalSize = cursor.getInt(cursor.getColumnIndexOrThrow("count"));
+            }
+            cursor.close();
+        }
+
+        return totalSize;
     }
 
     @NonNull
-    private List<OCUpload> getUploadPage(final long afterId, final boolean descending, @Nullable String selection, @Nullable String... selectionArgs) {
+    private List<OCUpload> getUploadPage(long limit, final long afterId, final boolean descending, @Nullable String selection, @Nullable String... selectionArgs) {
         List<OCUpload> uploads = new ArrayList<>();
         String pageSelection = selection;
         String[] pageSelectionArgs = selectionArgs;
@@ -499,13 +537,20 @@ public class UploadsStorageManager extends Observable {
         } else {
             Log_OC.d(TAG, String.format(Locale.ENGLISH, "QUERY: %s ROWID: %d", selection, afterId));
         }
+
+        String sortOrder;
+        if (limit > 0) {
+            sortOrder = String.format(Locale.ENGLISH, "_id " + sortDirection + " LIMIT %d", limit);
+        } else {
+            sortOrder = String.format(Locale.ENGLISH, "_id " + sortDirection);
+        }
+
         Cursor c = getDB().query(
             ProviderTableMeta.CONTENT_URI_UPLOADS,
             null,
             pageSelection,
             pageSelectionArgs,
-            String.format(Locale.ENGLISH, "_id " + sortDirection + " LIMIT %d", QUERY_PAGE_SIZE)
-                                );
+            sortOrder);
 
         if (c != null) {
             if (c.moveToFirst()) {
@@ -560,17 +605,8 @@ public class UploadsStorageManager extends Observable {
     }
 
     public OCUpload[] getCurrentAndPendingUploadsForAccount(final @NonNull String accountName) {
-        return getUploads("( " + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.LOCK_FAILED.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
-                              " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
-                          accountName);
+        String inProgressUploadsSelection = getInProgressUploadsSelection();
+        return getUploads(inProgressUploadsSelection, accountName);
     }
 
     /**
@@ -579,76 +615,66 @@ public class UploadsStorageManager extends Observable {
      * If <code>afterId</code> is -1, returns the first page
      */
     public List<OCUpload> getCurrentAndPendingUploadsForAccountPageAscById(final long afterId, final @NonNull String accountName) {
-        final String selection = "( " + ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
-            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-            "==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-            "==" + UploadResult.LOCK_FAILED.getValue() +
-            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-            "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-            " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-            "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
-            " ) AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?";
-        return getUploadPage(afterId, false, selection, accountName);
+        final String selection = getInProgressUploadsSelection();
+        return getUploadPage(QUERY_PAGE_SIZE, afterId, false, selection, accountName);
     }
 
     /**
      * Get all failed uploads.
      */
     public OCUpload[] getFailedUploads() {
-        return getUploads("(" + ProviderTableMeta.UPLOADS_STATUS + "== ?" +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.LOCK_FAILED.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
-                              " OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+        return getUploads("(" + ProviderTableMeta.UPLOADS_STATUS + IS_EQUAL +
+                              OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                              EQUAL + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                              OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                              EQUAL + UploadResult.LOCK_FAILED.getValue() +
+                              OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                              EQUAL + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                              OR + ProviderTableMeta.UPLOADS_LAST_RESULT +
+                              EQUAL + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
                               " ) AND " + ProviderTableMeta.UPLOADS_LAST_RESULT +
                               "!= " + UploadResult.VIRUS_DETECTED.getValue()
             , String.valueOf(UploadStatus.UPLOAD_FAILED.value));
     }
 
     public OCUpload[] getUploadsForAccount(final @NonNull String accountName) {
-        return getUploads(ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", accountName);
+        return getUploads(ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, accountName);
     }
 
     public OCUpload[] getFinishedUploadsForCurrentAccount() {
         User user = currentAccountProvider.getUser();
 
-        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
-                              ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
+                              ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, user.getAccountName());
     }
 
     public OCUpload[] getCancelledUploadsForCurrentAccount() {
         User user = currentAccountProvider.getUser();
 
-        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_CANCELLED.value + AND +
-                              ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_CANCELLED.value + AND +
+                              ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, user.getAccountName());
     }
 
     /**
      * Get all uploads which where successfully completed.
      */
     public OCUpload[] getFinishedUploads() {
-
-        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value, (String[]) null);
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_SUCCEEDED.value, (String[]) null);
     }
 
     public OCUpload[] getFailedButNotDelayedUploadsForCurrentAccount() {
         User user = currentAccountProvider.getUser();
 
-        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_FAILED.value +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                              ANGLE_BRACKETS + UploadResult.DELAYED_FOR_WIFI.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.LOCK_FAILED.getValue() +
+                              ANGLE_BRACKETS + UploadResult.LOCK_FAILED.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                              ANGLE_BRACKETS + UploadResult.DELAYED_FOR_CHARGING.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
-                              AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                              ANGLE_BRACKETS + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                              AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL,
                           user.getAccountName());
     }
 
@@ -659,14 +685,14 @@ public class UploadsStorageManager extends Observable {
      */
     public OCUpload[] getFailedButNotDelayedUploads() {
 
-        return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value + AND +
-                              ProviderTableMeta.UPLOADS_LAST_RESULT + "<>" + UploadResult.LOCK_FAILED.getValue() +
+        return getUploads(ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_FAILED.value + AND +
+                              ProviderTableMeta.UPLOADS_LAST_RESULT + ANGLE_BRACKETS + UploadResult.LOCK_FAILED.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                              ANGLE_BRACKETS + UploadResult.DELAYED_FOR_WIFI.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                              ANGLE_BRACKETS + UploadResult.DELAYED_FOR_CHARGING.getValue() +
                               AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                              "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue(),
+                              ANGLE_BRACKETS + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue(),
                           (String[]) null
                          );
     }
@@ -679,16 +705,16 @@ public class UploadsStorageManager extends Observable {
         User user = currentAccountProvider.getUser();
         final long deleted = getDB().delete(
             ProviderTableMeta.CONTENT_URI_UPLOADS,
-            ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
+            ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_FAILED.value +
                 AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                "<>" + UploadResult.LOCK_FAILED.getValue() +
+                ANGLE_BRACKETS + UploadResult.LOCK_FAILED.getValue() +
                 AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                "<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
+                ANGLE_BRACKETS + UploadResult.DELAYED_FOR_WIFI.getValue() +
                 AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                "<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
+                ANGLE_BRACKETS + UploadResult.DELAYED_FOR_CHARGING.getValue() +
                 AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
-                "<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
-                AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
+                ANGLE_BRACKETS + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
+                AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL,
             new String[]{user.getAccountName()}
                                            );
         Log_OC.d(TAG, "delete all failed uploads but those delayed for Wifi");
@@ -702,8 +728,8 @@ public class UploadsStorageManager extends Observable {
         User user = currentAccountProvider.getUser();
         final long deleted = getDB().delete(
             ProviderTableMeta.CONTENT_URI_UPLOADS,
-            ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_CANCELLED.value + AND +
-                ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()}
+            ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_CANCELLED.value + AND +
+                ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, new String[]{user.getAccountName()}
                                            );
 
         Log_OC.d(TAG, "delete all cancelled uploads");
@@ -716,8 +742,8 @@ public class UploadsStorageManager extends Observable {
         User user = currentAccountProvider.getUser();
         final long deleted = getDB().delete(
             ProviderTableMeta.CONTENT_URI_UPLOADS,
-            ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
-                ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()}
+            ProviderTableMeta.UPLOADS_STATUS + EQUAL + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
+                ProviderTableMeta.UPLOADS_ACCOUNT_NAME + IS_EQUAL, new String[]{user.getAccountName()}
                                            );
 
         Log_OC.d(TAG, "delete all successful uploads");
@@ -877,17 +903,13 @@ public class UploadsStorageManager extends Observable {
         }
 
         public static UploadStatus fromValue(int value) {
-            switch (value) {
-                case 0:
-                    return UPLOAD_IN_PROGRESS;
-                case 1:
-                    return UPLOAD_FAILED;
-                case 2:
-                    return UPLOAD_SUCCEEDED;
-                case 3:
-                    return UPLOAD_CANCELLED;
-            }
-            return null;
+            return switch (value) {
+                case 0 -> UPLOAD_IN_PROGRESS;
+                case 1 -> UPLOAD_FAILED;
+                case 2 -> UPLOAD_SUCCEEDED;
+                case 3 -> UPLOAD_CANCELLED;
+                default -> null;
+            };
         }
 
         public int getValue() {

+ 2 - 2
app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java

@@ -53,8 +53,8 @@ public final class NotificationUtils {
      * @param context       Context that will use the builder to create notifications
      * @return An instance of the regular {@link NotificationCompat.Builder}.
      */
-    public static NotificationCompat.Builder newNotificationBuilder(Context context, final ViewThemeUtils viewThemeUtils) {
-        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+    public static NotificationCompat.Builder newNotificationBuilder(Context context, String channelId, final ViewThemeUtils viewThemeUtils) {
+        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);
         viewThemeUtils.androidx.themeNotificationCompatBuilder(context, builder);
         return builder;
     }

+ 0 - 2
app/src/main/res/values-ar/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">فشل التنزيل، قم بتسجيل الدخول مرة أخرى</string>
     <string name="downloader_download_failed_ticker">فشل التحميل</string>
     <string name="downloader_download_file_not_found">الملف غير متوفر في الخادم</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% تحميل  %2$s</string>
     <string name="downloader_download_in_progress_ticker">جارِ التنزيل …</string>
     <string name="downloader_download_succeeded_content">%1$s مُنزَّلَة</string>
@@ -978,7 +977,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">الإبقاء على الملف في المجلد الأصلي</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">إحذف الملف من المجلد الأصلي</string>
     <string name="uploader_upload_forbidden_permissions">للرفع إلى هذا المجلد</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% رفع %2$s</string>
     <string name="uploader_upload_in_progress_ticker">يتم الرفع…</string>
     <string name="uploader_upload_succeeded_content_single">تم رفع %1$s</string>

+ 0 - 2
app/src/main/res/values-b+en+001/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Download failed, log in again</string>
     <string name="downloader_download_failed_ticker">Download failed</string>
     <string name="downloader_download_file_not_found">The file is no longer available on the server</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
     <string name="downloader_download_in_progress_ticker">Downloading…</string>
     <string name="downloader_download_succeeded_content">%1$s downloaded</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Keep file in source folder</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Delete file from source folder</string>
     <string name="uploader_upload_forbidden_permissions">to upload to this folder</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Uploading…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s uploaded</string>

+ 0 - 2
app/src/main/res/values-cs-rCZ/strings.xml

@@ -236,7 +236,6 @@
     <string name="downloader_download_failed_credentials_error">Stahování se nezdařilo, přihlaste se znovu</string>
     <string name="downloader_download_failed_ticker">Stahování se nezdařilo</string>
     <string name="downloader_download_file_not_found">Tento soubor už není na serveru k dispozici</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Stahuje se %2$s</string>
     <string name="downloader_download_in_progress_ticker">Stahování…</string>
     <string name="downloader_download_succeeded_content">%1$s staženo</string>
@@ -910,7 +909,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Ponechat soubor ve zdrojové složce</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Vymazat soubor ze zdrojové složky</string>
     <string name="uploader_upload_forbidden_permissions">pro nahrávání do této složky</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Odesílání %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Nahrávání…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s nahráno</string>

+ 0 - 2
app/src/main/res/values-de/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Herunterladen fehlgeschlagen, erneute Anmeldung erforderlich</string>
     <string name="downloader_download_failed_ticker">Herunterladen fehlgeschlagen</string>
     <string name="downloader_download_file_not_found">Diese Datei steht auf dem Server nicht mehr zur Verfügung</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Herunterladen %2$s</string>
     <string name="downloader_download_in_progress_ticker">Lade herunter…</string>
     <string name="downloader_download_succeeded_content">%1$s heruntergeladen</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Hochladen und im Quellordner behalten</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Hochladen und Datei im Quellordner löschen</string>
     <string name="uploader_upload_forbidden_permissions">diesen Ordner hochzuladen</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Hochladen %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Lade hoch…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s hochgeladen</string>

+ 0 - 2
app/src/main/res/values-es-rMX/strings.xml

@@ -238,7 +238,6 @@
     <string name="downloader_download_failed_credentials_error">La descarga falló, inicia sesión de nuevo</string>
     <string name="downloader_download_failed_ticker">Falla en la descarga</string>
     <string name="downloader_download_file_not_found">El archivo ya no se encuentra disponible en el servidor</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Descargando %2$s</string>
     <string name="downloader_download_in_progress_ticker">Descargando…</string>
     <string name="downloader_download_succeeded_content">%1$s descargado</string>
@@ -937,7 +936,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Mantener el archivo en la carpeta de origen</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Borrar el archivo de la carpeta de origen</string>
     <string name="uploader_upload_forbidden_permissions">para cargar a esta carpeta</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Cargando %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Cargando</string>
     <string name="uploader_upload_succeeded_content_single">%1$s cargado</string>

+ 0 - 2
app/src/main/res/values-es/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Descarga fallida, vuelve a iniciar sesión</string>
     <string name="downloader_download_failed_ticker">Fallo al descargar</string>
     <string name="downloader_download_file_not_found">Este archivo ya no se encuentra en el servidor</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Descargado de %2$s</string>
     <string name="downloader_download_in_progress_ticker">Descargando…</string>
     <string name="downloader_download_succeeded_content">%1$s descargado</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Mantener el archivo en la carpeta original</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Borrar archivo de la carpeta original</string>
     <string name="uploader_upload_forbidden_permissions">para subir archivos a esta carpeta</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Subiendo %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Subiendo…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s subido</string>

+ 0 - 2
app/src/main/res/values-eu/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Deskargak huts egin du, hasi saioa berriz</string>
     <string name="downloader_download_failed_ticker">Deskargak huts egin du</string>
     <string name="downloader_download_file_not_found">Fitxategia jadanik ez dago eskuragarri zerbitzarian</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Deskargatzen %2$s</string>
     <string name="downloader_download_in_progress_ticker">Deskargatzen…</string>
     <string name="downloader_download_succeeded_content">%1$s deskargatuta</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Mantendu fitxategia jatorrizko karpetan</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Ezabatu fitxategia jatorrizko karpetatik</string>
     <string name="uploader_upload_forbidden_permissions">kargatzeko karpeta honetara</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Igotzen %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Kargatzen…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s igota</string>

+ 0 - 2
app/src/main/res/values-fa/strings.xml

@@ -225,7 +225,6 @@
     <string name="downloader_download_failed_credentials_error">بارگیری شکست خورد. دوباره وارد شوید</string>
     <string name="downloader_download_failed_ticker">دانلود ناموفق</string>
     <string name="downloader_download_file_not_found">این فایل دیگر روی سرور وجود ندارد</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% در حال دانلود %2$s</string>
     <string name="downloader_download_in_progress_ticker">بارگیری…</string>
     <string name="downloader_download_succeeded_content">%1$sدانلود شده </string>
@@ -921,7 +920,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">نگهداری فایل در پوشه منبع</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">حذف فایل از پوشه منبع</string>
     <string name="uploader_upload_forbidden_permissions">برای بارگذاری در این پوشه</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% در حال آپلود%2$s</string>
     <string name="uploader_upload_in_progress_ticker">بارگذاری…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s آپلود شده</string>

+ 0 - 2
app/src/main/res/values-fr/strings.xml

@@ -246,7 +246,6 @@
     <string name="downloader_download_failed_credentials_error">Téléchargement échoué, reconnectez-vous</string>
     <string name="downloader_download_failed_ticker">Le téléchargement a échoué</string>
     <string name="downloader_download_file_not_found">Ce fichier n’est plus disponible sur le serveur</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">Téléchargement de %2$s : %1$d%% effectués</string>
     <string name="downloader_download_in_progress_ticker">Réception en cours…</string>
     <string name="downloader_download_succeeded_content">%1$s reçu</string>
@@ -946,7 +945,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Conserver le fichier dans le dossier original</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Supprimer le fichier du dossier original</string>
     <string name="uploader_upload_forbidden_permissions">d\'envoyer dans ce dossier</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">Téléversement de %2$s : %1$d%%</string>
     <string name="uploader_upload_in_progress_ticker">Téléversement en cours…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s envoyé</string>

+ 0 - 2
app/src/main/res/values-it/strings.xml

@@ -228,7 +228,6 @@
     <string name="downloader_download_failed_credentials_error">Scaricamento non riuscito, effettua nuovamente l\'accesso</string>
     <string name="downloader_download_failed_ticker">Scaricamento non riuscito</string>
     <string name="downloader_download_file_not_found">Il file non è più disponibile sul server</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Scaricamento di %2$s</string>
     <string name="downloader_download_in_progress_ticker">Scaricamento in corso…</string>
     <string name="downloader_download_succeeded_content">%1$s scaricato</string>
@@ -900,7 +899,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Mantieni il file nella cartella di origine</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Elimina il file dalla cartella di origine</string>
     <string name="uploader_upload_forbidden_permissions">per caricare in questa cartella</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Caricamento di %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Caricamento in corso…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s caricato</string>

+ 0 - 2
app/src/main/res/values-nb-rNO/strings.xml

@@ -241,7 +241,6 @@
     <string name="downloader_download_failed_credentials_error">Nedlasting mislyktes, prøv igjen</string>
     <string name="downloader_download_failed_ticker">Nedlasting mislyktes</string>
     <string name="downloader_download_file_not_found">Filen finnes ikke på serveren lenger</string>
-    <string name="downloader_download_in_progress">%1$d %% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Laster ned %2$s</string>
     <string name="downloader_download_in_progress_ticker">Laster ned…</string>
     <string name="downloader_download_succeeded_content">%1$s lastet ned</string>
@@ -941,7 +940,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Behold filen i kildemappe</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Slett filen fra kildemappen</string>
     <string name="uploader_upload_forbidden_permissions">å laste opp i denne mappen</string>
-    <string name="uploader_upload_in_progress">%1$d %% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Laster opp %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Laster opp…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s lastet opp</string>

+ 0 - 2
app/src/main/res/values-nl/strings.xml

@@ -233,7 +233,6 @@
     <string name="downloader_download_failed_credentials_error">Downloaden mislukt, je moet opnieuw inloggen</string>
     <string name="downloader_download_failed_ticker">Downloaden mislukt</string>
     <string name="downloader_download_file_not_found">Dit bestand is niet langer beschikbaar op de server</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Downloaden van %2$s</string>
     <string name="downloader_download_in_progress_ticker">Downloaden…</string>
     <string name="downloader_download_succeeded_content">%1$s gedownload.</string>
@@ -882,7 +881,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Bewaar het bestand in de bronmap</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Verwijder bestand uit bronmap</string>
     <string name="uploader_upload_forbidden_permissions">om dit bestand in deze map te uploaden</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Uploaden van %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Uploaden…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s geüpload</string>

+ 0 - 2
app/src/main/res/values-pt-rBR/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Download falhou, logue-se novamente</string>
     <string name="downloader_download_failed_ticker">Download falhou</string>
     <string name="downloader_download_file_not_found">Este arquivo não está mais disponível neste servidor</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Baixando %2$s</string>
     <string name="downloader_download_in_progress_ticker">Baixando…</string>
     <string name="downloader_download_succeeded_content">%1$s baixado</string>
@@ -950,7 +949,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Manter arquivo na pasta de origem</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Excluir arquivo da pasta de origem</string>
     <string name="uploader_upload_forbidden_permissions">para enviar a esta pasta</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% enviando %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Enviando…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s enviado</string>

+ 0 - 2
app/src/main/res/values-ru/strings.xml

@@ -241,7 +241,6 @@
     <string name="downloader_download_failed_credentials_error">Ошибка скачивания, необходимо авторизоваться</string>
     <string name="downloader_download_failed_ticker">Сбой при скачивании</string>
     <string name="downloader_download_file_not_found">Этот файл больше недоступен на сервере</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Скачивается %2$s</string>
     <string name="downloader_download_in_progress_ticker">Скачивается…</string>
     <string name="downloader_download_succeeded_content">%1$s скачано</string>
@@ -942,7 +941,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Оставить файл в исходной папке</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Удалить файл из исходной папки</string>
     <string name="uploader_upload_forbidden_permissions">для передачи в эту папку</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% «%2$s»</string>
     <string name="uploader_upload_in_progress_ticker">Передача…</string>
     <string name="uploader_upload_succeeded_content_single">Передача файла «%1$s» завершена</string>

+ 0 - 2
app/src/main/res/values-sk-rSK/strings.xml

@@ -245,7 +245,6 @@
     <string name="downloader_download_failed_credentials_error">Sťahovanie neúspešné, je potrebné sa znovu prihlásiť</string>
     <string name="downloader_download_failed_ticker">Stiahnutie zlyhalo</string>
     <string name="downloader_download_file_not_found">Súbor už na serveri nie je dostupný</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Sťahovanie %2$s</string>
     <string name="downloader_download_in_progress_ticker">Sťahujem…</string>
     <string name="downloader_download_succeeded_content">%1$s stiahnuté</string>
@@ -945,7 +944,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Ponechaj súbor v pôvodnom priečinku</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Odstráň súbor z pôvodného priečinka</string>
     <string name="uploader_upload_forbidden_permissions">nahrávať do tohto priečinka</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Odosielam %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Nahrávanie…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s odoslané</string>

+ 0 - 2
app/src/main/res/values-sr/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Неуспешно преузимање. Поново се пријавите</string>
     <string name="downloader_download_failed_ticker">Преузимање није успело</string>
     <string name="downloader_download_file_not_found">Фајл није више доступан на серверу</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% преузимам %2$s</string>
     <string name="downloader_download_in_progress_ticker">Преузимам…</string>
     <string name="downloader_download_succeeded_content">%1$s преузето</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Остави фајл у изворној фасцикли</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Избриши фајл из изворне фасцикле</string>
     <string name="uploader_upload_forbidden_permissions">да отпремите ову фасциклу</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Отпремање %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Отпремам…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s отпремљено</string>

+ 0 - 2
app/src/main/res/values-sv/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">Hämtningen misslyckades, logga in igen</string>
     <string name="downloader_download_failed_ticker">Hämtning misslyckades</string>
     <string name="downloader_download_file_not_found">Filen är inte längre tillgänglig på servern</string>
-    <string name="downloader_download_in_progress">%1$d%%%2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Hämtar %2$s</string>
     <string name="downloader_download_in_progress_ticker">Hämtar…</string>
     <string name="downloader_download_succeeded_content">%1$s hämtad</string>
@@ -952,7 +951,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Behåll fil i källmappen</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Ta bort fil från källmappen</string>
     <string name="uploader_upload_forbidden_permissions">att ladda upp denna mapp</string>
-    <string name="uploader_upload_in_progress">%1$d%%%2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Laddar upp %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Laddar upp…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s uppladdad</string>

+ 0 - 2
app/src/main/res/values-tr/strings.xml

@@ -246,7 +246,6 @@
     <string name="downloader_download_failed_credentials_error">İndirilemedi, yeniden oturum açmalısınız</string>
     <string name="downloader_download_failed_ticker">İndirilemedi</string>
     <string name="downloader_download_file_not_found">Bu dosya artık sunucuda yok</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%%%1$d İndirilen: %2$s</string>
     <string name="downloader_download_in_progress_ticker">İndiriliyor …</string>
     <string name="downloader_download_succeeded_content">%1$s indirildi</string>
@@ -948,7 +947,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">Kaynak klasördeki dosya tutulsun</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">Dosya kaynak klasörden silinsin</string>
     <string name="uploader_upload_forbidden_permissions">bu klasöre yükleyemezsiniz</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%%%1$d Yüklenen: %2$s</string>
     <string name="uploader_upload_in_progress_ticker">Yükleniyor …</string>
     <string name="uploader_upload_succeeded_content_single">%1$s yüklendi</string>

+ 0 - 2
app/src/main/res/values-zh-rCN/strings.xml

@@ -239,7 +239,6 @@
     <string name="downloader_download_failed_credentials_error">下载失败,请重新登录</string>
     <string name="downloader_download_failed_ticker">下载失败</string>
     <string name="downloader_download_file_not_found">该文件在服务器上不可用</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% 正在下载 %2$s</string>
     <string name="downloader_download_in_progress_ticker">正在下载…</string>
     <string name="downloader_download_succeeded_content">已下载了 %1$s</string>
@@ -964,7 +963,6 @@ Nextcloud 是一个私有文件同步、共享和通信服务器。它是自由
     <string name="uploader_upload_files_behaviour_only_upload">在原文件夹中保留文件</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">从原文件夹中删除文件</string>
     <string name="uploader_upload_forbidden_permissions">上传到此文件夹</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% 正在上传 %2$s</string>
     <string name="uploader_upload_in_progress_ticker">正在上传…</string>
     <string name="uploader_upload_succeeded_content_single">已上传了 %1$s</string>

+ 0 - 2
app/src/main/res/values-zh-rHK/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">下載失敗,再重新登入</string>
     <string name="downloader_download_failed_ticker">下載失敗</string>
     <string name="downloader_download_file_not_found">這個檔案已經不存在於伺服器中</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% 下載中 %2$s</string>
     <string name="downloader_download_in_progress_ticker">下載中…</string>
     <string name="downloader_download_succeeded_content">%1$s 已下載</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">在來源資料夾保留檔案</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">刪除來源資料夾中的檔案</string>
     <string name="uploader_upload_forbidden_permissions">上傳至此資料夾</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% 上傳 %2$s 中</string>
     <string name="uploader_upload_in_progress_ticker">上傳中…</string>
     <string name="uploader_upload_succeeded_content_single">%1$s 已上傳</string>

+ 0 - 2
app/src/main/res/values-zh-rTW/strings.xml

@@ -247,7 +247,6 @@
     <string name="downloader_download_failed_credentials_error">下載失敗,再重新登入</string>
     <string name="downloader_download_failed_ticker">下載失敗</string>
     <string name="downloader_download_file_not_found">這個檔案已經不存在於伺服器中</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% 下載中 %2$s</string>
     <string name="downloader_download_in_progress_ticker">正在下載……</string>
     <string name="downloader_download_succeeded_content">%1$s 已下載</string>
@@ -951,7 +950,6 @@
     <string name="uploader_upload_files_behaviour_only_upload">在來源資料夾保留檔案</string>
     <string name="uploader_upload_files_behaviour_upload_and_delete_from_source">刪除來源資料夾中的檔案</string>
     <string name="uploader_upload_forbidden_permissions">上傳至此資料夾</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% 上傳 %2$s 中</string>
     <string name="uploader_upload_in_progress_ticker">正在上傳……</string>
     <string name="uploader_upload_succeeded_content_single">%1$s 已上傳</string>

+ 8 - 2
app/src/main/res/values/strings.xml

@@ -186,8 +186,11 @@
     <string name="active_user">Active user</string>
     <string name="upload_chooser_title">Upload from…</string>
     <string name="uploader_info_dirname">Folder name</string>
+
+    <string name="upload_notification_manager_start_text">%1$d / %2$d - %3$s</string>
+    <string name="upload_notification_manager_upload_in_progress_text" translatable="false">%1$d%%</string>
+
     <string name="uploader_upload_in_progress_ticker">Uploading…</string>
-    <string name="uploader_upload_in_progress">%1$d%% %2$s</string>
     <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>
     <string name="uploader_upload_succeeded_content_single">%1$s uploaded</string>
     <string name="uploader_upload_failed_ticker">Upload failed</string>
@@ -216,8 +219,11 @@
     <string name="uploads_view_upload_status_fetching_server_version">Fetching server version…</string>
     <string name="uploads_view_later_waiting_to_upload">Waiting to upload</string>
     <string name="uploads_view_group_header" translatable="false">%1$s (%2$d)</string>
+
+    <string name="downloader_notification_manager_download_text" translatable="false">%1$d / %2$d - %3$s</string>
+    <string name="downloader_notification_manager_in_progress_text" translatable="false">%1$d%%</string>
+
     <string name="downloader_download_in_progress_ticker">Downloading…</string>
-    <string name="downloader_download_in_progress">%1$d%% %2$s</string>
     <string name="downloader_download_in_progress_content">%1$d%% Downloading %2$s</string>
     <string name="downloader_download_succeeded_ticker">Downloaded</string>
     <string name="downloader_download_succeeded_content">%1$s downloaded</string>