Display video/image compression progress

This commit is contained in:
Benoit Marty 2021-05-01 13:34:46 +02:00 committed by Benoit Marty
parent 765380ab95
commit e510de1ccc
6 changed files with 68 additions and 25 deletions

View File

@ -31,6 +31,8 @@ interface ContentUploadStateTracker {
sealed class State {
object Idle : State()
object EncryptingThumbnail : State()
object CompressingImage : State()
data class CompressingVideo(val percent: Float) : State()
data class UploadingThumbnail(val current: Long, val total: Long) : State()
data class Encrypting(val current: Long, val total: Long) : State()
data class Uploading(val current: Long, val total: Long) : State()

View File

@ -78,6 +78,16 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU
updateState(key, progressData)
}
internal fun setCompressingImage(key: String) {
val progressData = ContentUploadStateTracker.State.CompressingImage
updateState(key, progressData)
}
internal fun setCompressingVideo(key: String, percent: Float) {
val progressData = ContentUploadStateTracker.State.CompressingVideo(percent)
updateState(key, progressData)
}
internal fun setProgress(key: String, current: Long, total: Long) {
val progressData = ContentUploadStateTracker.State.Uploading(current, total)
updateState(key, progressData)

View File

@ -21,6 +21,7 @@ import android.graphics.BitmapFactory
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.listeners.ProgressListener
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel
@ -156,6 +157,8 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
// Do not compress gif
&& attachment.mimeType != MimeTypes.Gif
&& params.compressBeforeSending) {
notifyTracker(params) { contentUploadStateTracker.setCompressingImage(it) }
fileToUpload = imageCompressor.compress(workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
.also { compressedFile ->
// Get new Bitmap size
@ -174,7 +177,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
// Do not compress gif
&& attachment.mimeType != MimeTypes.Gif
&& params.compressBeforeSending) {
fileToUpload = videoCompressor.compress(workingFile)
fileToUpload = videoCompressor.compress(workingFile, object: ProgressListener {
override fun onProgress(progress: Int, total: Int) {
notifyTracker(params) { contentUploadStateTracker.setCompressingVideo(it, progress.toFloat()) }
}
})
.also { compressedFile ->
// Get new Video file size. For now video dimensions are not updated
newAttachmentAttributes = newAttachmentAttributes.copy(newFileSize = compressedFile.length())

View File

@ -23,6 +23,7 @@ import com.abedelazizshe.lightcompressorlibrary.VideoQuality
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.listeners.ProgressListener
import timber.log.Timber
import java.io.File
import java.util.UUID
@ -30,6 +31,7 @@ import javax.inject.Inject
internal class VideoCompressor @Inject constructor(private val context: Context) {
suspend fun compress(videoFile: File,
progressListener: ProgressListener?,
quality: VideoQuality = VideoQuality.MEDIUM,
isMinBitRateEnabled: Boolean = false,
keepOriginalResolution: Boolean = true): File {
@ -46,14 +48,17 @@ internal class VideoCompressor @Inject constructor(private val context: Context)
listener = object : CompressionListener {
override fun onProgress(percent: Float) {
Timber.d("Compressing: $percent%")
progressListener?.onProgress(percent.toInt(), 100)
}
override fun onStart() {
Timber.d("Compressing: start")
progressListener?.onProgress(0, 100)
}
override fun onSuccess() {
Timber.d("Compressing: success")
progressListener?.onProgress(100, 100)
job.complete()
}

View File

@ -25,6 +25,7 @@ import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ScreenScope
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.utils.TextUtils
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
@ -70,6 +71,9 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
private val messageColorProvider: MessageColorProvider,
private val errorFormatter: ErrorFormatter) : ContentUploadStateTracker.UpdateListener {
private val progressBar: ProgressBar = progressLayout.findViewById(R.id.mediaProgressBar)
private val progressTextView: TextView = progressLayout.findViewById(R.id.mediaProgressTextView)
override fun onUpdate(state: ContentUploadStateTracker.State) {
when (state) {
is ContentUploadStateTracker.State.Idle -> handleIdle()
@ -79,19 +83,19 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
is ContentUploadStateTracker.State.Uploading -> handleProgress(state)
is ContentUploadStateTracker.State.Failure -> handleFailure(/*state*/)
is ContentUploadStateTracker.State.Success -> handleSuccess()
}
is ContentUploadStateTracker.State.CompressingImage -> handleCompressingImage()
is ContentUploadStateTracker.State.CompressingVideo -> handleCompressingVideo(state)
}.exhaustive
}
private fun handleIdle() {
if (isLocalFile) {
progressLayout.isVisible = true
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
progressBar?.isVisible = true
progressBar?.isIndeterminate = true
progressBar?.progress = 0
progressTextView?.text = progressLayout.context.getString(R.string.send_file_step_idle)
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNSENT))
progressBar.isVisible = true
progressBar.isIndeterminate = true
progressBar.progress = 0
progressTextView.text = progressLayout.context.getString(R.string.send_file_step_idle)
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNSENT))
} else {
progressLayout.isVisible = false
}
@ -113,38 +117,51 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
doHandleProgress(R.string.send_file_step_sending_file, state.current, state.total)
}
private fun handleCompressingImage() {
progressLayout.visibility = View.VISIBLE
progressBar.isVisible = true
progressBar.isIndeterminate = true
progressTextView.isVisible = true
progressTextView.text = progressLayout.context.getString(R.string.send_file_step_compressing_image)
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.SENDING))
}
private fun handleCompressingVideo(state: ContentUploadStateTracker.State.CompressingVideo) {
progressLayout.visibility = View.VISIBLE
progressBar.isVisible = true
progressBar.isIndeterminate = false
progressBar.progress = state.percent.toInt()
progressTextView.isVisible = true
progressTextView.text = progressLayout.context.getString(R.string.send_file_step_compressing_video, state.percent.toInt())
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.SENDING))
}
private fun doHandleEncrypting(resId: Int, current: Long, total: Long) {
progressLayout.visibility = View.VISIBLE
val percent = if (total > 0) (100L * (current.toFloat() / total.toFloat())) else 0f
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
progressBar?.isIndeterminate = false
progressBar?.progress = percent.toInt()
progressBar.isIndeterminate = false
progressBar.progress = percent.toInt()
progressTextView.isVisible = true
progressTextView?.text = progressLayout.context.getString(resId)
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.ENCRYPTING))
progressTextView.text = progressLayout.context.getString(resId)
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.ENCRYPTING))
}
private fun doHandleProgress(resId: Int, current: Long, total: Long) {
progressLayout.visibility = View.VISIBLE
val percent = 100L * (current.toFloat() / total.toFloat())
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
progressBar?.isVisible = true
progressBar?.isIndeterminate = false
progressBar?.progress = percent.toInt()
progressBar.isVisible = true
progressBar.isIndeterminate = false
progressBar.progress = percent.toInt()
progressTextView.isVisible = true
progressTextView?.text = progressLayout.context.getString(resId,
progressTextView.text = progressLayout.context.getString(resId,
TextUtils.formatFileSize(progressLayout.context, current, true),
TextUtils.formatFileSize(progressLayout.context, total, true))
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.SENDING))
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.SENDING))
}
private fun handleFailure(/*state: ContentUploadStateTracker.State.Failure*/) {
progressLayout.visibility = View.VISIBLE
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
progressBar?.isVisible = false
progressBar.isVisible = false
// Do not show the message it's too technical for users, and unfortunate when upload is cancelled
// in the middle by turning airplane mode for example
progressTextView.isVisible = false

View File

@ -2174,6 +2174,8 @@
<string name="send_file_step_sending_thumbnail">Sending thumbnail (%1$s / %2$s)</string>
<string name="send_file_step_encrypting_file">Encrypting file…</string>
<string name="send_file_step_sending_file">Sending file (%1$s / %2$s)</string>
<string name="send_file_step_compressing_image">Compressing image…</string>
<string name="send_file_step_compressing_video">Compressing video %d%%</string>
<string name="downloading_file">Downloading file %1$s…</string>
<string name="downloaded_file">File %1$s has been downloaded!</string>