Skip to content

Commit 0c93a95

Browse files
Implemented file conflict name generator specific for offlineOperations
Signed-off-by: daniele-verducci <daniele.verducci@nextcloud.com>
1 parent a6ab15a commit 0c93a95

2 files changed

Lines changed: 52 additions & 9 deletions

File tree

app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ import com.nextcloud.client.database.entity.model.ShareeKey
1212
import com.nextcloud.client.database.entity.toOCCapability
1313
import com.owncloud.android.datamodel.FileDataStorageManager
1414
import com.owncloud.android.datamodel.OCFile
15+
import com.owncloud.android.lib.common.OwnCloudClient
1516
import com.owncloud.android.lib.common.utils.Log_OC
17+
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation
1618
import com.owncloud.android.lib.resources.files.model.RemoteFile
1719
import com.owncloud.android.lib.resources.shares.OCShare
1820
import com.owncloud.android.lib.resources.status.OCCapability
21+
import com.owncloud.android.operations.upload.RemoteFileExistence
1922
import com.owncloud.android.utils.FileStorageUtils
2023
import com.owncloud.android.utils.MimeTypeUtil
2124
import kotlinx.coroutines.Dispatchers
@@ -185,6 +188,49 @@ fun FileDataStorageManager.moveFiles(ocFile: OCFile?, targetPath: String, target
185188
}
186189
}
187190

191+
/**
192+
* Finds a suitable file name to resolve a conflict.
193+
* Tries to concatenate a number to the name until it finds a non-existent one.
194+
* E.g. for "file.txt" it will propose "file (2).txt". If that exists, then "file (3).txt" and so on.
195+
* E.g. for "folder" it will propose "folder (2)/". If that exists, then "folder (3)/" and so on.
196+
*
197+
* @return the new remote path, or null if the user is unauthorized in the provided path
198+
*/
199+
fun getRemotePathForConflictResolution(client: OwnCloudClient, remotePath: String, fileName: String): String? {
200+
val newName = generateFileNameForConflictResolution(fileName)
201+
val newPath = "$remotePath$newName"
202+
203+
// Check if new name exists
204+
val operation = ExistenceCheckRemoteOperation(newPath, false)
205+
val existence = RemoteFileExistence.fromExistenceCheck(operation.execute(client))
206+
if (existence == RemoteFileExistence.UNAUTHORIZED)
207+
return null
208+
if (existence == RemoteFileExistence.DOES_NOT_EXIST)
209+
return newPath
210+
return getRemotePathForConflictResolution(client, remotePath, newName)
211+
}
212+
213+
fun generateFileNameForConflictResolution(fileName: String): String {
214+
val isFolder = fileName.endsWith(OCFile.PATH_SEPARATOR)
215+
val separator = if (isFolder) OCFile.PATH_SEPARATOR else "."
216+
var nameFirstPart = fileName.substringBeforeLast(separator)
217+
var nameLastPart = fileName.substringAfterLast(separator, "") // Extension or path separator
218+
if (nameLastPart.isNotEmpty()) nameLastPart = "$separator$nameLastPart"
219+
val regex = Regex("""(.*)\((\d+)\)$""", RegexOption.MULTILINE)
220+
if (regex.matches(nameFirstPart)) {
221+
// Already a resolved conflict (i.e. "file (1).txt"). Update the number.
222+
nameFirstPart = regex.replace(nameFirstPart, transform = { m ->
223+
val baseName = m.groups[1]?.value
224+
val number = m.groups[2]?.value?.toInt() ?: 0
225+
"$baseName(${number + 1})"
226+
})
227+
} else {
228+
// Add the number
229+
nameFirstPart = "$nameFirstPart (1)"
230+
}
231+
return "$nameFirstPart$nameLastPart"
232+
}
233+
188234
@Suppress("ReturnCount")
189235
private fun moveLocalFiles(accountName: String, ocFile: OCFile, defaultSavePath: String, targetPath: String): Boolean {
190236
val localFile = File(FileStorageUtils.getDefaultSavePathFor(accountName, ocFile))

app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -362,17 +362,14 @@ public void keepOfflineOperationAndServerFile(OfflineOperationEntity entity, OCF
362362
String oldFileName = entity.getFilename();
363363
if (oldFileName == null) return;
364364

365-
Long parentOCFileId = entity.getParentOCFileId();
366-
if (parentOCFileId == null) return;
367-
368-
OCFile parentFolder = getFileById(parentOCFileId);
369-
if (parentFolder == null) return;
365+
String parentRemotePath = file.getParentRemotePath();
366+
if (parentRemotePath == null || parentRemotePath.isEmpty())
367+
return;
370368

371-
final String newPath = UploadFileOperation.getNewAvailableRemotePath(
369+
final String newPath = FileDataStorageManagerExtensionsKt.getRemotePathForConflictResolution(
372370
client,
373-
(entity.getPath() != null) ? entity.getPath() : file.getDecryptedRemotePath(),
374-
List.of(oldFileName),
375-
file.isEncrypted()
371+
parentRemotePath,
372+
oldFileName
376373
);
377374
offlineOperationsRepository.updateOperationForKeepBoth(entity, newPath);
378375
}

0 commit comments

Comments
 (0)