Skip to content

Commit 22fef50

Browse files
committed
fix conflict resolve activity
Signed-off-by: alperozturk <[email protected]>
1 parent db2de63 commit 22fef50

File tree

1 file changed

+117
-61
lines changed

1 file changed

+117
-61
lines changed

app/src/main/java/com/owncloud/android/ui/activity/ConflictsResolveActivity.kt

Lines changed: 117 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker
2727
import com.nextcloud.client.jobs.upload.UploadNotificationManager
2828
import com.nextcloud.model.HTTPStatusCodes
2929
import com.nextcloud.utils.extensions.getDecryptedPath
30-
import com.nextcloud.utils.extensions.getParcelableArgument
3130
import com.nextcloud.utils.extensions.logFileSize
3231
import com.owncloud.android.R
3332
import com.owncloud.android.datamodel.OCFile
@@ -42,7 +41,6 @@ import com.owncloud.android.ui.dialog.ConflictsResolveDialog
4241
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.Decision
4342
import com.owncloud.android.ui.dialog.ConflictsResolveDialog.OnConflictDecisionMadeListener
4443
import com.owncloud.android.ui.notifications.NotificationUtils
45-
import com.owncloud.android.utils.FileStorageUtils
4644
import kotlinx.coroutines.Dispatchers
4745
import kotlinx.coroutines.launch
4846
import 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

Comments
 (0)