@@ -27,7 +27,6 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker
2727import com.nextcloud.client.jobs.upload.UploadNotificationManager
2828import com.nextcloud.model.HTTPStatusCodes
2929import com.nextcloud.utils.extensions.getDecryptedPath
30- import com.nextcloud.utils.extensions.getParcelableArgument
3130import com.nextcloud.utils.extensions.logFileSize
3231import com.owncloud.android.R
3332import com.owncloud.android.datamodel.OCFile
@@ -42,7 +41,6 @@ import com.owncloud.android.ui.dialog.ConflictsResolveDialog
4241import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
4342import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
4443import com.owncloud.android.ui.notifications.NotificationUtils
45- import com.owncloud.android.utils.FileStorageUtils
4644import kotlinx.coroutines.Dispatchers
4745import kotlinx.coroutines.launch
4846import kotlinx.coroutines.withContext
@@ -64,7 +62,6 @@ class ConflictsResolveActivity :
6462 private var conflictUploadId: Long = 0
6563 private var offlineOperationPath: String? = null
6664 private var existingFile: OCFile ? = null
67- private var newFile: OCFile ? = null
6865 private var localBehaviour = FileUploadWorker .LOCAL_BEHAVIOUR_FORGET
6966 private lateinit var offlineOperationNotificationManager: OfflineOperationsNotificationManager
7067
@@ -81,31 +78,25 @@ class ConflictsResolveActivity :
8178 localBehaviour = upload.localAction
8279 }
8380
84- // new file was modified locally in file system
85- newFile = file
8681 setupOnConflictDecisionMadeListener(upload)
8782 offlineOperationNotificationManager = OfflineOperationsNotificationManager (this , viewThemeUtils)
8883 }
8984
9085 private fun getArguments (savedInstanceState : Bundle ? ) {
9186 if (savedInstanceState != null ) {
9287 conflictUploadId = savedInstanceState.getLong(EXTRA_CONFLICT_UPLOAD_ID )
93- existingFile = savedInstanceState.getParcelableArgument(EXTRA_EXISTING_FILE , OCFile ::class .java)
9488 localBehaviour = savedInstanceState.getInt(EXTRA_LOCAL_BEHAVIOUR )
9589 offlineOperationPath = savedInstanceState.getString(EXTRA_OFFLINE_OPERATION_PATH )
9690 } else {
9791 offlineOperationPath = intent.getStringExtra(EXTRA_OFFLINE_OPERATION_PATH )
9892 conflictUploadId = intent.getLongExtra(EXTRA_CONFLICT_UPLOAD_ID , - 1 )
99- existingFile = intent.getParcelableArgument(EXTRA_EXISTING_FILE , OCFile ::class .java)
10093 localBehaviour = intent.getIntExtra(EXTRA_LOCAL_BEHAVIOUR , localBehaviour)
10194 }
10295 }
10396
10497 private fun setupOnConflictDecisionMadeListener (upload : OCUpload ? ) {
10598 listener = OnConflictDecisionMadeListener { decision: Decision ? ->
10699
107- // local file got changed, so either upload it or replace it again by server
108- val file = newFile
109100
110101 // version
111102 val user = user.orElseThrow { RuntimeException () }
@@ -117,12 +108,12 @@ class ConflictsResolveActivity :
117108 }
118109
119110 when (decision) {
120- Decision .KEEP_LOCAL -> keepLocal(file, upload, user)
121- Decision .KEEP_BOTH -> keepBoth(file, upload, user)
122- Decision .KEEP_SERVER -> keepServer(file, upload)
123- Decision .KEEP_OFFLINE_FOLDER -> keepOfflineFolder(file, offlineOperation)
111+ Decision .KEEP_LOCAL -> keepLocal(upload, user)
112+ Decision .KEEP_BOTH -> keepBoth(upload, user)
113+ Decision .KEEP_SERVER -> keepServer(upload)
114+ Decision .KEEP_OFFLINE_FOLDER -> keepOfflineFolder(offlineOperation)
124115 Decision .KEEP_SERVER_FOLDER -> keepServerFile(offlineOperation)
125- Decision .KEEP_BOTH_FOLDER -> keepBothFolder(offlineOperation, file )
116+ Decision .KEEP_BOTH_FOLDER -> keepBothFolder(offlineOperation)
126117 else -> Unit
127118 }
128119
@@ -157,9 +148,9 @@ class ConflictsResolveActivity :
157148 notificationManager.cancel(tag, FileUploadWorker .NOTIFICATION_ERROR_ID )
158149 }
159150
160- private fun keepBothFolder (offlineOperation : OfflineOperationEntity ? , serverFile : OCFile ? ) {
151+ private fun keepBothFolder (offlineOperation : OfflineOperationEntity ? ) {
161152 offlineOperation ? : return
162- fileDataStorageManager.keepOfflineOperationAndServerFile(offlineOperation, serverFile )
153+ fileDataStorageManager.keepOfflineOperationAndServerFile(offlineOperation, file )
163154 backgroundJobManager.startOfflineOperations()
164155 offlineOperationNotificationManager.dismissNotification(offlineOperation.id)
165156 }
@@ -172,14 +163,14 @@ class ConflictsResolveActivity :
172163 offlineOperationNotificationManager.dismissNotification(id)
173164 }
174165
175- private fun keepOfflineFolder (serverFile : OCFile ? , offlineOperation : OfflineOperationEntity ? ) {
176- serverFile ? : return
166+ private fun keepOfflineFolder (offlineOperation : OfflineOperationEntity ? ) {
167+ file ? : return
177168 offlineOperation ? : return
178169
179170 lifecycleScope.launch(Dispatchers .IO ) {
180171 val client = clientRepository.getOwncloudClient() ? : return @launch
181172 val isSuccess = fileOperationHelper.removeFile(
182- serverFile ,
173+ file !! ,
183174 onlyLocalCopy = false ,
184175 inBackground = false ,
185176 client = client
@@ -194,20 +185,35 @@ class ConflictsResolveActivity :
194185 }
195186 }
196187
197- private fun keepLocal (file : OCFile ? , upload : OCUpload ? , user : User ) {
198- upload?.let {
199- FileUploadHelper .instance().removeFileUpload(it.remotePath, it.accountName)
188+ /* *
189+ * Removes the existing remote file and uploads the newly selected local file.
190+ */
191+ private fun keepLocal (upload : OCUpload ? , user : User ) {
192+ if (upload == null ) {
193+ Log_OC .e(TAG , " upload is null cannot upload a new file" )
194+ return
200195 }
201196
202- FileUploadHelper .instance().uploadUpdatedFile(
203- user,
204- arrayOf(file),
205- localBehaviour,
206- NameCollisionPolicy .OVERWRITE
207- )
197+ if (existingFile == null || existingFile?.fileId == - 1L ) {
198+ Log_OC .e(TAG , " existing file is null, cannot be delete." )
199+ return
200+ }
201+
202+ lifecycleScope.launch {
203+ val result = withContext(Dispatchers .IO ) {
204+ fileDataStorageManager.removeFile(existingFile, true , false )
205+ }
206+
207+ if (result) {
208+ backgroundJobManager.startFilesUploadJob(user,
209+ longArrayOf(upload.uploadId),
210+ true
211+ )
212+ }
213+ }
208214 }
209215
210- private fun keepBoth (file : OCFile ? , upload : OCUpload ? , user : User ) {
216+ private fun keepBoth (upload : OCUpload ? , user : User ) {
211217 upload?.let {
212218 FileUploadHelper .instance().removeFileUpload(it.remotePath, it.accountName)
213219 }
@@ -220,13 +226,13 @@ class ConflictsResolveActivity :
220226 )
221227 }
222228
223- private fun keepServer (file : OCFile ? , upload : OCUpload ? ) {
229+ private fun keepServer (upload : OCUpload ? ) {
224230 if (! shouldDeleteLocal()) {
225231 // Overwrite local file
226232 file?.let {
227233 FileDownloadHelper .instance().downloadFile(
228234 user.orElseThrow { RuntimeException () },
229- file ,
235+ it ,
230236 conflictUploadId = conflictUploadId
231237 )
232238 }
@@ -249,7 +255,6 @@ class ConflictsResolveActivity :
249255
250256 outState.run {
251257 putLong(EXTRA_CONFLICT_UPLOAD_ID , conflictUploadId)
252- putParcelable(EXTRA_EXISTING_FILE , existingFile)
253258 putInt(EXTRA_LOCAL_BEHAVIOUR , localBehaviour)
254259 }
255260 }
@@ -263,18 +268,18 @@ class ConflictsResolveActivity :
263268 super .onStart()
264269
265270 if (account == null ) {
266- finish ()
271+ showErrorAndFinish ()
267272 return
268273 }
269274
270- if (newFile == null ) {
271- Log_OC .e(TAG , " No file received " )
272- finish ()
275+ if (file == null ) {
276+ Log_OC .e(TAG , " newly selected local file cannot be null " )
277+ showErrorAndFinish ()
273278 return
274279 }
275280
276281 offlineOperationPath?.let { path ->
277- newFile ?.let { ocFile ->
282+ file ?.let { ocFile ->
278283 val offlineOperation = fileDataStorageManager.offlineOperationDao.getByPath(path)
279284
280285 if (offlineOperation == null ) {
@@ -293,33 +298,85 @@ class ConflictsResolveActivity :
293298 }
294299 }
295300
296- if (existingFile == null ) {
297- val remotePath = fileDataStorageManager.retrieveRemotePathConsideringEncryption(newFile) ? : return
298- val operation = ReadFileRemoteOperation (remotePath)
299-
300- @Suppress(" TooGenericExceptionCaught" )
301- lifecycleScope.launch(Dispatchers .IO ) {
302- try {
303- val result = operation.execute(account, this @ConflictsResolveActivity)
304- if (result.isSuccess) {
305- existingFile = FileStorageUtils .fillOCFile(result.data[0 ] as RemoteFile )
306- existingFile?.lastSyncDateForProperties = System .currentTimeMillis()
307- startDialog(remotePath)
308- } else {
309- Log_OC .e(TAG , " ReadFileRemoteOp returned failure with code: " + result.httpCode)
310- showErrorAndFinish(result.httpCode)
311- }
312- } catch (e: Exception ) {
313- Log_OC .e(TAG , " Error when trying to fetch remote file" , e)
301+ initExistingFile()
302+ }
303+
304+ private fun initExistingFile () {
305+ lifecycleScope.launch {
306+ val resolved = withContext(Dispatchers .IO ) {
307+ resolveExistingFileFromDbOrServer()
308+ }
309+
310+ withContext(Dispatchers .Main ) {
311+ if (resolved == null ) {
312+ Log_OC .e(TAG , " existing file cannot be resolved from DB or server" )
313+ showErrorAndFinish()
314+ return @withContext
315+ }
316+
317+ existingFile = resolved
318+
319+ val remotePath = fileDataStorageManager
320+ .retrieveRemotePathConsideringEncryption(existingFile)
321+
322+ if (remotePath == null ) {
323+ Log_OC .e(TAG , " failed to obtain remotePath for existing file" )
314324 showErrorAndFinish()
325+ return @withContext
315326 }
327+
328+ startDialog(remotePath)
316329 }
317- } else {
318- val remotePath = fileDataStorageManager.retrieveRemotePathConsideringEncryption(existingFile) ? : return
319- startDialog(remotePath)
320330 }
321331 }
322332
333+ private fun resolveExistingFileFromDbOrServer (): OCFile ? {
334+ val candidate = file ? : return null
335+
336+ val remotePath = try {
337+ fileDataStorageManager.retrieveRemotePathConsideringEncryption(candidate)
338+ } catch (e: Exception ) {
339+ Log_OC .e(TAG , " Error calculating decrypted remote path" , e)
340+ return null
341+ } ? : return null
342+
343+ // check db first
344+ var dbFile = fileDataStorageManager.getFileByDecryptedRemotePath(remotePath)
345+ if (dbFile != null && dbFile.fileId != - 1L ) {
346+ return dbFile
347+ }
348+
349+ Log_OC .w(TAG , " DB entry missing for $remotePath → fetching from server…" )
350+
351+ val account = account ? : return null
352+ val result = try {
353+ val op = ReadFileRemoteOperation (remotePath)
354+ op.execute(account, this @ConflictsResolveActivity)
355+ } catch (e: Exception ) {
356+ Log_OC .e(TAG , " Error calling ReadFileRemoteOperation" , e)
357+ return null
358+ }
359+
360+ if (! result.isSuccess || result.data.isEmpty()) {
361+ Log_OC .e(TAG , " Remote file fetch failed (http ${result.httpCode} )" )
362+ return null
363+ }
364+
365+ val remoteFile = result.data[0 ] as ? RemoteFile ? : return null
366+
367+ dbFile = fileDataStorageManager.getFileByDecryptedRemotePath(remoteFile.remotePath)
368+
369+ if (dbFile != null && dbFile.fileId != - 1L ) {
370+ dbFile.lastSyncDateForProperties = System .currentTimeMillis()
371+ fileDataStorageManager.saveFile(dbFile)
372+ return dbFile
373+ }
374+
375+ Log_OC .e(TAG , " DB still missing entry for ${remoteFile.remotePath} " )
376+ return null
377+ }
378+
379+
323380 @SuppressLint(" CommitTransaction" )
324381 private fun prepareDialog (): Pair <FragmentTransaction , User > {
325382 val userOptional = user
@@ -341,11 +398,11 @@ class ConflictsResolveActivity :
341398 private fun startDialog (remotePath : String ) {
342399 val (ft, user) = prepareDialog()
343400
344- if (existingFile != null && storageManager.fileExists(remotePath) && newFile != null ) {
401+ if (existingFile != null && storageManager.fileExists(remotePath) && file != null ) {
345402 val dialog = ConflictsResolveDialog .newInstance(
346403 title = storageManager.getDecryptedPath(existingFile!! ),
347404 context = this ,
348- leftFile = newFile !! ,
405+ leftFile = file !! ,
349406 rightFile = existingFile!! ,
350407 user = user
351408 )
@@ -386,7 +443,6 @@ class ConflictsResolveActivity :
386443 * Specify the upload local behaviour when there is no CONFLICT_UPLOAD.
387444 */
388445 const val EXTRA_LOCAL_BEHAVIOUR = " LOCAL_BEHAVIOUR"
389- const val EXTRA_EXISTING_FILE = " EXISTING_FILE"
390446 private const val EXTRA_OFFLINE_OPERATION_PATH = " EXTRA_OFFLINE_OPERATION_PATH"
391447
392448 private val TAG = ConflictsResolveActivity ::class .java.simpleName
0 commit comments