diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml
index 8bf33df0ac..16cc35cebe 100644
--- a/.idea/dictionaries/bmarty.xml
+++ b/.idea/dictionaries/bmarty.xml
@@ -25,6 +25,7 @@
pids
pkcs
previewable
+ previewables
riotx
signin
signout
diff --git a/CHANGES.md b/CHANGES.md
index 2be9d31cf8..f39242ed62 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -16,6 +16,8 @@ Bugfix 🐛:
- Fix cancellation of sending event (#2438)
- Double bottomsheet effect after verify with passphrase
- EditText cursor jumps to the start while typing fast (#2469)
+ - Show preview when sending attachment from the keyboard (#2440)
+ - Do not compress GIFs (#1616, #1254)
Translations 🗣:
-
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt
index 4677c2be32..4164b84ecd 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentAttachmentData.kt
@@ -21,6 +21,7 @@ import android.os.Parcelable
import androidx.exifinterface.media.ExifInterface
import com.squareup.moshi.JsonClass
import kotlinx.android.parcel.Parcelize
+import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
@Parcelize
@JsonClass(generateAdapter = true)
@@ -45,5 +46,5 @@ data class ContentAttachmentData(
VIDEO
}
- fun getSafeMimeType() = if (mimeType == "image/jpg") "image/jpeg" else mimeType
+ fun getSafeMimeType() = mimeType?.normalizeMimeType()
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt
index 859f7fd104..73e27b64e3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/message/MessageImageContent.kt
@@ -20,6 +20,7 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
@JsonClass(generateAdapter = true)
@@ -54,5 +55,5 @@ data class MessageImageContent(
@Json(name = "file") override val encryptedFileInfo: EncryptedFileInfo? = null
) : MessageImageInfoContent {
override val mimeType: String?
- get() = encryptedFileInfo?.mimetype ?: info?.mimeType ?: "image/*"
+ get() = encryptedFileInfo?.mimetype ?: info?.mimeType ?: MimeTypes.Images
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt
new file mode 100644
index 0000000000..c74999b4ab
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/MimeTypes.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Matrix.org Foundation C.I.C.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.matrix.android.sdk.api.util
+
+import org.matrix.android.sdk.api.extensions.orFalse
+
+// The Android SDK does not provide constant for mime type, add some of them here
+object MimeTypes {
+ const val Any: String = "*/*"
+ const val OctetStream = "application/octet-stream"
+
+ const val Images = "image/*"
+
+ const val Png = "image/png"
+ const val BadJpg = "image/jpg"
+ const val Jpeg = "image/jpeg"
+ const val Gif = "image/gif"
+
+ fun String?.normalizeMimeType() = if (this == BadJpg) Jpeg else this
+
+ fun String?.isMimeTypeImage() = this?.startsWith("image/").orFalse()
+ fun String?.isMimeTypeVideo() = this?.startsWith("video/").orFalse()
+ fun String?.isMimeTypeAudio() = this?.startsWith("audio/").orFalse()
+}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
index 8c3aad6a1f..4b31db59b1 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
+import org.matrix.android.sdk.api.util.MimeTypes
import timber.log.Timber
import java.io.ByteArrayOutputStream
@@ -58,7 +59,7 @@ internal object ThumbnailExtractor {
height = thumbnailHeight,
size = thumbnailSize.toLong(),
bytes = outputStream.toByteArray(),
- mimeType = "image/jpeg"
+ mimeType = MimeTypes.Jpeg
)
thumbnail.recycle()
outputStream.reset()
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
index 77f39a7768..672d407d25 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt
@@ -29,6 +29,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments
import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
@@ -151,7 +152,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
params.attachment.size
)
- if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) {
+ if (attachment.type == ContentAttachmentData.Type.IMAGE
+ // Do not compress gif
+ && attachment.mimeType != MimeTypes.Gif
+ && params.compressBeforeSending) {
fileToUpload = imageCompressor.compress(context, workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
.also { compressedFile ->
// Get new Bitmap size
@@ -191,7 +195,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
Timber.v("## FileService: Uploading file")
fileUploader
- .uploadFile(encryptedFile, attachment.name, "application/octet-stream", progressListener)
+ .uploadFile(encryptedFile, attachment.name, MimeTypes.OctetStream, progressListener)
} else {
Timber.v("## FileService: Clear file")
encryptedFile = null
@@ -258,7 +262,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType)
val contentUploadResponse = fileUploader.uploadByteArray(encryptionResult.encryptedByteArray,
"thumb_${params.attachment.name}",
- "application/octet-stream",
+ MimeTypes.OctetStream,
thumbnailProgressListener)
UploadThumbnailResult(
contentUploadResponse.contentUri,
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
index 5265e4f17d..500d43408e 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.identity.ThreePid
import org.matrix.android.sdk.api.session.profile.ProfileService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity
import org.matrix.android.sdk.internal.database.model.UserThreePidEntity
@@ -80,7 +81,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto
override fun updateAvatar(userId: String, newAvatarUri: Uri, fileName: String, matrixCallback: MatrixCallback): Cancelable {
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, matrixCallback) {
- val response = fileUploader.uploadFromUri(newAvatarUri, fileName, "image/jpeg")
+ val response = fileUploader.uploadFromUri(newAvatarUri, fileName, MimeTypes.Jpeg)
setAvatarUrlTask.execute(SetAvatarUrlTask.Params(userId = userId, newAvatarUrl = response.contentUri))
userStore.updateAvatar(userId, response.contentUri)
}
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
index 79ff9db087..fb840b4eb3 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
@@ -96,7 +97,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
fileUploader.uploadFromUri(
uri = avatarUri,
filename = UUID.randomUUID().toString(),
- mimeType = "image/jpeg")
+ mimeType = MimeTypes.Jpeg)
}
?.let { response ->
Event(
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
index 6015d945c4..a93ec8e797 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/state/DefaultStateService.kt
@@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.api.session.room.state.StateService
import org.matrix.android.sdk.api.util.Cancelable
import org.matrix.android.sdk.api.util.JsonDict
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.session.content.FileUploader
import org.matrix.android.sdk.internal.session.room.alias.AddRoomAliasTask
@@ -164,7 +165,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback): Cancelable {
return taskExecutor.executorScope.launchToCallback(coroutineDispatchers.main, callback) {
- val response = fileUploader.uploadFromUri(avatarUri, fileName, "image/jpeg")
+ val response = fileUploader.uploadFromUri(avatarUri, fileName, MimeTypes.Jpeg)
awaitCallback {
sendStateEvent(
eventType = EventType.STATE_ROOM_AVATAR,
diff --git a/vector/src/main/java/im/vector/app/core/resources/ResourceUtils.kt b/vector/src/main/java/im/vector/app/core/resources/ResourceUtils.kt
index 7ab2271c57..f14c9b834d 100644
--- a/vector/src/main/java/im/vector/app/core/resources/ResourceUtils.kt
+++ b/vector/src/main/java/im/vector/app/core/resources/ResourceUtils.kt
@@ -20,17 +20,11 @@ import android.content.Context
import android.net.Uri
import android.webkit.MimeTypeMap
import im.vector.app.core.utils.getFileExtension
+import org.matrix.android.sdk.api.util.MimeTypes
+import org.matrix.android.sdk.api.util.MimeTypes.normalizeMimeType
import timber.log.Timber
import java.io.InputStream
-/**
- * Mime types
- */
-const val MIME_TYPE_JPEG = "image/jpeg"
-const val MIME_TYPE_JPG = "image/jpg"
-const val MIME_TYPE_IMAGE_ALL = "image/*"
-const val MIME_TYPE_ALL_CONTENT = "*/*"
-
data class Resource(
var mContentStream: InputStream? = null,
var mMimeType: String? = null
@@ -55,7 +49,7 @@ data class Resource(
* @return true if the opened resource is a jpeg one.
*/
fun isJpegResource(): Boolean {
- return MIME_TYPE_JPEG == mMimeType || MIME_TYPE_JPG == mMimeType
+ return mMimeType.normalizeMimeType() == MimeTypes.Jpeg
}
}
diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
index 4c6aa51348..45db8ea91d 100644
--- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
+++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt
@@ -48,6 +48,10 @@ import okio.buffer
import okio.sink
import okio.source
import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.util.MimeTypes
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeAudio
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeVideo
import timber.log.Timber
import java.io.File
import java.io.FileInputStream
@@ -138,7 +142,7 @@ fun openFileSelection(activity: Activity,
fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultipleSelection)
fileIntent.addCategory(Intent.CATEGORY_OPENABLE)
- fileIntent.type = "*/*"
+ fileIntent.type = MimeTypes.Any
try {
activityResultLauncher
@@ -182,7 +186,7 @@ fun openCamera(activity: Activity, titlePrefix: String, requestCode: Int): Strin
// The Galaxy S not only requires the name of the file to output the image to, but will also not
// set the mime type of the picture it just took (!!!). We assume that the Galaxy S takes image/jpegs
// so the attachment uploader doesn't freak out about there being no mimetype in the content database.
- values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
+ values.put(MediaStore.Images.Media.MIME_TYPE, MimeTypes.Jpeg)
var dummyUri: Uri? = null
try {
dummyUri = activity.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
@@ -344,10 +348,10 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
}
val externalContentUri = when {
- mediaMimeType?.startsWith("image/") == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
- mediaMimeType?.startsWith("video/") == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
- mediaMimeType?.startsWith("audio/") == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
- else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
+ mediaMimeType?.isMimeTypeImage() == true -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+ mediaMimeType?.isMimeTypeVideo() == true -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+ mediaMimeType?.isMimeTypeAudio() == true -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+ else -> MediaStore.Downloads.EXTERNAL_CONTENT_URI
}
val uri = context.contentResolver.insert(externalContentUri, values)
@@ -365,7 +369,7 @@ fun saveMedia(context: Context, file: File, title: String, mediaMimeType: String
notificationUtils.buildDownloadFileNotification(
uri,
filename,
- mediaMimeType ?: "application/octet-stream"
+ mediaMimeType ?: MimeTypes.OctetStream
).let { notification ->
notificationUtils.showNotificationMessage("DL", uri.hashCode(), notification)
}
@@ -385,10 +389,10 @@ private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: Str
GlobalScope.launch(Dispatchers.IO) {
val dest = when {
- mediaMimeType?.startsWith("image/") == true -> Environment.DIRECTORY_PICTURES
- mediaMimeType?.startsWith("video/") == true -> Environment.DIRECTORY_MOVIES
- mediaMimeType?.startsWith("audio/") == true -> Environment.DIRECTORY_MUSIC
- else -> Environment.DIRECTORY_DOWNLOADS
+ mediaMimeType?.isMimeTypeImage() == true -> Environment.DIRECTORY_PICTURES
+ mediaMimeType?.isMimeTypeVideo() == true -> Environment.DIRECTORY_MOVIES
+ mediaMimeType?.isMimeTypeAudio() == true -> Environment.DIRECTORY_MUSIC
+ else -> Environment.DIRECTORY_DOWNLOADS
}
val downloadDir = Environment.getExternalStoragePublicDirectory(dest)
try {
@@ -405,7 +409,7 @@ private fun saveMediaLegacy(context: Context, mediaMimeType: String?, title: Str
savedFile.name,
title,
true,
- mediaMimeType ?: "application/octet-stream",
+ mediaMimeType ?: MimeTypes.OctetStream,
savedFile.absolutePath,
savedFile.length(),
true)
diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsMapper.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsMapper.kt
index 9c9d8f8017..4e8dcaacb7 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsMapper.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsMapper.kt
@@ -23,6 +23,9 @@ import im.vector.lib.multipicker.entity.MultiPickerFileType
import im.vector.lib.multipicker.entity.MultiPickerImageType
import im.vector.lib.multipicker.entity.MultiPickerVideoType
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeAudio
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeVideo
import timber.log.Timber
fun MultiPickerContactType.toContactAttachment(): ContactAttachment {
@@ -59,10 +62,10 @@ fun MultiPickerAudioType.toContentAttachmentData(): ContentAttachmentData {
private fun MultiPickerBaseType.mapType(): ContentAttachmentData.Type {
return when {
- mimeType?.startsWith("image/") == true -> ContentAttachmentData.Type.IMAGE
- mimeType?.startsWith("video/") == true -> ContentAttachmentData.Type.VIDEO
- mimeType?.startsWith("audio/") == true -> ContentAttachmentData.Type.AUDIO
- else -> ContentAttachmentData.Type.FILE
+ mimeType?.isMimeTypeImage() == true -> ContentAttachmentData.Type.IMAGE
+ mimeType?.isMimeTypeVideo() == true -> ContentAttachmentData.Type.VIDEO
+ mimeType?.isMimeTypeAudio() == true -> ContentAttachmentData.Type.AUDIO
+ else -> ContentAttachmentData.Type.FILE
}
}
diff --git a/vector/src/main/java/im/vector/app/features/attachments/ContentAttachmentData.kt b/vector/src/main/java/im/vector/app/features/attachments/ContentAttachmentData.kt
index bd13c0dac4..e35ab96365 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/ContentAttachmentData.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/ContentAttachmentData.kt
@@ -17,11 +17,19 @@
package im.vector.app.features.attachments
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
+import org.matrix.android.sdk.api.util.MimeTypes
+
+private val listOfPreviewableMimeTypes = listOf(
+ MimeTypes.Jpeg,
+ MimeTypes.BadJpg,
+ MimeTypes.Png,
+ MimeTypes.Gif
+)
fun ContentAttachmentData.isPreviewable(): Boolean {
// For now the preview only supports still image
return type == ContentAttachmentData.Type.IMAGE
- && listOf("image/jpeg", "image/png", "image/jpg").contains(getSafeMimeType() ?: "")
+ && listOfPreviewableMimeTypes.contains(getSafeMimeType() ?: "")
}
data class GroupedContentAttachmentData(
diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/Extensions.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/Extensions.kt
index bd06f8cf0b..853f9f8997 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/preview/Extensions.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/preview/Extensions.kt
@@ -17,12 +17,14 @@
package im.vector.app.features.attachments.preview
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
+import org.matrix.android.sdk.api.util.MimeTypes
+import org.matrix.android.sdk.api.util.MimeTypes.isMimeTypeImage
/**
* All images are editable, expect Gif
*/
fun ContentAttachmentData.isEditable(): Boolean {
return type == ContentAttachmentData.Type.IMAGE
- && getSafeMimeType()?.startsWith("image/") == true
- && getSafeMimeType() != "image/gif"
+ && getSafeMimeType()?.isMimeTypeImage() == true
+ && getSafeMimeType() != MimeTypes.Gif
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index 8f24d7964a..aff29bb7a3 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -166,7 +166,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_detail.*
-import kotlinx.android.synthetic.main.merge_composer_layout.view.*
+import kotlinx.android.synthetic.main.composer_layout.view.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser
@@ -1101,18 +1101,6 @@ class RoomDetailFragment @Inject constructor(
}
}
- private val writingFileActivityResultLauncher = registerForPermissionsResult { allGranted ->
- if (allGranted) {
- val pendingUri = roomDetailViewModel.pendingUri
- if (pendingUri != null) {
- roomDetailViewModel.pendingUri = null
- sendUri(pendingUri)
- }
- } else {
- cleanUpAfterPermissionNotGranted()
- }
- }
-
private fun setupComposer() {
val composerEditText = composerLayout.composerEditText
autoCompleter.setup(composerEditText)
@@ -1158,14 +1146,7 @@ class RoomDetailFragment @Inject constructor(
}
override fun onRichContentSelected(contentUri: Uri): Boolean {
- // We need WRITE_EXTERNAL permission
- return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), writingFileActivityResultLauncher)) {
- sendUri(contentUri)
- } else {
- roomDetailViewModel.pendingUri = contentUri
- // Always intercept when we request some permission
- true
- }
+ return sendUri(contentUri)
}
}
}
@@ -1196,11 +1177,9 @@ class RoomDetailFragment @Inject constructor(
}
private fun sendUri(uri: Uri): Boolean {
- roomDetailViewModel.preventAttachmentPreview = true
val shareIntent = Intent(Intent.ACTION_SEND, uri)
val isHandled = attachmentsHelper.handleShareIntent(requireContext(), shareIntent)
if (!isHandled) {
- roomDetailViewModel.preventAttachmentPreview = false
Toast.makeText(requireContext(), R.string.error_handling_incoming_share, Toast.LENGTH_SHORT).show()
}
return isHandled
@@ -1562,7 +1541,6 @@ class RoomDetailFragment @Inject constructor(
private fun cleanUpAfterPermissionNotGranted() {
// Reset all pending data
roomDetailViewModel.pendingAction = null
- roomDetailViewModel.pendingUri = null
attachmentsHelper.pendingType = null
}
@@ -1969,24 +1947,18 @@ class RoomDetailFragment @Inject constructor(
// AttachmentsHelper.Callback
override fun onContentAttachmentsReady(attachments: List) {
- if (roomDetailViewModel.preventAttachmentPreview) {
- roomDetailViewModel.preventAttachmentPreview = false
- roomDetailViewModel.handle(RoomDetailAction.SendMedia(attachments, false))
- } else {
- val grouped = attachments.toGroupedContentAttachmentData()
- if (grouped.notPreviewables.isNotEmpty()) {
- // Send the not previewable attachments right now (?)
- roomDetailViewModel.handle(RoomDetailAction.SendMedia(grouped.notPreviewables, false))
- }
- if (grouped.previewables.isNotEmpty()) {
- val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(grouped.previewables))
- contentAttachmentActivityResultLauncher.launch(intent)
- }
+ val grouped = attachments.toGroupedContentAttachmentData()
+ if (grouped.notPreviewables.isNotEmpty()) {
+ // Send the not previewable attachments right now (?)
+ roomDetailViewModel.handle(RoomDetailAction.SendMedia(grouped.notPreviewables, false))
+ }
+ if (grouped.previewables.isNotEmpty()) {
+ val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(grouped.previewables))
+ contentAttachmentActivityResultLauncher.launch(intent)
}
}
override fun onAttachmentsProcessFailed() {
- roomDetailViewModel.preventAttachmentPreview = false
Toast.makeText(requireContext(), R.string.error_attachment, Toast.LENGTH_SHORT).show()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
index 3b854f8b40..14085a58a6 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt
@@ -132,12 +132,6 @@ class RoomDetailViewModel @AssistedInject constructor(
// Slot to keep a pending action during permission request
var pendingAction: RoomDetailAction? = null
- // Slot to keep a pending uri during permission request
- var pendingUri: Uri? = null
-
- // Slot to store if we want to prevent preview of attachment
- var preventAttachmentPreview = false
-
private var trackUnreadMessages = AtomicBoolean(false)
private var mostRecentDisplayedEvent: TimelineEvent? = null
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt
index af0e1a91f0..f232e9a65e 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/TextComposerView.kt
@@ -36,7 +36,7 @@ import androidx.transition.TransitionSet
import butterknife.BindView
import butterknife.ButterKnife
import im.vector.app.R
-import kotlinx.android.synthetic.main.merge_composer_layout.view.*
+import kotlinx.android.synthetic.main.composer_layout.view.*
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
/**
@@ -86,7 +86,7 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
get() = composerEditText.text
init {
- inflate(context, R.layout.merge_composer_layout, this)
+ inflate(context, R.layout.composer_layout, this)
ButterKnife.bind(this)
collapse(false)
composerEditText.callback = object : ComposerEditText.Callback {
@@ -110,20 +110,20 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
}
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
- if (currentConstraintSetId == R.layout.constraint_set_composer_layout_compact) {
+ if (currentConstraintSetId == R.layout.composer_layout_constraint_set_compact) {
// ignore we good
return
}
- currentConstraintSetId = R.layout.constraint_set_composer_layout_compact
+ currentConstraintSetId = R.layout.composer_layout_constraint_set_compact
applyNewConstraintSet(animate, transitionComplete)
}
fun expand(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
- if (currentConstraintSetId == R.layout.constraint_set_composer_layout_expanded) {
+ if (currentConstraintSetId == R.layout.composer_layout_constraint_set_expanded) {
// ignore we good
return
}
- currentConstraintSetId = R.layout.constraint_set_composer_layout_expanded
+ currentConstraintSetId = R.layout.composer_layout_constraint_set_expanded
applyNewConstraintSet(animate, transitionComplete)
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index 05611995a8..27696f5b28 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -88,6 +88,7 @@ import org.matrix.android.sdk.api.session.room.model.message.getFileName
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent
import javax.inject.Inject
@@ -311,7 +312,7 @@ class MessageItemFactory @Inject constructor(
.leftGuideline(avatarSizeProvider.leftGuideline)
.imageContentRenderer(imageContentRenderer)
.contentUploadStateTrackerBinder(contentUploadStateTrackerBinder)
- .playable(messageContent.info?.mimeType == "image/gif")
+ .playable(messageContent.info?.mimeType == MimeTypes.Gif)
.highlighted(highlight)
.mediaData(data)
.apply {
diff --git a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
index 584b13f32b..328d8f943e 100644
--- a/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/media/DataAttachmentRoomProvider.kt
@@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+import org.matrix.android.sdk.api.util.MimeTypes
import java.io.File
class DataAttachmentRoomProvider(
@@ -38,7 +39,7 @@ class DataAttachmentRoomProvider(
return getItem(position).let {
when (it) {
is ImageContentRenderer.Data -> {
- if (it.mimeType == "image/gif") {
+ if (it.mimeType == MimeTypes.Gif) {
AttachmentInfo.AnimatedImage(
uid = it.eventId,
url = it.url ?: "",
diff --git a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
index 569d006fba..53c5dac9ad 100644
--- a/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/media/RoomEventsAttachmentProvider.kt
@@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt
import java.io.File
@@ -56,7 +57,7 @@ class RoomEventsAttachmentProvider(
allowNonMxcUrls = it.root.sendState.isSending()
)
- if (content.mimeType == "image/gif") {
+ if (content.mimeType == MimeTypes.Gif) {
AttachmentInfo.AnimatedImage(
uid = it.eventId,
url = content.url ?: "",
diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt
index 96248187aa..7be7624a48 100755
--- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt
+++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt
@@ -46,6 +46,7 @@ import okhttp3.Response
import org.json.JSONException
import org.json.JSONObject
import org.matrix.android.sdk.api.Matrix
+import org.matrix.android.sdk.api.util.MimeTypes
import timber.log.Timber
import java.io.File
import java.io.IOException
@@ -274,7 +275,7 @@ class BugReporter @Inject constructor(
// add the gzipped files
for (file in gzippedFiles) {
- builder.addFormDataPart("compressed-log", file.name, file.asRequestBody("application/octet-stream".toMediaTypeOrNull()))
+ builder.addFormDataPart("compressed-log", file.name, file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
}
mBugReportFiles.addAll(gzippedFiles)
@@ -295,7 +296,7 @@ class BugReporter @Inject constructor(
}
builder.addFormDataPart("file",
- logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody("application/octet-stream".toMediaTypeOrNull()))
+ logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
} catch (e: Exception) {
Timber.e(e, "## sendBugReport() : fail to write screenshot$e")
}
diff --git a/vector/src/main/res/drawable/bg_send.xml b/vector/src/main/res/drawable/bg_send.xml
index 4b357d7ab1..8ab95bf5c5 100644
--- a/vector/src/main/res/drawable/bg_send.xml
+++ b/vector/src/main/res/drawable/bg_send.xml
@@ -1,6 +1,10 @@
- -
+
-
diff --git a/vector/src/main/res/layout/merge_composer_layout.xml b/vector/src/main/res/layout/composer_layout.xml
similarity index 97%
rename from vector/src/main/res/layout/merge_composer_layout.xml
rename to vector/src/main/res/layout/composer_layout.xml
index ea2bc1bf30..cb0b37d844 100644
--- a/vector/src/main/res/layout/merge_composer_layout.xml
+++ b/vector/src/main/res/layout/composer_layout.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- tools:constraintSet="@layout/constraint_set_composer_layout_compact"
+ tools:constraintSet="@layout/composer_layout_constraint_set_compact"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/constraint_set_composer_layout_compact.xml b/vector/src/main/res/layout/composer_layout_constraint_set_compact.xml
similarity index 88%
rename from vector/src/main/res/layout/constraint_set_composer_layout_compact.xml
rename to vector/src/main/res/layout/composer_layout_constraint_set_compact.xml
index 6b9fbd4885..a4dfcf019c 100644
--- a/vector/src/main/res/layout/constraint_set_composer_layout_compact.xml
+++ b/vector/src/main/res/layout/composer_layout_constraint_set_compact.xml
@@ -10,7 +10,7 @@
app:layout_constraintStart_toStartOf="parent">
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml b/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml
similarity index 89%
rename from vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml
rename to vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml
index f52b072ece..8a76c0547e 100644
--- a/vector/src/main/res/layout/constraint_set_composer_layout_expanded.xml
+++ b/vector/src/main/res/layout/composer_layout_constraint_set_expanded.xml
@@ -10,7 +10,7 @@
app:layout_constraintStart_toStartOf="parent">
+ app:layout_constraintEnd_toEndOf="@id/related_message_background"
+ app:layout_constraintStart_toStartOf="@+id/related_message_background"
+ app:layout_constraintTop_toTopOf="@id/related_message_background" />
+ app:layout_constraintBottom_toBottomOf="@id/related_message_background"
+ app:layout_constraintEnd_toEndOf="@id/related_message_background"
+ app:layout_constraintStart_toStartOf="@+id/related_message_background" />
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file