Media : branch upload to preview screen (need improvement)

This commit is contained in:
ganfra 2023-05-17 08:44:35 +02:00
parent c8ead4ab9f
commit f51d6a3cfd
15 changed files with 237 additions and 92 deletions

View file

@ -25,3 +25,16 @@ inline fun <R, T : R> Result<T>.mapFailure(transform: (exception: Throwable) ->
else -> Result.failure(transform(exception))
}
}
/**
* Can be used to transform some Throwable into some other.
*/
inline fun <R, T> Result<R>.flatMap(transform: (R) -> Result<T>): Result<T> {
return when (val exception = exceptionOrNull()) {
null -> mapCatching(transform).fold(
onSuccess = { it },
onFailure = { Result.failure(it) }
)
else -> Result.failure(exception)
}
}

View file

@ -20,13 +20,13 @@ import android.net.Uri
interface MediaPreProcessor {
/**
* Given a [uri] and [mediaType], pre-processes the media before it's uploaded, resizing, transcoding, and removing sensitive info from its metadata.
* Given a [uri] and [mimeType], pre-processes the media before it's uploaded, resizing, transcoding, and removing sensitive info from its metadata.
* If [deleteOriginal] is `true`, the file reference by the [uri] will be automatically deleted too when this process finishes.
* @return a [Result] with the [MediaUploadInfo] containing all the info needed to begin the upload.
*/
suspend fun process(
uri: Uri,
mediaType: MediaType,
mimeType: String,
deleteOriginal: Boolean = false
): Result<MediaUploadInfo>

View file

@ -1,24 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* 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 io.element.android.libraries.mediaupload.api
sealed interface MediaType {
object Image : MediaType
object Video : MediaType
object Audio : MediaType
object File : MediaType
}

View file

@ -27,7 +27,9 @@ import io.element.android.libraries.androidutils.media.runAndRelease
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.matrix.api.media.AudioInfo
@ -37,7 +39,6 @@ import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.media.ThumbnailInfo
import io.element.android.libraries.matrix.api.media.VideoInfo
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaType
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
import io.element.android.libraries.mediaupload.api.ThumbnailProcessingInfo
import kotlinx.coroutines.Dispatchers
@ -53,7 +54,7 @@ import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
@ContributesBinding(AppScope::class)
class MediaPreProcessorImpl @Inject constructor(
class AndroidMediaPreProcessor @Inject constructor(
@ApplicationContext private val context: Context,
private val imageCompressor: ImageCompressor,
private val videoCompressor: VideoCompressor,
@ -89,27 +90,18 @@ class MediaPreProcessorImpl @Inject constructor(
override suspend fun process(
uri: Uri,
mediaType: MediaType,
mimeType: String,
deleteOriginal: Boolean,
): Result<MediaUploadInfo> = runCatching {
// Camera returns an 'octet-stream' mimetype, so it needs to be overridden
val mimeType = contentResolver.getType(uri)
val mimeTypeOrDefault = if (mimeType == MimeTypes.OctetStream) {
when (mediaType) {
MediaType.Image -> MimeTypes.Jpeg
MediaType.Video -> MimeTypes.Mp4
MediaType.Audio -> MimeTypes.Ogg
else -> mimeType
}
} else {
mimeType
}
val compressBeforeSending = mediaType in sequenceOf(MediaType.Image, MediaType.Video)
val result = if (compressBeforeSending && mimeType != MimeTypes.Gif) {
when (mediaType) {
MediaType.Image -> processImage(uri)
MediaType.Video -> processVideo(uri, mimeTypeOrDefault)
MediaType.Audio -> processAudio(uri, mimeTypeOrDefault)
val compressBeforeSending = (
mimeType.isMimeTypeImage() && mimeType != MimeTypes.Gif) ||
mimeType.isMimeTypeVideo()
val result = if (compressBeforeSending) {
when {
mimeType.isMimeTypeImage() -> processImage(uri)
mimeType.isMimeTypeVideo() -> processVideo(uri, mimeType)
mimeType.isMimeTypeAudio() -> processAudio(uri, mimeType)
else -> error("Cannot compress file of type: $mimeType")
}
} else {

View file

@ -19,7 +19,6 @@ package io.element.android.libraries.mediaupload.test
import android.net.Uri
import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaType
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
import java.io.File
@ -37,7 +36,7 @@ class FakeMediaPreProcessor : MediaPreProcessor {
)
)
override suspend fun process(uri: Uri, mediaType: MediaType, deleteOriginal: Boolean): Result<MediaUploadInfo> = result
override suspend fun process(uri: Uri, mimeType: String, deleteOriginal: Boolean): Result<MediaUploadInfo> = result
fun givenResult(value: Result<MediaUploadInfo>) {
this.result = value