Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/src/main/java/com/nextcloud/client/database/dao/UploadDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ interface UploadDao {
)
suspend fun updateStatuses(remotePaths: List<String>, accountName: String, status: Int): Int

@Query(
"""
UPDATE ${ProviderTableMeta.UPLOADS_TABLE_NAME}
SET ${ProviderTableMeta.UPLOADS_STATUS} = :newStatus,
${ProviderTableMeta.UPLOADS_LAST_RESULT} = :lastResult
WHERE ${ProviderTableMeta.UPLOADS_ACCOUNT_NAME} = :accountName
AND ${ProviderTableMeta.UPLOADS_STATUS} = :currentStatus
"""
)
suspend fun updateStatusAndResultByAccount(
accountName: String,
currentStatus: Int,
newStatus: Int,
lastResult: Int
): Int

@Query(
"""
SELECT * FROM ${ProviderTableMeta.UPLOADS_TABLE_NAME}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ class AutoUploadWorker(
return@withContext
}

if (result.code == ResultCode.QUOTA_EXCEEDED) {
Log_OC.w(TAG, "quota exceeded, stopping auto upload")
sendUploadFinishEvent(operation, result)
return@withContext
}

// Mark CONFLICT files as handled to prevent retries
if (result.code.isConflict()) {
repository.markFileAsHandled(localPath, syncedFolder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,9 @@ class AlbumFileUploadWorker(

if (result.code == ResultCode.QUOTA_EXCEEDED) {
Log_OC.w(TAG, "Quota exceeded, stopping uploads")
notificationManager.showQuotaExceedNotification(operation)
break
uploadsStorageManager.markInProgressUploadsAsQuotaExceeded(accountName)
fileUploadEventBroadcaster.sendUploadCompleted(operation, result, context)
return@withContext Result.failure()
}

sendUploadFinishEvent(totalUploadSize, currentUploadIndex, operation, result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,9 @@ class FileUploadWorker(
// check quota first
if (result.code == ResultCode.QUOTA_EXCEEDED) {
Log_OC.w(TAG, "Quota exceeded, stopping uploads")
notificationManager.showQuotaExceedNotification(operation)
break
uploadsStorageManager.markInProgressUploadsAsQuotaExceeded(accountName)
fileUploadEventBroadcaster.sendUploadCompleted(operation, result, context)
return@withContext Result.failure()
}

if (!result.isSuccess && !result.code.isUserCancellation()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,6 @@ class UploadNotificationManager(private val context: Context, viewThemeUtils: Vi
)
}

fun showQuotaExceedNotification(operation: UploadFileOperation) {
val notification = notificationBuilder.run {
setContentTitle(context.getString(R.string.upload_quota_exceeded))
setContentText("")
clearActions()
setProgress(0, 0, false)
}.build()

showNotification(operation.file.fileId.toInt(), notification)
}

fun showConnectionErrorNotification() {
notificationManager.cancel(getId())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ object UploadErrorNotificationManager {
return
}

if (result.code == ResultCode.QUOTA_EXCEEDED) {
AppWideNotificationManager.showQuotaExceededNotification(context)
return
}

// do not show an error notification when uploading the same file again
if (result.code.isConflict()) {
val isSameFile = withContext(Dispatchers.IO) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.nextcloud.client.notifications

import android.Manifest
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
Expand Down Expand Up @@ -37,6 +38,7 @@ object AppWideNotificationManager {
private const val SYNC_CONFLICT_NOTIFICATION_INTENT_ACTION_REQ_CODE = 17

private const val SYNC_CONFLICT_NOTIFICATION_ID = 112
private const val QUOTA_EXCEEDED_NOTIFICATION_ID = 113

fun getUploadListPendingIntent(context: Context): PendingIntent {
val intent = NavigatorActivity.intent(context, NavigatorScreen.UploadList).apply {
Expand Down Expand Up @@ -84,16 +86,36 @@ object AppWideNotificationManager {
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()

notify(context, SYNC_CONFLICT_NOTIFICATION_ID, notification)
}

fun showQuotaExceededNotification(context: Context) {
val description = context.getString(R.string.upload_quota_exceeded_notification_description)

val notification = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
.setSmallIcon(R.drawable.uploads)
.setContentTitle(context.getString(R.string.upload_quota_exceeded))
.setContentText(description)
.setStyle(NotificationCompat.BigTextStyle().bigText(description))
.setContentIntent(getUploadListPendingIntent(context))
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()

notify(context, QUOTA_EXCEEDED_NOTIFICATION_ID, notification)
}

private fun notify(context: Context, id: Int, notification: Notification) {
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
Log_OC.w(TAG, "cannot show sync conflict notification, post notification permission is not granted")
Log_OC.w(TAG, "cannot show notification $id, post notification permission is not granted")
return
}

NotificationManagerCompat.from(context)
.notify(SYNC_CONFLICT_NOTIFICATION_ID, notification)
NotificationManagerCompat.from(context).notify(id, notification)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ fun UploadResult.isNonRetryable(): Boolean = when (this) {
UploadResult.SAME_FILE_CONFLICT,
UploadResult.LOCAL_STORAGE_NOT_COPIED,
UploadResult.VIRUS_DETECTED,
UploadResult.QUOTA_EXCEEDED,
UploadResult.PRIVILEGES_ERROR,

// user's choice
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,17 @@ class UploadsStorageManager(
}
}

suspend fun markInProgressUploadsAsQuotaExceeded(accountName: String) {
val count = uploadDao.updateStatusAndResultByAccount(
accountName = accountName,
currentStatus = UploadStatus.UPLOAD_IN_PROGRESS.value,
newStatus = UploadStatus.UPLOAD_FAILED.value,
lastResult = UploadResult.QUOTA_EXCEEDED.value
)
Log_OC.d(TAG, "marked $count in progress uploads as quota exceeded")
notifyObserversNow()
}

fun removeUpload(upload: OCUpload?): Int = if (upload == null) 0 else removeUpload(upload.uploadId)

fun removeUpload(id: Long): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class UploadListAdapter(
) : SectionedRecyclerViewAdapter<SectionedViewHolder>() {

private val uploadListSections = UploadListSection.sections()
private var latestLoadId = 0
private val showUser: Boolean = accountManager.getAccounts().size > 1
private val uploadHelper = FileUploadHelper.instance()
private var uploadProgressListener: UploadProgressListener? = null
Expand Down Expand Up @@ -559,6 +560,7 @@ class UploadListAdapter(

val accountName = optionalUser.get().accountName
val capabilities = optionalCapabilities.get()
val loadId = ++latestLoadId

activity.lifecycleScope.launch(Dispatchers.IO) {
val succeededUploads = uploadHelper.getUploadsByStatus(
Expand All @@ -578,6 +580,11 @@ class UploadListAdapter(
}

withContext(Dispatchers.Main) {
if (loadId != latestLoadId) {
onCompleted.run()
return@withContext
}

for (i in uploadListSections.indices) {
uploadListSections[i] = updatedSections[i]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ class UploadListFragment :

private val uploadFinishReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == FileUploadEventBroadcaster.ACTION_UPLOAD_COMPLETED) {
uploadListAdapter.loadUploadItemsFromDb()
return
}

throttler.run(UPDATE_UPLOAD_LIST_KEY) { uploadListAdapter.loadUploadItemsFromDb() }
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,7 @@
<string name="upload_local_storage_not_copied">File could not be copied to local storage</string>
<string name="upload_global_pause_title">All uploads are paused</string>
<string name="upload_quota_exceeded">Storage quota exceeded</string>
<string name="upload_quota_exceeded_notification_description">Your storage quota is full, so uploads were stopped. Free up space or ask your administrator for more quota, then retry the failed uploads from Uploads.</string>
<string name="host_not_available">Server not available</string>
<string name="delete_entries">Delete entries</string>
<string name="upload_list_expand_header">Toggle expansion of header</string>
Expand Down
8 changes: 8 additions & 0 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22629,6 +22629,14 @@
<sha256 value="803eeabdbf8e78808a42986a9e6ec7d5e7e74ec9024a38a577898ef699f504db" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library" version="36c60a34dd">
<artifact name="android-library-36c60a34dd.aar">
<sha256 value="e5620b63d4686654a1a595f5f255972c5050ec1c7ff2086afa9f24bd0badc19c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="android-library-36c60a34dd.module">
<sha256 value="f89245e58b5bbf0c26d1bd7db208941aacc0b0ae1844b2c868003b85c5c3e668" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.github.nextcloud" name="android-library" version="38328f338c00870c6a062188974f8f30a61fb450">
<artifact name="android-library-38328f338c00870c6a062188974f8f30a61fb450.aar">
<sha256 value="05b55bc24c2f1c5b30cd74ccde6b506b7b0c40411c0282d9adf838635fb3328d" origin="Generated by Gradle" reason="Artifact is not signed"/>
Expand Down
Loading