From 7ef0e538929567177a86f8dfad687588963d9ac6 Mon Sep 17 00:00:00 2001 From: kosyak Date: Sun, 14 Jul 2024 18:05:34 +0200 Subject: [PATCH] use original file name in chat attachements --- .../medialib/activities/EditActivity.kt | 10 ++- .../persistance/FileBackend.java | 23 +++++-- .../conversations/persistance/FileUtils.kt | 61 +++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/persistance/FileUtils.kt diff --git a/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt b/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt index 83a21498b..31d63a408 100644 --- a/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt +++ b/src/main/java/eu/siacs/conversations/medialib/activities/EditActivity.kt @@ -36,6 +36,7 @@ import eu.siacs.conversations.medialib.dialogs.ResizeDialog import eu.siacs.conversations.medialib.extensions.* import eu.siacs.conversations.medialib.helpers.* import eu.siacs.conversations.medialib.models.FilterItem +import eu.siacs.conversations.persistance.name import eu.siacs.conversations.utils.ThemeHelper import java.io.* import java.lang.Float.max @@ -672,7 +673,14 @@ class EditActivity : AppCompatActivity(), CropImageView.OnCropImageCompleteListe } private fun saveBitmapToFile(bitmap: Bitmap, showSavingToast: Boolean) { - val file = File(filesDir, "Images/${UUID.randomUUID()}.jpg") + val name = originalUri?.name(this) ?: UUID.randomUUID().toString() + var file = File(/* parent = */ filesDir, /* child = */ "Images/${name}.jpg") + + var counter = 1 + while (file.exists()) { + file = File(filesDir, "Images/${name}" + "(" + counter + ").jpg") + counter++ + } file.deleteRecursively() file.parentFile?.mkdirs() diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index a794f1bfa..f3bd9149f 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -767,7 +767,14 @@ public class FileBackend { if ("ogg".equals(extension) && type != null && type.startsWith("audio/")) { extension = "oga"; } - setupRelativeFilePath(message, String.format("%s.%s", message.getUuid(), extension)); + + String filenamePrefix = FileUtilsKt.name(uri, mXmppConnectionService); + + if (filenamePrefix.isEmpty()) { + filenamePrefix = message.getUuid(); + } + + setupRelativeFilePath(message, String.format("%s.%s", filenamePrefix, extension)); copyFileToPrivateStorage(mXmppConnectionService.getFileBackend().getFile(message), uri); } @@ -891,19 +898,27 @@ public class FileBackend { public void copyImageToPrivateStorage(Message message, Uri image) throws FileCopyException, ImageCompressionException { final String filename; + + String filenamePrefix = FileUtilsKt.name(image, mXmppConnectionService); + + if (filenamePrefix.isEmpty()) { + filenamePrefix = message.getUuid(); + } + switch (Config.IMAGE_FORMAT) { case JPEG: - filename = String.format("%s.%s", message.getUuid(), "jpg"); + filename = String.format("%s.%s", filenamePrefix, "jpg"); break; case PNG: - filename = String.format("%s.%s", message.getUuid(), "png"); + filename = String.format("%s.%s", filenamePrefix, "png"); break; case WEBP: - filename = String.format("%s.%s", message.getUuid(), "webp"); + filename = String.format("%s.%s", filenamePrefix, "webp"); break; default: throw new IllegalStateException("Unknown image format"); } + setupRelativeFilePath(message, filename); copyImageToPrivateStorage(getFile(message), image); updateFileParams(message); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileUtils.kt b/src/main/java/eu/siacs/conversations/persistance/FileUtils.kt new file mode 100644 index 000000000..9e98a2ccb --- /dev/null +++ b/src/main/java/eu/siacs/conversations/persistance/FileUtils.kt @@ -0,0 +1,61 @@ +package eu.siacs.conversations.persistance + +import android.content.ContentResolver +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns +import androidx.core.net.toFile + +fun Uri.name(context: Context): String { + when (scheme) { + ContentResolver.SCHEME_FILE -> { + return toFile().nameWithoutExtension + } + ContentResolver.SCHEME_CONTENT -> { + val cursor = context.contentResolver.query( + this, + arrayOf(OpenableColumns.DISPLAY_NAME), + null, + null, + null + ) ?: throw Exception("Failed to obtain cursor from the content resolver") + cursor.moveToFirst() + if (cursor.count == 0) { + throw Exception("The given Uri doesn't represent any file") + } + val displayNameColumnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + val displayName = cursor.getString(displayNameColumnIndex) + cursor.close() + return displayName.substringBeforeLast(".") + } + ContentResolver.SCHEME_ANDROID_RESOURCE -> { + // for uris like [android.resource://com.example.app/1234567890] + var resourceId = lastPathSegment?.toIntOrNull() + if (resourceId != null) { + return context.resources.getResourceName(resourceId) + } + // for uris like [android.resource://com.example.app/raw/sample] + val packageName = authority + val resourceType = if (pathSegments.size >= 1) { + pathSegments[0] + } else { + throw Exception("Resource type could not be found") + } + val resourceEntryName = if (pathSegments.size >= 2) { + pathSegments[1] + } else { + throw Exception("Resource entry name could not be found") + } + resourceId = context.resources.getIdentifier( + resourceEntryName, + resourceType, + packageName + ) + return context.resources.getResourceName(resourceId) + } + else -> { + // probably a http uri + return toString().substringBeforeLast(".").substringAfterLast("/") + } + } +} \ No newline at end of file