Display video/image compression progress
This commit is contained in:
parent
765380ab95
commit
e510de1ccc
|
@ -31,6 +31,8 @@ interface ContentUploadStateTracker {
|
||||||
sealed class State {
|
sealed class State {
|
||||||
object Idle : State()
|
object Idle : State()
|
||||||
object EncryptingThumbnail : 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 UploadingThumbnail(val current: Long, val total: Long) : State()
|
||||||
data class Encrypting(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()
|
data class Uploading(val current: Long, val total: Long) : State()
|
||||||
|
|
|
@ -78,6 +78,16 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU
|
||||||
updateState(key, progressData)
|
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) {
|
internal fun setProgress(key: String, current: Long, total: Long) {
|
||||||
val progressData = ContentUploadStateTracker.State.Uploading(current, total)
|
val progressData = ContentUploadStateTracker.State.Uploading(current, total)
|
||||||
updateState(key, progressData)
|
updateState(key, progressData)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import android.graphics.BitmapFactory
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
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.content.ContentAttachmentData
|
||||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
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
|
// Do not compress gif
|
||||||
&& attachment.mimeType != MimeTypes.Gif
|
&& attachment.mimeType != MimeTypes.Gif
|
||||||
&& params.compressBeforeSending) {
|
&& params.compressBeforeSending) {
|
||||||
|
notifyTracker(params) { contentUploadStateTracker.setCompressingImage(it) }
|
||||||
|
|
||||||
fileToUpload = imageCompressor.compress(workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
|
fileToUpload = imageCompressor.compress(workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE)
|
||||||
.also { compressedFile ->
|
.also { compressedFile ->
|
||||||
// Get new Bitmap size
|
// Get new Bitmap size
|
||||||
|
@ -174,7 +177,11 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter
|
||||||
// Do not compress gif
|
// Do not compress gif
|
||||||
&& attachment.mimeType != MimeTypes.Gif
|
&& attachment.mimeType != MimeTypes.Gif
|
||||||
&& params.compressBeforeSending) {
|
&& 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 ->
|
.also { compressedFile ->
|
||||||
// Get new Video file size. For now video dimensions are not updated
|
// Get new Video file size. For now video dimensions are not updated
|
||||||
newAttachmentAttributes = newAttachmentAttributes.copy(newFileSize = compressedFile.length())
|
newAttachmentAttributes = newAttachmentAttributes.copy(newFileSize = compressedFile.length())
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.abedelazizshe.lightcompressorlibrary.VideoQuality
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.matrix.android.sdk.api.listeners.ProgressListener
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
@ -30,6 +31,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
internal class VideoCompressor @Inject constructor(private val context: Context) {
|
internal class VideoCompressor @Inject constructor(private val context: Context) {
|
||||||
suspend fun compress(videoFile: File,
|
suspend fun compress(videoFile: File,
|
||||||
|
progressListener: ProgressListener?,
|
||||||
quality: VideoQuality = VideoQuality.MEDIUM,
|
quality: VideoQuality = VideoQuality.MEDIUM,
|
||||||
isMinBitRateEnabled: Boolean = false,
|
isMinBitRateEnabled: Boolean = false,
|
||||||
keepOriginalResolution: Boolean = true): File {
|
keepOriginalResolution: Boolean = true): File {
|
||||||
|
@ -46,14 +48,17 @@ internal class VideoCompressor @Inject constructor(private val context: Context)
|
||||||
listener = object : CompressionListener {
|
listener = object : CompressionListener {
|
||||||
override fun onProgress(percent: Float) {
|
override fun onProgress(percent: Float) {
|
||||||
Timber.d("Compressing: $percent%")
|
Timber.d("Compressing: $percent%")
|
||||||
|
progressListener?.onProgress(percent.toInt(), 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
Timber.d("Compressing: start")
|
Timber.d("Compressing: start")
|
||||||
|
progressListener?.onProgress(0, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess() {
|
override fun onSuccess() {
|
||||||
Timber.d("Compressing: success")
|
Timber.d("Compressing: success")
|
||||||
|
progressListener?.onProgress(100, 100)
|
||||||
job.complete()
|
job.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.ScreenScope
|
import im.vector.app.core.di.ScreenScope
|
||||||
import im.vector.app.core.error.ErrorFormatter
|
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.core.utils.TextUtils
|
||||||
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
|
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import org.matrix.android.sdk.api.session.content.ContentUploadStateTracker
|
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 messageColorProvider: MessageColorProvider,
|
||||||
private val errorFormatter: ErrorFormatter) : ContentUploadStateTracker.UpdateListener {
|
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) {
|
override fun onUpdate(state: ContentUploadStateTracker.State) {
|
||||||
when (state) {
|
when (state) {
|
||||||
is ContentUploadStateTracker.State.Idle -> handleIdle()
|
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.Uploading -> handleProgress(state)
|
||||||
is ContentUploadStateTracker.State.Failure -> handleFailure(/*state*/)
|
is ContentUploadStateTracker.State.Failure -> handleFailure(/*state*/)
|
||||||
is ContentUploadStateTracker.State.Success -> handleSuccess()
|
is ContentUploadStateTracker.State.Success -> handleSuccess()
|
||||||
}
|
is ContentUploadStateTracker.State.CompressingImage -> handleCompressingImage()
|
||||||
|
is ContentUploadStateTracker.State.CompressingVideo -> handleCompressingVideo(state)
|
||||||
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleIdle() {
|
private fun handleIdle() {
|
||||||
if (isLocalFile) {
|
if (isLocalFile) {
|
||||||
progressLayout.isVisible = true
|
progressLayout.isVisible = true
|
||||||
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
|
progressBar.isVisible = true
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
progressBar.isIndeterminate = true
|
||||||
progressBar?.isVisible = true
|
progressBar.progress = 0
|
||||||
progressBar?.isIndeterminate = true
|
progressTextView.text = progressLayout.context.getString(R.string.send_file_step_idle)
|
||||||
progressBar?.progress = 0
|
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNSENT))
|
||||||
progressTextView?.text = progressLayout.context.getString(R.string.send_file_step_idle)
|
|
||||||
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNSENT))
|
|
||||||
} else {
|
} else {
|
||||||
progressLayout.isVisible = false
|
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)
|
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) {
|
private fun doHandleEncrypting(resId: Int, current: Long, total: Long) {
|
||||||
progressLayout.visibility = View.VISIBLE
|
progressLayout.visibility = View.VISIBLE
|
||||||
val percent = if (total > 0) (100L * (current.toFloat() / total.toFloat())) else 0f
|
val percent = if (total > 0) (100L * (current.toFloat() / total.toFloat())) else 0f
|
||||||
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
|
progressBar.isIndeterminate = false
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
progressBar.progress = percent.toInt()
|
||||||
progressBar?.isIndeterminate = false
|
|
||||||
progressBar?.progress = percent.toInt()
|
|
||||||
progressTextView.isVisible = true
|
progressTextView.isVisible = true
|
||||||
progressTextView?.text = progressLayout.context.getString(resId)
|
progressTextView.text = progressLayout.context.getString(resId)
|
||||||
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.ENCRYPTING))
|
progressTextView.setTextColor(messageColorProvider.getMessageTextColor(SendState.ENCRYPTING))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doHandleProgress(resId: Int, current: Long, total: Long) {
|
private fun doHandleProgress(resId: Int, current: Long, total: Long) {
|
||||||
progressLayout.visibility = View.VISIBLE
|
progressLayout.visibility = View.VISIBLE
|
||||||
val percent = 100L * (current.toFloat() / total.toFloat())
|
val percent = 100L * (current.toFloat() / total.toFloat())
|
||||||
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
|
progressBar.isVisible = true
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
progressBar.isIndeterminate = false
|
||||||
progressBar?.isVisible = true
|
progressBar.progress = percent.toInt()
|
||||||
progressBar?.isIndeterminate = false
|
|
||||||
progressBar?.progress = percent.toInt()
|
|
||||||
progressTextView.isVisible = true
|
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, current, true),
|
||||||
TextUtils.formatFileSize(progressLayout.context, total, 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*/) {
|
private fun handleFailure(/*state: ContentUploadStateTracker.State.Failure*/) {
|
||||||
progressLayout.visibility = View.VISIBLE
|
progressLayout.visibility = View.VISIBLE
|
||||||
val progressBar = progressLayout.findViewById<ProgressBar>(R.id.mediaProgressBar)
|
progressBar.isVisible = false
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
|
||||||
progressBar?.isVisible = false
|
|
||||||
// Do not show the message it's too technical for users, and unfortunate when upload is cancelled
|
// 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
|
// in the middle by turning airplane mode for example
|
||||||
progressTextView.isVisible = false
|
progressTextView.isVisible = false
|
||||||
|
|
|
@ -2174,6 +2174,8 @@
|
||||||
<string name="send_file_step_sending_thumbnail">Sending thumbnail (%1$s / %2$s)</string>
|
<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_encrypting_file">Encrypting file…</string>
|
||||||
<string name="send_file_step_sending_file">Sending file (%1$s / %2$s)</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="downloading_file">Downloading file %1$s…</string>
|
||||||
<string name="downloaded_file">File %1$s has been downloaded!</string>
|
<string name="downloaded_file">File %1$s has been downloaded!</string>
|
||||||
|
|
Loading…
Reference in New Issue