Commit 4c8e492a authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Improves the image upload process.

parent ce646a38
...@@ -35,6 +35,7 @@ import chat.rocket.android.server.domain.useRealName ...@@ -35,6 +35,7 @@ import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.state import chat.rocket.android.server.infraestructure.state
import chat.rocket.android.util.extension.compressImageAndGetByteArray import chat.rocket.android.util.extension.compressImageAndGetByteArray
import chat.rocket.android.util.extension.getByteArray
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -80,6 +81,7 @@ import kotlinx.coroutines.experimental.launch ...@@ -80,6 +81,7 @@ import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import org.threeten.bp.Instant import org.threeten.bp.Instant
import timber.log.Timber import timber.log.Timber
import java.io.InputStream
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
...@@ -346,15 +348,51 @@ class ChatRoomPresenter @Inject constructor( ...@@ -346,15 +348,51 @@ class ChatRoomPresenter @Inject constructor(
view.showFileSelection(settings.uploadMimeTypeFilter()) view.showFileSelection(settings.uploadMimeTypeFilter())
} }
fun uploadFile(roomId: String, uri: Uri, msg: String, bitmap: Bitmap? = null) { fun uploadImage(roomId: String, mimeType: String, uri: Uri, bitmap: Bitmap, msg: String) {
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
try { try {
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
val fileName = uriInteractor.getFileName(uri) ?: uri.toString() val fileName = uriInteractor.getFileName(uri) ?: uri.toString()
val mimeType = uriInteractor.getMimeType(uri) if (fileName.isEmpty()) {
val byteArray = bitmap?.compressImageAndGetByteArray(mimeType) view.showInvalidFileMessage()
val fileSize = byteArray?.size ?: uriInteractor.getFileSize(uri) } else {
val byteArray =
bitmap.getByteArray(mimeType, 100, settings.uploadMaxFileSize())
retryIO("uploadFile($roomId, $fileName, $mimeType") {
client.uploadFile(
roomId,
fileName,
mimeType,
msg,
description = fileName
) {
byteArray.inputStream()
}
}
logMediaUploaded(mimeType)
}
}
} catch (ex: Exception) {
Timber.d(ex, "Error uploading image")
when (ex) {
is RocketChatException -> view.showMessage(ex)
else -> view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
}
}
fun uploadFile(roomId: String, mimeType: String, uri: Uri, msg: String) {
launchUI(strategy) {
view.showLoading()
try {
withContext(DefaultDispatcher) {
val fileName = uriInteractor.getFileName(uri) ?: uri.toString()
val fileSize = uriInteractor.getFileSize(uri)
val maxFileSizeAllowed = settings.uploadMaxFileSize() val maxFileSizeAllowed = settings.uploadMaxFileSize()
when { when {
...@@ -370,7 +408,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -370,7 +408,7 @@ class ChatRoomPresenter @Inject constructor(
msg, msg,
description = fileName description = fileName
) { ) {
byteArray?.inputStream() ?: uriInteractor.getInputStream(uri) uriInteractor.getInputStream(uri)
} }
} }
logMediaUploaded(mimeType) logMediaUploaded(mimeType)
......
...@@ -7,6 +7,7 @@ import androidx.core.view.isVisible ...@@ -7,6 +7,7 @@ import androidx.core.view.isVisible
import chat.rocket.android.emoji.internal.GlideApp import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.util.extensions.getFileName import chat.rocket.android.util.extensions.getFileName
import chat.rocket.android.util.extensions.getMimeType import chat.rocket.android.util.extensions.getMimeType
import chat.rocket.common.util.ifNull
import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
...@@ -14,10 +15,12 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -14,10 +15,12 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
imagePreview.isVisible = false imagePreview.isVisible = false
audioVideoAttachment.isVisible = false audioVideoAttachment.isVisible = false
textFile.isVisible = false textFile.isVisible = false
lateinit var mimeType: String
var bitmap: Bitmap? = null var bitmap: Bitmap? = null
activity?.let { context -> activity?.let { context ->
uri.getMimeType(context).let { mimeType -> uri.getMimeType(context).let {
mimeType = it
description.text.clear() description.text.clear()
when { when {
mimeType.startsWith("image") -> { mimeType.startsWith("image") -> {
...@@ -25,7 +28,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -25,7 +28,6 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
.with(context) .with(context)
.asBitmap() .asBitmap()
.load(uri) .load(uri)
.override(imagePreview.width, imagePreview.height)
.fitCenter() .fitCenter()
.into(object : SimpleTarget<Bitmap>() { .into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady( override fun onResourceReady(
...@@ -48,12 +50,22 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) { ...@@ -48,12 +50,22 @@ fun ChatRoomFragment.showFileAttachmentDialog(uri: Uri) {
} }
sendButton.setOnClickListener { sendButton.setOnClickListener {
bitmap?.let { bitmap ->
presenter.uploadImage(
chatRoomId,
mimeType,
uri,
bitmap,
(citation ?: "") + description.text.toString()
)
}.ifNull {
presenter.uploadFile( presenter.uploadFile(
chatRoomId, chatRoomId,
mimeType,
uri, uri,
(citation ?: "") + description.text.toString(), (citation ?: "") + description.text.toString()
bitmap
) )
}
alertDialog.dismiss() alertDialog.dismiss()
} }
cancelButton.setOnClickListener { alertDialog.dismiss() } cancelButton.setOnClickListener { alertDialog.dismiss() }
......
...@@ -32,20 +32,46 @@ suspend fun Bitmap.compressImageAndGetInputStream(mimeType: String): InputStream ...@@ -32,20 +32,46 @@ suspend fun Bitmap.compressImageAndGetInputStream(mimeType: String): InputStream
return inputStream return inputStream
} }
/**
* Returns a [ByteArray] of a [Bitmap].
*
* @param mimeType The MIME type of the [Bitmap].
* @param quality The quality of the [Bitmap] for the resulting [ByteArray].
* @param maxFileSizeAllowed The max file size allowed by the server. Note: The [quality] will be
* decreased minus 10 until the [ByteArray] size fits the [maxFileSizeAllowed] value.
* @return A [ByteArray] of a [Bitmap]
*/
suspend fun Bitmap.getByteArray(
mimeType: String,
quality: Int,
maxFileSizeAllowed: Int
): ByteArray {
lateinit var byteArray: ByteArray
compressImageAndGetByteArray(mimeType, quality)?.let {
if (it.size > maxFileSizeAllowed && maxFileSizeAllowed !in -1..0) {
getByteArray(mimeType, quality - 10, maxFileSizeAllowed)
} else {
byteArray = it
}
}
return byteArray
}
/** /**
* Compress a [Bitmap] image. * Compress a [Bitmap] image.
* *
* @param mimeType The MimeType of what the compressed image should be. * @param mimeType The MimeType of what the compressed image should be.
* @return An [ByteArray] of a compressed image, otherwise null if the compression couldn't be done. * @return An [ByteArray] of a compressed image, otherwise null if the compression couldn't be done.
*/ */
suspend fun Bitmap.compressImageAndGetByteArray(mimeType: String): ByteArray? { suspend fun Bitmap.compressImageAndGetByteArray(mimeType: String, quality: Int = 100): ByteArray? {
var byteArray: ByteArray? = null var byteArray: ByteArray? = null
withContext(DefaultDispatcher) { withContext(DefaultDispatcher) {
val byteArrayOutputStream = ByteArrayOutputStream() val byteArrayOutputStream = ByteArrayOutputStream()
// TODO: Add an option the the app to the user be able to select the quality of the compressed image
val isCompressed = val isCompressed =
this.compress(mimeType.getCompressFormat(), 70, byteArrayOutputStream) this.compress(mimeType.getCompressFormat(), quality, byteArrayOutputStream)
if (isCompressed) { if (isCompressed) {
byteArray = byteArrayOutputStream.toByteArray() byteArray = byteArrayOutputStream.toByteArray()
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment