Media : branch upload to preview screen (need improvement)

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

View file

@ -14,11 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.libraries.mediaupload.api package io.element.android.features.messages.impl.attachments.preview
sealed interface MediaType { import androidx.compose.runtime.Immutable
object Image : MediaType
object Video : MediaType @Immutable
object Audio : MediaType sealed interface AttachmentsPreviewEvents {
object File : MediaType object SendAttachment : AttachmentsPreviewEvents
object ClearSendState : AttachmentsPreviewEvents
} }

View file

@ -16,15 +16,32 @@
package io.element.android.features.messages.impl.attachments.preview package io.element.android.features.messages.impl.attachments.preview
import android.net.Uri
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.executeResult
import io.element.android.libraries.core.extensions.flatMap
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.sendMedia
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
class AttachmentsPreviewPresenter @AssistedInject constructor( class AttachmentsPreviewPresenter @AssistedInject constructor(
@Assisted private val attachment: Attachment, @Assisted private val attachment: Attachment,
private val room: MatrixRoom,
private val mediaPreProcessor: MediaPreProcessor,
private val snackbarDispatcher: SnackbarDispatcher,
) : Presenter<AttachmentsPreviewState> { ) : Presenter<AttachmentsPreviewState> {
@AssistedFactory @AssistedFactory
@ -35,8 +52,54 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
@Composable @Composable
override fun present(): AttachmentsPreviewState { override fun present(): AttachmentsPreviewState {
val coroutineScope = rememberCoroutineScope()
val sendActionState = remember {
mutableStateOf<Async<Unit>>(Async.Uninitialized)
}
fun handleEvents(attachmentsPreviewEvents: AttachmentsPreviewEvents) {
when (attachmentsPreviewEvents) {
AttachmentsPreviewEvents.SendAttachment -> coroutineScope.sendAttachment(attachment, sendActionState)
AttachmentsPreviewEvents.ClearSendState -> sendActionState.value = Async.Uninitialized
}
}
return AttachmentsPreviewState( return AttachmentsPreviewState(
attachment = attachment, attachment = attachment,
sendActionState = sendActionState.value,
eventSink = ::handleEvents
) )
} }
private fun CoroutineScope.sendAttachment(
attachment: Attachment,
sendActionState: MutableState<Async<Unit>>,
) = launch {
when (attachment) {
is Attachment.Media -> {
sendMedia(
uri = attachment.localMedia.uri,
mimeType = attachment.localMedia.mimeType,
deleteOriginal = false,
sendActionState = sendActionState
)
}
}
}
private suspend fun sendMedia(
uri: Uri,
mimeType: String,
deleteOriginal: Boolean = false,
sendActionState: MutableState<Async<Unit>>,
) {
suspend {
mediaPreProcessor
.process(uri, mimeType, deleteOriginal)
.flatMap { info ->
room.sendMedia(info)
}
}.executeResult(sendActionState)
}
} }

View file

@ -17,7 +17,10 @@
package io.element.android.features.messages.impl.attachments.preview package io.element.android.features.messages.impl.attachments.preview
import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.libraries.architecture.Async
data class AttachmentsPreviewState( data class AttachmentsPreviewState(
val attachment: Attachment, val attachment: Attachment,
val sendActionState: Async<Unit>,
val eventSink: (AttachmentsPreviewEvents) -> Unit
) )

View file

@ -20,17 +20,23 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.core.net.toUri import androidx.core.net.toUri
import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.features.messages.impl.media.local.LocalMedia import io.element.android.features.messages.impl.media.local.LocalMedia
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.core.mimetype.MimeTypes
open class AttachmentsPreviewStateProvider : PreviewParameterProvider<AttachmentsPreviewState> { open class AttachmentsPreviewStateProvider : PreviewParameterProvider<AttachmentsPreviewState> {
override val values: Sequence<AttachmentsPreviewState> override val values: Sequence<AttachmentsPreviewState>
get() = sequenceOf( get() = sequenceOf(
aAttachmentsPreviewState(), anAttachmentsPreviewState(),
anAttachmentsPreviewState(sendActionState = Async.Loading()),
anAttachmentsPreviewState(sendActionState = Async.Failure(RuntimeException())),
// Add other states here // Add other states here
) )
} }
fun aAttachmentsPreviewState() = AttachmentsPreviewState( fun anAttachmentsPreviewState(sendActionState: Async<Unit> = Async.Uninitialized) = AttachmentsPreviewState(
attachment = Attachment.Media( attachment = Attachment.Media(
localMedia = LocalMedia("".toUri(), mimeType = null) localMedia = LocalMedia("".toUri(), mimeType = MimeTypes.OctetStream),
) ),
sendActionState = sendActionState,
eventSink = {}
) )

