@@ -31,39 +31,74 @@ import java.io.File
3131object UploadErrorNotificationManager {
3232 private const val TAG = " UploadErrorNotificationManager"
3333
34+ /* *
35+ * Processes the result of an upload operation and manages error notifications.
36+ * * It filters out successful or silent results and handles [ResultCode.SYNC_CONFLICT]
37+ * by checking if the remote file is identical. If it's a "real" conflict or error,
38+ * it displays a notification with relevant actions (e.g., Resolve Conflict, Pause, Cancel).
39+ *
40+ * @param onSameFileConflict Triggered only if result code is SYNC_CONFLICT and files are identical.
41+ */
42+ @Suppress(" ReturnCount" )
3443 suspend fun handleResult (
3544 context : Context ,
3645 notificationManager : WorkerNotificationManager ,
3746 operation : UploadFileOperation ,
3847 result : RemoteOperationResult <Any ?>,
39- showSameFileAlreadyExistsNotification : suspend () -> Unit = {}
48+ onSameFileConflict : suspend () -> Unit = {}
4049 ) {
4150 Log_OC .d(TAG , " handle upload result with result code: " + result.code)
4251
43- val notification = withContext(Dispatchers .IO ) {
44- val isSameFileOnRemote = FileUploadHelper .instance().isSameFileOnRemote(
45- operation.user,
46- File (operation.storagePath),
47- operation.remotePath,
48- context
49- )
52+ if (result.isSuccess || result.isCancelled || operation.isMissingPermissionThrown) {
53+ Log_OC .d(TAG , " operation is successful, cancelled or lack of storage permission, notification skipped" )
54+ return
55+ }
5056
51- getNotification(
52- isSameFileOnRemote,
53- context,
54- notificationManager.notificationBuilder,
55- operation,
56- result,
57- notifyOnSameFileExists = {
58- showSameFileAlreadyExistsNotification()
59- operation.handleLocalBehaviour()
60- }
61- )
62- } ? : return
57+ val silentCodes = setOf (
58+ ResultCode .DELAYED_FOR_WIFI ,
59+ ResultCode .DELAYED_FOR_CHARGING ,
60+ ResultCode .DELAYED_IN_POWER_SAVE_MODE ,
61+ ResultCode .LOCAL_FILE_NOT_FOUND ,
62+ ResultCode .LOCK_FAILED
63+ )
64+
65+ if (result.code in silentCodes) {
66+ Log_OC .d(TAG , " silent error code, notification skipped" )
67+ return
68+ }
69+
70+ // do not show an error notification when uploading the same file again
71+ if (result.code == ResultCode .SYNC_CONFLICT ) {
72+ val isSameFile = withContext(Dispatchers .IO ) {
73+ FileUploadHelper .instance().isSameFileOnRemote(
74+ operation.user,
75+ File (operation.storagePath),
76+ operation.remotePath,
77+ context
78+ )
79+ }
80+
81+ if (isSameFile) {
82+ Log_OC .w(TAG , " exact same file already exists on remote, error notification skipped" )
83+
84+ // only show notification for manual uploads
85+ onSameFileConflict()
86+ return
87+ }
88+ }
89+
90+ // now we can show error notification
91+ val notification = getNotification(
92+ context,
93+ notificationManager.notificationBuilder,
94+ operation,
95+ result
96+ )
6397
6498 Log_OC .d(TAG , " 🔔" + " notification created" )
6599
66100 withContext(Dispatchers .Main ) {
101+ // if error code is file specific show new notification for each file
67102 if (result.code.isFileSpecificError()) {
68103 notificationManager.showNotification(operation.ocUploadId.toInt(), notification)
69104 } else {
@@ -72,16 +107,12 @@ object UploadErrorNotificationManager {
72107 }
73108 }
74109
75- private suspend fun getNotification (
76- isSameFileOnRemote : Boolean ,
110+ private fun getNotification (
77111 context : Context ,
78112 builder : NotificationCompat .Builder ,
79113 operation : UploadFileOperation ,
80- result : RemoteOperationResult <Any ?>,
81- notifyOnSameFileExists : suspend () -> Unit
82- ): Notification ? {
83- if (! shouldShowConflictDialog(isSameFileOnRemote, operation, result, notifyOnSameFileExists)) return null
84-
114+ result : RemoteOperationResult <Any ?>
115+ ): Notification {
85116 val textId = result.code.toFailedResultTitleId()
86117 val errorMessage = ErrorMessageAdapter .getErrorCauseMessage(result, operation, context.resources)
87118
@@ -94,19 +125,19 @@ object UploadErrorNotificationManager {
94125 setProgress(0 , 0 , false )
95126 clearActions()
96127
97- result.code.takeIf { it == ResultCode .SYNC_CONFLICT }?.let {
128+ // actions for all error types
129+ addAction(UploadBroadcastAction .PauseAndCancel (operation).pauseAction(context))
130+ addAction(UploadBroadcastAction .PauseAndCancel (operation).cancelAction(context))
131+
132+ if (result.code == ResultCode .SYNC_CONFLICT ) {
98133 addAction(
99134 R .drawable.ic_cloud_upload,
100135 context.getString(R .string.upload_list_resolve_conflict),
101136 conflictResolvePendingIntent(context, operation)
102137 )
103138 }
104139
105- addAction(UploadBroadcastAction .PauseAndCancel (operation).pauseAction(context))
106-
107- addAction(UploadBroadcastAction .PauseAndCancel (operation).cancelAction(context))
108-
109- result.code.takeIf { it == ResultCode .UNAUTHORIZED }?.let {
140+ if (result.code == ResultCode .UNAUTHORIZED ) {
110141 setContentIntent(credentialPendingIntent(context, operation))
111142 }
112143 }.build()
@@ -159,33 +190,4 @@ object UploadErrorNotificationManager {
159190 PendingIntent .FLAG_IMMUTABLE
160191 )
161192 }
162-
163- @Suppress(" ReturnCount" , " ComplexCondition" )
164- private suspend fun shouldShowConflictDialog (
165- isSameFileOnRemote : Boolean ,
166- operation : UploadFileOperation ,
167- result : RemoteOperationResult <Any ?>,
168- notifyOnSameFileExists : suspend () -> Unit
169- ): Boolean {
170- if (result.isSuccess ||
171- result.isCancelled ||
172- result.code == ResultCode .USER_CANCELLED ||
173- operation.isMissingPermissionThrown
174- ) {
175- Log_OC .w(TAG , " operation is successful, cancelled or lack of storage permission" )
176- return false
177- }
178-
179- if (result.code == ResultCode .SYNC_CONFLICT && isSameFileOnRemote) {
180- Log_OC .w(TAG , " same file exists on remote" )
181- notifyOnSameFileExists()
182- return false
183- }
184-
185- val delayedCodes =
186- setOf (ResultCode .DELAYED_FOR_WIFI , ResultCode .DELAYED_FOR_CHARGING , ResultCode .DELAYED_IN_POWER_SAVE_MODE )
187- val invalidCodes = setOf (ResultCode .LOCAL_FILE_NOT_FOUND , ResultCode .LOCK_FAILED )
188-
189- return result.code !in delayedCodes && result.code !in invalidCodes
190- }
191193}
0 commit comments