@@ -26,12 +26,10 @@ import eu.opencloud.android.domain.BaseUseCaseWithResult
2626import eu.opencloud.android.domain.exceptions.FileNotFoundException
2727import eu.opencloud.android.domain.files.FileRepository
2828import eu.opencloud.android.domain.files.model.OCFile
29- import eu.opencloud.android.domain.files.usecases.SaveConflictUseCase
29+
3030import eu.opencloud.android.presentation.settings.security.SettingsSecurityFragment
3131import eu.opencloud.android.usecases.transfers.downloads.DownloadFileUseCase
3232import eu.opencloud.android.usecases.transfers.uploads.UploadFileInConflictUseCase
33- import kotlinx.coroutines.CoroutineScope
34- import kotlinx.coroutines.Dispatchers
3533import timber.log.Timber
3634import java.io.File
3735import java.text.SimpleDateFormat
@@ -42,7 +40,6 @@ import java.util.UUID
4240class SynchronizeFileUseCase (
4341 private val downloadFileUseCase : DownloadFileUseCase ,
4442 private val uploadFileInConflictUseCase : UploadFileInConflictUseCase ,
45- private val saveConflictUseCase : SaveConflictUseCase ,
4643 private val fileRepository : FileRepository ,
4744 private val preferencesProvider : SharedPreferencesProvider ,
4845) : BaseUseCaseWithResult<SynchronizeFileUseCase.SyncType, SynchronizeFileUseCase.Params>() {
@@ -51,13 +48,13 @@ class SynchronizeFileUseCase(
5148 val fileToSynchronize = params.fileToSynchronize
5249 val accountName: String = fileToSynchronize.owner
5350
54- // Fix: Use correct dispatcher usage. `CoroutineScope(Dispatchers.IO).run` blocks the current thread if called with `runBlocking` or similar upstream,
55- // but here it returns a value, so it implies this is synchronous code?
51+ // Fix: Use correct dispatcher usage. `CoroutineScope(Dispatchers.IO).run` blocks the current thread
52+ // if called with `runBlocking` or similar upstream, but here it returns a value, so it implies this is synchronous code?
5653 // `BaseUseCaseWithResult` usually runs in a background thread if invoked correctly?
57- // The original code used `CoroutineScope(Dispatchers.IO).run`, which creates a scope and runs the block.
58- // But `run` is incorrect here if we want to return from the function.
54+ // The original code used `CoroutineScope(Dispatchers.IO).run`, which creates a scope and runs the block.
55+ // But `run` is incorrect here if we want to return from the function.
5956 // `CoroutineScope(Dispatchers.IO).run` returns the result of the block.
60- // Actually `run` is a standard library extension on T.
57+ // Actually `run` is a standard library extension on T.
6158 // `CoroutineScope(Dispatchers.IO)` creates a stand-alone scope. `run` executes the block on *that object*.
6259 // It does NOT switch threads! `CoroutineScope(Dispatchers.IO)` just creates a new scope object.
6360 // The original code was likely running on the caller's thread!
@@ -66,20 +63,23 @@ class SynchronizeFileUseCase(
6663 // This is a subtle but massive bug in the original code too if it expected async/threading.
6764 // However, `BaseUseCaseWithResult` might be handling threading?
6865 // Let's assume we just want to fix the logic bugs for now.
69-
66+
7067 // 1. Check local state first to avoid network calls if possible (optimization)
7168 // Check if file has changed locally by reading ACTUAL file timestamp from filesystem
7269 val storagePath = fileToSynchronize.storagePath
73- val localFile = if ( storagePath != null ) File (storagePath) else null
70+ val localFile = storagePath?. let { File (it) }
7471 val fileExistsLocally = localFile?.exists() == true
75-
72+
7673 var changedLocally = false
7774 if (fileExistsLocally) {
7875 val actualFileModificationTime = localFile!! .lastModified()
7976 // Fix: Null safety for lastSyncDateForData
8077 changedLocally = actualFileModificationTime > (fileToSynchronize.lastSyncDateForData ? : 0 )
81-
82- Timber .d(" File ${fileToSynchronize.fileName} : localTimestamp=$actualFileModificationTime , lastSync=${fileToSynchronize.lastSyncDateForData} , changedLocally=$changedLocally " )
78+
79+ Timber .d(
80+ " File ${fileToSynchronize.fileName} : localTimestamp=$actualFileModificationTime , " +
81+ " lastSync=${fileToSynchronize.lastSyncDateForData} , changedLocally=$changedLocally "
82+ )
8383 }
8484
8585 // 2. Perform propfind to check remote state
@@ -91,11 +91,11 @@ class SynchronizeFileUseCase(
9191 )
9292 } catch (exception: FileNotFoundException ) {
9393 Timber .i(exception, " File does not exist anymore in remote" )
94-
94+
9595 // 2.1 File does not exist anymore in remote
9696 // If it still exists locally, but file has different path, another operation could have been done simultaneously
9797 val localDbFile = fileToSynchronize.id?.let { fileRepository.getFileById(it) }
98-
98+
9999 if (localDbFile != null && (localDbFile.remotePath == fileToSynchronize.remotePath && localDbFile.spaceId == fileToSynchronize.spaceId)) {
100100 fileRepository.deleteFiles(listOf (fileToSynchronize), true )
101101 }
@@ -118,7 +118,7 @@ class SynchronizeFileUseCase(
118118 val preferLocal = preferencesProvider.getBoolean(
119119 SettingsSecurityFragment .PREFERENCE_PREFER_LOCAL_ON_CONFLICT , false
120120 )
121-
121+
122122 if (preferLocal) {
123123 // User prefers local version - upload it (overwrites remote)
124124 Timber .i(" File ${fileToSynchronize.fileName} has conflict. User prefers local version, uploading." )
@@ -130,7 +130,7 @@ class SynchronizeFileUseCase(
130130 val conflictedCopyPath = createConflictedCopyPath(fileToSynchronize)
131131 // Fix: Rename safety
132132 val renamed = renameLocalFile(fileToSynchronize.storagePath!! , conflictedCopyPath)
133-
133+
134134 if (renamed) {
135135 Timber .i(" Local file renamed to conflicted copy: $conflictedCopyPath " )
136136 // Refresh parent folder so the conflicted copy appears in the file list
@@ -144,7 +144,7 @@ class SynchronizeFileUseCase(
144144 } catch (e: Exception ) {
145145 Timber .w(e, " Failed to refresh parent folder after creating conflicted copy" )
146146 }
147-
147+
148148 // Only download if renamed successfully
149149 val uuid = requestForDownload(accountName, fileToSynchronize)
150150 SyncType .ConflictResolvedWithCopy (uuid, conflictedCopyPath)
@@ -158,7 +158,7 @@ class SynchronizeFileUseCase(
158158 }
159159 } else if (changedRemotely) {
160160 // 5.2 File has changed ONLY remotely -> download new version
161- // Fix: Check if we have unsaved local changes that we missed?
161+ // Fix: Check if we have unsaved local changes that we missed?
162162 // (Already covered by changedLocally check above)
163163 Timber .i(" File ${fileToSynchronize.fileName} has changed remotely. Let's download the new version" )
164164 val uuid = requestForDownload(accountName, fileToSynchronize)
@@ -208,13 +208,11 @@ class SynchronizeFileUseCase(
208208 return File (file.parent, conflictedName).absolutePath
209209 }
210210
211- private fun renameLocalFile (oldPath : String , newPath : String ): Boolean {
212- return try {
213- File (oldPath).renameTo(File (newPath))
214- } catch (e: Exception ) {
215- Timber .e(e, " Failed to rename local file from $oldPath to $newPath " )
216- false
217- }
211+ private fun renameLocalFile (oldPath : String , newPath : String ): Boolean = try {
212+ File (oldPath).renameTo(File (newPath))
213+ } catch (e: Exception ) {
214+ Timber .e(e, " Failed to rename local file from $oldPath to $newPath " )
215+ false
218216 }
219217
220218 data class Params (
0 commit comments