#1249 fixed copying content URI items

This commit is contained in:
Thibault Deckers 2024-10-29 01:06:46 +01:00
parent ccbca7c506
commit c6ec5afba1
3 changed files with 80 additions and 66 deletions

View file

@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file.
### Fixed
- crash when loading large collection
- Viewer: copying content URI item
## <a id="v1.11.16"></a>[v1.11.16] - 2024-10-10

View file

@ -137,8 +137,7 @@ abstract class ImageProvider {
"success" to false,
)
// prevent naming with a `.` prefix as it would hide the file and remove it from the Media Store
if (sourcePath != null && !desiredName.startsWith('.')) {
if (sourcePath != null) {
try {
var newFields: FieldMap = skippedFieldMap
if (!isCancelledOp()) {
@ -570,6 +569,20 @@ abstract class ImageProvider {
}
}
fun createTimeStampFileName() = Date().time.toString()
private fun sanitizeDesiredFileName(desiredName: String): String {
var name = desiredName
// prevent creating hidden files
while (name.isNotEmpty() && name.startsWith(".")) {
name = name.substring(1)
}
if (name.isEmpty()) {
name = createTimeStampFileName()
}
return name
}
// returns available name to use, or `null` to skip it
suspend fun resolveTargetFileNameWithoutExtension(
contextWrapper: ContextWrapper,
@ -578,18 +591,19 @@ abstract class ImageProvider {
mimeType: String,
conflictStrategy: NameConflictStrategy,
): NameConflictResolution {
var resolvedName: String? = desiredNameWithoutExtension
val sanitizedNameWithoutExtension = sanitizeDesiredFileName(desiredNameWithoutExtension)
var resolvedName: String? = sanitizedNameWithoutExtension
var replacementFile: File? = null
val extension = extensionFor(mimeType)
val targetFile = File(dir, "$desiredNameWithoutExtension$extension")
val targetFile = File(dir, "$sanitizedNameWithoutExtension$extension")
when (conflictStrategy) {
NameConflictStrategy.RENAME -> {
var nameWithoutExtension = desiredNameWithoutExtension
var nameWithoutExtension = sanitizedNameWithoutExtension
var i = 0
while (File(dir, "$nameWithoutExtension$extension").exists()) {
i++
nameWithoutExtension = "$desiredNameWithoutExtension ($i)"
nameWithoutExtension = "$sanitizedNameWithoutExtension ($i)"
}
resolvedName = nameWithoutExtension
}

View file

@ -40,6 +40,7 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.io.SyncFailedException
import java.util.Date
import java.util.Locale
import java.util.concurrent.CompletableFuture
import kotlin.coroutines.Continuation
@ -478,7 +479,6 @@ class MediaStoreImageProvider : ImageProvider() {
"success" to false,
)
if (sourcePath != null) {
// on API 30 we cannot get access granted directly to a volume root from its document tree,
// but it is still less constraining to use tree document files than to rely on the Media Store
//
@ -496,7 +496,7 @@ class MediaStoreImageProvider : ImageProvider() {
// - the Media Store only allows inserting in specific primary directories ("DCIM", "Pictures") when using scoped storage
try {
val appDir = when {
toBin -> StorageUtils.trashDirFor(activity, sourcePath)
toBin -> StorageUtils.trashDirFor(activity, sourcePath ?: StorageUtils.getPrimaryVolumePath(activity))
toVault -> File(targetDir)
else -> null
}
@ -511,8 +511,8 @@ class MediaStoreImageProvider : ImageProvider() {
if (effectiveTargetDir != null) {
val newFields = if (isCancelledOp()) skippedFieldMap else {
val sourceFile = File(sourcePath)
if (!sourceFile.exists() && toBin) {
val sourceFile = if (sourcePath != null) File(sourcePath) else null
if (sourceFile != null && !sourceFile.exists() && toBin) {
delete(activity, sourceUri, sourcePath, mimeType = mimeType)
deletedFieldMap
} else {
@ -522,7 +522,7 @@ class MediaStoreImageProvider : ImageProvider() {
sourceUri = sourceUri,
targetDir = effectiveTargetDir,
targetDirDocFile = targetDirDocFile,
desiredName = desiredName ?: sourceFile.name,
desiredName = desiredName ?: sourceFile?.name ?: sourceUri.lastPathSegment ?: createTimeStampFileName(),
nameConflictStrategy = nameConflictStrategy,
mimeType = mimeType,
copy = copy,
@ -536,7 +536,6 @@ class MediaStoreImageProvider : ImageProvider() {
} catch (e: Exception) {
Log.w(LOG_TAG, "failed to move to targetDir=$targetDir entry with sourcePath=$sourcePath", e)
}
}
callback.onSuccess(result)
}
}
@ -544,7 +543,7 @@ class MediaStoreImageProvider : ImageProvider() {
private suspend fun moveSingle(
activity: Activity,
sourceFile: File,
sourceFile: File?,
sourceUri: Uri,
targetDir: String,
targetDirDocFile: DocumentFileCompat?,
@ -554,8 +553,8 @@ class MediaStoreImageProvider : ImageProvider() {
copy: Boolean,
toBin: Boolean,
): FieldMap {
val sourcePath = sourceFile.path
val sourceDir = sourceFile.parent?.let { ensureTrailingSeparator(it) }
val sourcePath = sourceFile?.path
val sourceDir = sourceFile?.parent?.let { ensureTrailingSeparator(it) }
if (sourceDir == targetDir && !(copy && nameConflictStrategy == NameConflictStrategy.RENAME)) {
// nothing to do unless it's a renamed copy
return skippedFieldMap