Compress image before sending
This commit is contained in:
parent
385fa317c0
commit
e6bd09859f
|
@ -119,6 +119,7 @@ dependencies {
|
|||
|
||||
// Image
|
||||
implementation 'androidx.exifinterface:exifinterface:1.1.0'
|
||||
implementation 'id.zelory:compressor:3.0.0'
|
||||
|
||||
// Database
|
||||
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
|
||||
|
|
|
@ -51,26 +51,24 @@ interface SendService {
|
|||
/**
|
||||
* Method to send a media asynchronously.
|
||||
* @param attachment the media to send
|
||||
* @param compressBeforeSending set to true to compress media before sending them
|
||||
* @param compressBeforeSending set to true to compress images before sending them
|
||||
* @param roomIds set of roomIds to where the media will be sent. The current roomId will be add to this set if not present.
|
||||
* It can be useful to send media to multiple room. It's safe to include the current roomId in this set
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendMedia(attachment: ContentAttachmentData,
|
||||
// TODO Change to a Compression Level Enum
|
||||
compressBeforeSending: Boolean,
|
||||
roomIds: Set<String>): Cancelable
|
||||
|
||||
/**
|
||||
* Method to send a list of media asynchronously.
|
||||
* @param attachments the list of media to send
|
||||
* @param compressBeforeSending set to true to compress media before sending them
|
||||
* @param compressBeforeSending set to true to compress images before sending them
|
||||
* @param roomIds set of roomIds to where the media will be sent. The current roomId will be add to this set if not present.
|
||||
* It can be useful to send media to multiple room. It's safe to include the current roomId in this set
|
||||
* @return a [Cancelable]
|
||||
*/
|
||||
fun sendMedias(attachments: List<ContentAttachmentData>,
|
||||
// TODO Change to a Compression Level Enum
|
||||
compressBeforeSending: Boolean,
|
||||
roomIds: Set<String>): Cancelable
|
||||
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
package im.vector.matrix.android.internal.session.content
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import id.zelory.compressor.Compressor
|
||||
import id.zelory.compressor.constraint.default
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
|
@ -42,7 +45,13 @@ import java.io.File
|
|||
import java.io.FileInputStream
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class UploadContentWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||
private data class NewImageAttributes(
|
||||
val newWidth: Int?,
|
||||
val newHeight: Int?,
|
||||
val newFileSize: Int
|
||||
)
|
||||
|
||||
internal class UploadContentWorker(val context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
|
@ -73,6 +82,8 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
|
||||
val attachment = params.attachment
|
||||
|
||||
var newImageAttributes: NewImageAttributes? = null
|
||||
|
||||
val attachmentFile = try {
|
||||
File(attachment.path)
|
||||
} catch (e: Exception) {
|
||||
|
@ -88,8 +99,35 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
))
|
||||
)
|
||||
}
|
||||
.let {originalFile ->
|
||||
if (attachment.type == ContentAttachmentData.Type.IMAGE) {
|
||||
if (params.compressBeforeSending) {
|
||||
Compressor.compress(context, originalFile) {
|
||||
default(
|
||||
width = MAX_IMAGE_SIZE,
|
||||
height = MAX_IMAGE_SIZE
|
||||
)
|
||||
}.also { compressedFile ->
|
||||
// Update the params
|
||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
BitmapFactory.decodeFile(compressedFile.absolutePath, options)
|
||||
val fileSize = compressedFile.length().toInt()
|
||||
|
||||
// TODO Use compressBeforeSending
|
||||
newImageAttributes = NewImageAttributes(
|
||||
options.outWidth,
|
||||
options.outHeight,
|
||||
fileSize
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// TODO Fix here the image rotation issue
|
||||
originalFile
|
||||
}
|
||||
} else {
|
||||
// Other type
|
||||
originalFile
|
||||
}
|
||||
}
|
||||
|
||||
var uploadedThumbnailUrl: String? = null
|
||||
var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null
|
||||
|
@ -168,7 +206,12 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
.uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener)
|
||||
}
|
||||
|
||||
handleSuccess(params, contentUploadResponse.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo)
|
||||
handleSuccess(params,
|
||||
contentUploadResponse.contentUri,
|
||||
uploadedFileEncryptedFileInfo,
|
||||
uploadedThumbnailUrl,
|
||||
uploadedThumbnailEncryptedFileInfo,
|
||||
newImageAttributes)
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t)
|
||||
handleFailure(params, t)
|
||||
|
@ -195,7 +238,8 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
attachmentUrl: String,
|
||||
encryptedFileInfo: EncryptedFileInfo?,
|
||||
thumbnailUrl: String?,
|
||||
thumbnailEncryptedFileInfo: EncryptedFileInfo?): Result {
|
||||
thumbnailEncryptedFileInfo: EncryptedFileInfo?,
|
||||
newImageAttributes: NewImageAttributes?): Result {
|
||||
Timber.v("handleSuccess $attachmentUrl, work is stopped $isStopped")
|
||||
params.events
|
||||
.mapNotNull { it.eventId }
|
||||
|
@ -205,7 +249,7 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
|
||||
val updatedEvents = params.events
|
||||
.map {
|
||||
updateEvent(it, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo)
|
||||
updateEvent(it, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newImageAttributes)
|
||||
}
|
||||
|
||||
val sendParams = MultipleEventSendingDispatcherWorker.Params(params.sessionId, updatedEvents, params.isRoomEncrypted)
|
||||
|
@ -216,10 +260,11 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
url: String,
|
||||
encryptedFileInfo: EncryptedFileInfo?,
|
||||
thumbnailUrl: String? = null,
|
||||
thumbnailEncryptedFileInfo: EncryptedFileInfo?): Event {
|
||||
thumbnailEncryptedFileInfo: EncryptedFileInfo?,
|
||||
newImageAttributes: NewImageAttributes?): Event {
|
||||
val messageContent: MessageContent = event.content.toModel() ?: return event
|
||||
val updatedContent = when (messageContent) {
|
||||
is MessageImageContent -> messageContent.update(url, encryptedFileInfo)
|
||||
is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newImageAttributes)
|
||||
is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo)
|
||||
is MessageFileContent -> messageContent.update(url, encryptedFileInfo)
|
||||
is MessageAudioContent -> messageContent.update(url, encryptedFileInfo)
|
||||
|
@ -229,10 +274,16 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
}
|
||||
|
||||
private fun MessageImageContent.update(url: String,
|
||||
encryptedFileInfo: EncryptedFileInfo?): MessageImageContent {
|
||||
encryptedFileInfo: EncryptedFileInfo?,
|
||||
newImageAttributes: NewImageAttributes?): MessageImageContent {
|
||||
return copy(
|
||||
url = if (encryptedFileInfo == null) url else null,
|
||||
encryptedFileInfo = encryptedFileInfo?.copy(url = url)
|
||||
encryptedFileInfo = encryptedFileInfo?.copy(url = url),
|
||||
info = info?.copy(
|
||||
width = newImageAttributes?.newWidth ?: info.width,
|
||||
height = newImageAttributes?.newHeight ?: info.height,
|
||||
size = newImageAttributes?.newFileSize ?: info.size
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -265,4 +316,8 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
|
|||
encryptedFileInfo = encryptedFileInfo?.copy(url = url)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_IMAGE_SIZE = 640
|
||||
}
|
||||
}
|
||||
|
|
|
@ -314,6 +314,11 @@ SOFTWARE.
|
|||
<br/>
|
||||
Copyright (c) 2012-2016 Dan Wheeler and Dropbox, Inc.
|
||||
</li>
|
||||
<li>
|
||||
<b>Compressor</b>
|
||||
<br/>
|
||||
Copyright (c) 2016 Zetra.
|
||||
</li>
|
||||
<li>
|
||||
<b>com.otaliastudios:autocomplete</b>
|
||||
<br/>
|
||||
|
|
|
@ -124,6 +124,7 @@ class AttachmentsPreviewFragment @Inject constructor(
|
|||
attachmentBigPreviewController.setData(state)
|
||||
attachmentPreviewerBigList.scrollToPosition(state.currentAttachmentIndex)
|
||||
attachmentPreviewerMiniatureList.scrollToPosition(state.currentAttachmentIndex)
|
||||
attachmentPreviewerSendImageOriginalSize.text = resources.getQuantityString(R.plurals.send_images_with_original_size, state.attachments.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -508,7 +508,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
AttachmentsPreviewActivity.REQUEST_CODE -> {
|
||||
val sendData = AttachmentsPreviewActivity.getOutput(data)
|
||||
val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data)
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, keepOriginalSize))
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, !keepOriginalSize))
|
||||
}
|
||||
REACTION_SELECT_REQUEST_CODE -> {
|
||||
val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return
|
||||
|
@ -1352,7 +1352,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
override fun onContentAttachmentsReady(attachments: List<ContentAttachmentData>) {
|
||||
val grouped = attachments.toGroupedContentAttachmentData()
|
||||
if (grouped.notPreviewables.isNotEmpty()) {
|
||||
// Send the not previewable attachment right now (?)
|
||||
// Send the not previewable attachments right now (?)
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMedia(grouped.notPreviewables, false))
|
||||
}
|
||||
if (grouped.previewables.isNotEmpty()) {
|
||||
|
|
|
@ -142,7 +142,7 @@ class IncomingShareViewModel @AssistedInject constructor(@Assisted initialState:
|
|||
if (proposeMediaEdition) {
|
||||
val grouped = attachmentData.toGroupedContentAttachmentData()
|
||||
if (grouped.notPreviewables.isNotEmpty()) {
|
||||
// Send the not previewable attachment right now (?)
|
||||
// Send the not previewable attachments right now (?)
|
||||
// Pick the first room to send the media
|
||||
selectedRoomIds.firstOrNull()
|
||||
?.let { roomId -> session.getRoom(roomId) }
|
||||
|
|
Loading…
Reference in New Issue