View file

@ -29,17 +29,23 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.features.messages.impl.attachments.Attachment import io.element.android.features.messages.impl.attachments.Attachment
import io.element.android.features.messages.impl.attachments.preview.error.sendAttachmentError
import io.element.android.features.messages.impl.media.local.LocalMediaView import io.element.android.features.messages.impl.media.local.LocalMediaView
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.components.dialogs.RetryDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.ui.strings.R
import io.element.android.libraries.ui.strings.R as StringsR import io.element.android.libraries.ui.strings.R as StringsR
@Composable @Composable
@ -49,39 +55,93 @@ fun AttachmentsPreviewView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
fun onSendClicked() { fun postSendAttachment() {
state.eventSink(AttachmentsPreviewEvents.SendAttachment)
}
fun postClearSendState() {
state.eventSink(AttachmentsPreviewEvents.ClearSendState)
}
if (state.sendActionState is Async.Success) {
LaunchedEffect(state.sendActionState) {
onDismiss()
}
} }
Scaffold(modifier) { Scaffold(modifier) {
Column( Box {
modifier = Modifier.fillMaxWidth(), AttachmentPreviewContent(
) { attachment = state.attachment,
Spacer( onSendClicked = ::postSendAttachment,
modifier = Modifier.height(80.dp) onDismiss = onDismiss
) )
Box( AttachmentSendStateView(
modifier = Modifier sendActionState = state.sendActionState,
.fillMaxWidth() onRetryClicked = ::postSendAttachment,
.weight(1f) onRetryDismissed = ::postClearSendState
) {
when (state.attachment) {
is Attachment.Media -> LocalMediaView(
localMedia = state.attachment.localMedia
)
}
}
AttachmentsPreviewBottomActions(
onCancelClicked = onDismiss,
onSendClicked = ::onSendClicked,
modifier = Modifier
.fillMaxWidth()
.defaultMinSize(minHeight = 120.dp)
.padding(all = 24.dp)
) )
} }
} }
} }
@Composable
private fun AttachmentSendStateView(
sendActionState: Async<Unit>,
onRetryDismissed: () -> Unit,
onRetryClicked: () -> Unit
) {
when (sendActionState) {
is Async.Loading -> {
ProgressDialog(text = stringResource(id = R.string.common_loading))
}
is Async.Failure -> {
RetryDialog(
content = stringResource(sendAttachmentError(sendActionState.error)),
onDismiss = onRetryDismissed,
onRetry = onRetryClicked
)
}
else -> Unit
}
}
@Composable
private fun AttachmentPreviewContent(
attachment: Attachment,
onSendClicked: () -> Unit,
onDismiss: () -> Unit
) {
Column(
modifier = Modifier.fillMaxWidth(),
) {
Spacer(
modifier = Modifier.height(80.dp)
)
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
when (attachment) {
is Attachment.Media -> LocalMediaView(
localMedia = attachment.localMedia
)
}
}
AttachmentsPreviewBottomActions(
onCancelClicked = onDismiss,
onSendClicked = onSendClicked,
modifier = Modifier
.fillMaxWidth()
.defaultMinSize(minHeight = 120.dp)
.padding(all = 24.dp)
)
}
}
@Composable @Composable
private fun AttachmentsPreviewBottomActions( private fun AttachmentsPreviewBottomActions(
onCancelClicked: () -> Unit, onCancelClicked: () -> Unit,

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2022 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.features.messages.impl.attachments.preview.error
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.ui.strings.R
fun sendAttachmentError(
throwable: Throwable
): Int {
return if (throwable is MediaPreProcessor.Failure) {
R.string.screen_media_upload_preview_error_failed_processing
} else {
R.string.screen_media_upload_preview_error_failed_sending
}
}

View file

@ -19,6 +19,7 @@ package io.element.android.features.messages.impl.media.local
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import javax.inject.Inject import javax.inject.Inject
@ -30,7 +31,7 @@ class AndroidLocalMediaFactory @Inject constructor(
override fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia? { override fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia? {
if (uri == null) return null if (uri == null) return null
val resolvedMimeType = mimeType ?: context.contentResolver.getType(uri) val resolvedMimeType = mimeType ?: context.contentResolver.getType(uri) ?: MimeTypes.OctetStream
return LocalMedia(uri, resolvedMimeType) return LocalMedia(uri, resolvedMimeType)
} }
} }

View file

@ -17,13 +17,14 @@
package io.element.android.features.messages.impl.media.local package io.element.android.features.messages.impl.media.local
import android.net.Uri import android.net.Uri
import io.element.android.libraries.core.mimetype.MimeTypes
class FakeLocalMediaFactory() : LocalMediaFactory { class FakeLocalMediaFactory() : LocalMediaFactory {
var mimeType: String? = null var fallbackMimeType: String = MimeTypes.OctetStream
override fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia? { override fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia? {
if (uri == null) return null if (uri == null) return null
return LocalMedia(uri, mimeType) return LocalMedia(uri, mimeType ?: fallbackMimeType)
} }
} }

View file

@ -23,5 +23,5 @@ import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
data class LocalMedia( data class LocalMedia(
val uri: Uri, val uri: Uri,
val mimeType: String?, val mimeType: String,
) : Parcelable ) : Parcelable

View file

@ -19,5 +19,10 @@ package io.element.android.features.messages.impl.media.local
import android.net.Uri import android.net.Uri
interface LocalMediaFactory { interface LocalMediaFactory {
/**
* This method will create a [LocalMedia] with the given [uri] and [mimeType]
* If the [mimeType] is null, it'll try to read it from the content.
*
*/
fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia? fun createFromUri(uri: Uri?, mimeType: String?): LocalMedia?
} }

View file

@ -34,7 +34,6 @@ import io.element.android.libraries.core.data.StableCharSequence
import io.element.android.libraries.core.data.toStableCharSequence import io.element.android.libraries.core.data.toStableCharSequence
import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.SnackbarMessage
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
@ -42,15 +41,11 @@ import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.mediapickers.api.PickerProvider import io.element.android.libraries.mediapickers.api.PickerProvider
import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaType
import io.element.android.libraries.mediaupload.api.sendMedia
import io.element.android.libraries.textcomposer.MessageComposerMode import io.element.android.libraries.textcomposer.MessageComposerMode
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import io.element.android.libraries.ui.strings.R as StringR
@SingleIn(RoomScope::class) @SingleIn(RoomScope::class)
class MessageComposerPresenter @Inject constructor( class MessageComposerPresenter @Inject constructor(
@ -59,8 +54,6 @@ class MessageComposerPresenter @Inject constructor(
private val mediaPickerProvider: PickerProvider, private val mediaPickerProvider: PickerProvider,
private val featureFlagService: FeatureFlagService, private val featureFlagService: FeatureFlagService,
private val localMediaFactory: LocalMediaFactory, private val localMediaFactory: LocalMediaFactory,
private val mediaPreProcessor: MediaPreProcessor,
private val snackbarDispatcher: SnackbarDispatcher,
) : Presenter<MessageComposerState> { ) : Presenter<MessageComposerState> {
@SuppressLint("UnsafeOptInUsageError") @SuppressLint("UnsafeOptInUsageError")
@ -186,26 +179,4 @@ class MessageComposerPresenter @Inject constructor(
} }
} }
private fun CoroutineScope.sendMedia(
uri: Uri,
mediaType: MediaType,
deleteOriginal: Boolean = false
) = launch {
mediaPreProcessor.process(uri, mediaType, deleteOriginal)
.map { info ->
room.sendMedia(info)
}
.onSuccess {
Timber.d("onSuccess sending media")
}.onFailure { failure ->
Timber.e(failure, "onfailure sending media: $failure")
val snackbarMessage = if (failure is MediaPreProcessor.Failure) {
StringR.string.screen_media_upload_preview_error_failed_processing
} else {
StringR.string.screen_media_upload_preview_error_failed_sending
}
snackbarDispatcher.post(SnackbarMessage(snackbarMessage))
}
}
} }

View file

@ -25,3 +25,16 @@ inline fun <R, T : R> Result<T>.mapFailure(transform: (exception: Throwable) ->
else -> Result.failure(transform(exception)) 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 { 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. * 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. * @return a [Result] with the [MediaUploadInfo] containing all the info needed to begin the upload.
*/ */
suspend fun process( suspend fun process(
uri: Uri, uri: Uri,
mediaType: MediaType, mimeType: String,
deleteOriginal: Boolean = false deleteOriginal: Boolean = false
): Result<MediaUploadInfo> ): Result<MediaUploadInfo>

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

View file

@ -19,7 +19,6 @@ package io.element.android.libraries.mediaupload.test
import android.net.Uri import android.net.Uri
import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.mediaupload.api.MediaPreProcessor 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.MediaUploadInfo
import java.io.File 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>) { fun givenResult(value: Result<MediaUploadInfo>) {
this.result = value this.result = value