Browse Source

Media: improve media viewer

feature/jme/open-room-member-details-when-clicking-on-user-data
ganfra 1 year ago
parent
commit
80adbd4bd1
  1. 12
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
  2. 2
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/local/LocalMedia.kt
  3. 22
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/local/LocalMediaView.kt
  4. 22
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerEvents.kt
  5. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerNode.kt
  6. 66
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerPresenter.kt
  7. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerState.kt
  8. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerStateProvider.kt
  9. 44
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerView.kt
  10. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt
  11. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt
  12. 1
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContentProvider.kt
  13. 2
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt
  14. 3
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt
  15. 6
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MatrixMediaLoader.kt
  16. 27
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaFile.kt
  17. 31
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/MediaHandle.kt
  18. 14
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt
  19. 27
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaFile.kt
  20. 7
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt

12
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt

@ -62,7 +62,11 @@ class MessagesFlowNode @AssistedInject constructor( @@ -62,7 +62,11 @@ class MessagesFlowNode @AssistedInject constructor(
object Messages : NavTarget
@Parcelize
data class MediaViewer(val title: String, val mediaSource: MatrixMediaSource) : NavTarget
data class MediaViewer(
val title: String,
val mediaSource: MatrixMediaSource,
val mimeType: String?
) : NavTarget
@Parcelize
data class AttachmentPreview(val attachment: Attachment) : NavTarget
@ -89,7 +93,7 @@ class MessagesFlowNode @AssistedInject constructor( @@ -89,7 +93,7 @@ class MessagesFlowNode @AssistedInject constructor(
createNode<MessagesNode>(buildContext, listOf(callback))
}
is NavTarget.MediaViewer -> {
val inputs = MediaViewerNode.Inputs(navTarget.title, navTarget.mediaSource)
val inputs = MediaViewerNode.Inputs(navTarget.title, navTarget.mediaSource, navTarget.mimeType)
createNode<MediaViewerNode>(buildContext, listOf(inputs))
}
is NavTarget.AttachmentPreview -> {
@ -103,12 +107,12 @@ class MessagesFlowNode @AssistedInject constructor( @@ -103,12 +107,12 @@ class MessagesFlowNode @AssistedInject constructor(
when (event.content) {
is TimelineItemImageContent -> {
val mediaSource = event.content.mediaSource
val navTarget = NavTarget.MediaViewer(event.content.body, mediaSource)
val navTarget = NavTarget.MediaViewer(event.content.body, mediaSource, event.content.mimeType)
backstack.push(navTarget)
}
is TimelineItemVideoContent -> {
val mediaSource = event.content.videoSource
val navTarget = NavTarget.MediaViewer(event.content.body, mediaSource)
val navTarget = NavTarget.MediaViewer(event.content.body, mediaSource, event.content.mimeType)
backstack.push(navTarget)
}
else -> Unit

2
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/local/LocalMedia.kt

@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.media.local @@ -18,7 +18,7 @@ package io.element.android.features.messages.impl.media.local
import android.net.Uri
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
import kotlinx.parcelize.Parcelize
@Parcelize
data class LocalMedia(

22
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/local/LocalMediaView.kt

@ -22,6 +22,8 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT @@ -22,6 +22,8 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
@ -84,13 +86,17 @@ fun MediaVideoView( @@ -84,13 +86,17 @@ fun MediaVideoView(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val exoPlayer = ExoPlayer.Builder(LocalContext.current).build()
val mediaItem = MediaItem.Builder()
.setUri(uri)
.build()
exoPlayer.playWhenReady
val exoPlayer = remember {
ExoPlayer.Builder(context).build()
.apply {
this.playWhenReady = true
this.prepare()
}
}
LaunchedEffect(uri) {
val mediaItem = MediaItem.fromUri(uri)
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
}
AndroidView(
factory = {
@ -98,8 +104,10 @@ fun MediaVideoView( @@ -98,8 +104,10 @@ fun MediaVideoView(
player = exoPlayer
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
controllerShowTimeoutMs = 3000
}
}, modifier = modifier.fillMaxSize()
},
modifier = modifier.fillMaxSize()
)
OnLifecycleEvent { _, event ->

22
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerEvents.kt

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
/*
* 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.features.messages.impl.media.viewer
sealed interface MediaViewerEvents {
object RetryLoading : MediaViewerEvents
object SaveOnDisk : MediaViewerEvents
}

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerNode.kt

@ -39,11 +39,12 @@ class MediaViewerNode @AssistedInject constructor( @@ -39,11 +39,12 @@ class MediaViewerNode @AssistedInject constructor(
data class Inputs(
val name: String,
val mediaSource: MatrixMediaSource,
val mimeType: String?
) : NodeInputs
private val inputs: Inputs = inputs()
private val presenter = presenterFactory.create(inputs.name, inputs.mediaSource)
private val presenter = presenterFactory.create(inputs)
@Composable
override fun View(modifier: Modifier) {

66
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerPresenter.kt

@ -17,8 +17,14 @@ @@ -17,8 +17,14 @@
package io.element.android.features.messages.impl.media.viewer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.core.net.toUri
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -27,37 +33,65 @@ import io.element.android.features.messages.impl.media.local.LocalMediaFactory @@ -27,37 +33,65 @@ import io.element.android.features.messages.impl.media.local.LocalMediaFactory
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
import io.element.android.libraries.matrix.api.media.MediaFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
class MediaViewerPresenter @AssistedInject constructor(
@Assisted private val name: String,
@Assisted private val mediaSource: MatrixMediaSource,
@Assisted private val inputs: MediaViewerNode.Inputs,
private val localMediaFactory: LocalMediaFactory,
private val client: MatrixClient,
) : Presenter<MediaViewerState> {
@AssistedFactory
interface Factory {
fun create(name: String, mediaSource: MatrixMediaSource): MediaViewerPresenter
fun create(inputs: MediaViewerNode.Inputs): MediaViewerPresenter
}
@Composable
override fun present(): MediaViewerState {
val localMedia by produceState<Async<LocalMedia>>(initialValue = Async.Uninitialized) {
value = Async.Loading(null)
//TODO we are missing some permissions to use this API
client.mediaLoader.loadMediaFile(mediaSource, null)
.onSuccess {
val localMedia = localMediaFactory.createFromUri(uri = it, null)
Async.Success(localMedia)
}.onFailure {
Async.Failure(it, null)
val coroutineScope = rememberCoroutineScope()
var loadMediaTrigger by remember { mutableStateOf(0) }
val mediaFile: MutableState<MediaFile?> = remember {
mutableStateOf(null)
}
val localMedia: MutableState<Async<LocalMedia>> = remember {
mutableStateOf(Async.Uninitialized)
}
DisposableEffect(loadMediaTrigger) {
coroutineScope.loadMedia(mediaFile, localMedia)
onDispose {
mediaFile.value?.close()
}
}
fun handleEvents(mediaViewerEvents: MediaViewerEvents) {
when (mediaViewerEvents) {
MediaViewerEvents.RetryLoading -> loadMediaTrigger++
MediaViewerEvents.SaveOnDisk -> TODO()
}
}
return MediaViewerState(
name = name,
downloadedMedia = localMedia,
name = inputs.name,
downloadedMedia = localMedia.value,
eventSink = ::handleEvents
)
}
private fun CoroutineScope.loadMedia(mediaFile: MutableState<MediaFile?>, localMedia: MutableState<Async<LocalMedia>>) = launch {
mediaFile.value = null
localMedia.value = Async.Loading()
client.mediaLoader.loadMediaFile(inputs.mediaSource, inputs.mimeType)
.onSuccess {
mediaFile.value = it
}.mapCatching {
val uri = it.path().toUri()
localMediaFactory.createFromUri(uri, inputs.mimeType)!!
}.onSuccess {
localMedia.value = Async.Success(it)
}.onFailure {
localMedia.value = Async.Failure(it)
}
}
}

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerState.kt

@ -21,5 +21,6 @@ import io.element.android.libraries.architecture.Async @@ -21,5 +21,6 @@ import io.element.android.libraries.architecture.Async
data class MediaViewerState(
val name: String,
val downloadedMedia: Async<LocalMedia>
val downloadedMedia: Async<LocalMedia>,
val eventSink: (MediaViewerEvents) -> Unit
)

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerStateProvider.kt

@ -29,5 +29,6 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState> @@ -29,5 +29,6 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState>
fun aMediaViewerState() = MediaViewerState(
name = "A media",
downloadedMedia = Async.Uninitialized
downloadedMedia = Async.Uninitialized,
eventSink = {}
)

44
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/media/viewer/MediaViewerView.kt

@ -19,37 +19,50 @@ @@ -19,37 +19,50 @@
package io.element.android.features.messages.impl.media.viewer
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.messages.impl.media.local.LocalMediaView
import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.R.string as StringR
@Composable
fun MediaViewerView(
state: MediaViewerState,
modifier: Modifier = Modifier,
) {
fun onRetry() {
state.eventSink(MediaViewerEvents.RetryLoading)
}
Scaffold(modifier) {
Box(
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize()
.padding(it),
contentAlignment = Alignment.Center
) {
when (state.downloadedMedia) {
is Async.Success -> LocalMediaView(state.downloadedMedia.state)
is Async.Failure -> ErrorDialog(
content = "Error while downloading the media",
)
is Async.Failure -> ErrorView("Error while downloading", ::onRetry)
else -> CircularProgressIndicator(
strokeWidth = 2.dp,
)
@ -58,6 +71,27 @@ fun MediaViewerView( @@ -58,6 +71,27 @@ fun MediaViewerView(
}
}
@Composable
private fun ErrorView(
errorMessage: String,
onRetry: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(text = errorMessage)
Spacer(modifier = Modifier.size(8.dp))
Button(
onClick = onRetry
) {
Text(text = stringResource(id = StringR.action_retry))
}
}
}
@Preview
@Composable
fun MediaViewerViewLightPreview(@PreviewParameter(MediaViewerStateProvider::class) state: MediaViewerState) =

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactory.kt

@ -52,6 +52,7 @@ class TimelineItemContentMessageFactory @Inject constructor() { @@ -52,6 +52,7 @@ class TimelineItemContentMessageFactory @Inject constructor() {
body = messageType.body,
height = messageType.info?.height?.toInt(),
width = messageType.info?.width?.toInt(),
mimeType = messageType.info?.mimetype,
mediaSource = messageType.source,
blurhash = messageType.info?.blurhash,
aspectRatio = aspectRatio
@ -69,7 +70,7 @@ class TimelineItemContentMessageFactory @Inject constructor() { @@ -69,7 +70,7 @@ class TimelineItemContentMessageFactory @Inject constructor() {
body = messageType.body,
thumbnailSource = messageType.info?.thumbnailSource,
videoSource = messageType.source,
mimetype = messageType.info?.mimetype,
mimeType = messageType.info?.mimetype,
width = messageType.info?.width?.toInt(),
height = messageType.info?.height?.toInt(),
duration = messageType.info?.duration ?: 0L,

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContent.kt

@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaSource @@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaSource
data class TimelineItemImageContent(
val body: String,
val mediaSource: MatrixMediaSource,
val mimeType: String?,
val blurhash: String?,
val width: Int?,
val height: Int?,

1
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemImageContentProvider.kt

@ -34,6 +34,7 @@ fun aTimelineItemImageContent() = TimelineItemImageContent( @@ -34,6 +34,7 @@ fun aTimelineItemImageContent() = TimelineItemImageContent(
mediaSource = MatrixMediaSource(""),
blurhash = "TQF5:I_NtRE4kXt7Z#MwkCIARPjr",
aspectRatio = 0.5f,
mimeType = "null",
height = null,
width = null
)

2
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContent.kt

@ -27,7 +27,7 @@ data class TimelineItemVideoContent( @@ -27,7 +27,7 @@ data class TimelineItemVideoContent(
val blurhash: String?,
val height: Int?,
val width: Int?,
val mimetype: String?,
val mimeType: String?,
) : TimelineItemEventContent {
override val type: String = "TimelineItemImageContent"
}

3
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemVideoContentProvider.kt

@ -18,7 +18,6 @@ package io.element.android.features.messages.impl.timeline.model.event @@ -18,7 +18,6 @@ package io.element.android.features.messages.impl.timeline.model.event
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
import io.element.android.libraries.matrix.ui.media.MediaRequestData
open class TimelineItemVideoContentProvider : PreviewParameterProvider<TimelineItemVideoContent> {
override val values: Sequence<TimelineItemVideoContent>
@ -38,5 +37,5 @@ fun aTimelineItemVideoContent() = TimelineItemVideoContent( @@ -38,5 +37,5 @@ fun aTimelineItemVideoContent() = TimelineItemVideoContent(
videoSource = MatrixMediaSource(""),
height = null,
width = null,
mimetype = null
mimeType = null
)

6
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MatrixMediaLoader.kt

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package io.element.android.libraries.matrix.api.media
import android.net.Uri
interface MatrixMediaLoader {
/**
* @param url to fetch the content for.
@ -36,7 +34,7 @@ interface MatrixMediaLoader { @@ -36,7 +34,7 @@ interface MatrixMediaLoader {
/**
* @param url to fetch the data for.
* @param mimeType: optional mime type
* @return a [Result] of [Uri]. It's the uri of the downloaded file.
* @return a [Result] of [MediaFile]
*/
suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<Uri>
suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<MediaFile>
}

27
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/media/MediaFile.kt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* 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.matrix.api.media
import java.io.Closeable
/**
* A wrapper around a media file on the disk.
* When closed the file will be removed from the disk.
*/
interface MediaFile : Closeable {
fun path(): String
}

31
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/MediaHandle.kt

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
/*
* 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.matrix.impl.media
import io.element.android.libraries.matrix.api.media.MediaFile
import org.matrix.rustcomponents.sdk.MediaFileHandle
class RustMediaFile(private val inner: MediaFileHandle) : MediaFile {
override fun path(): String {
return inner.path()
}
override fun close() {
inner.close()
}
}

14
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/media/RustMediaLoader.kt

@ -16,15 +16,14 @@ @@ -16,15 +16,14 @@
package io.element.android.libraries.matrix.impl.media
import android.net.Uri
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
import io.element.android.libraries.matrix.api.media.MediaFile
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
import org.matrix.rustcomponents.sdk.use
import java.io.File
class RustMediaLoader(
private val dispatchers: CoroutineDispatchers,
@ -59,19 +58,16 @@ class RustMediaLoader( @@ -59,19 +58,16 @@ class RustMediaLoader(
}
}
override suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<Uri> =
override suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<MediaFile> =
withContext(dispatchers.io) {
runCatching {
mediaSourceFromUrl(source.url).use { mediaSource ->
innerClient.getMediaFile(
val mediaFile = innerClient.getMediaFile(
mediaSource = mediaSource,
mimeType = mimeType ?: "application/octet-stream"
).use {
val file = File(it.path())
Uri.fromFile(file)
)
RustMediaFile(mediaFile)
}
}
}
}
}

27
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaFile.kt

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* 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.matrix.test.media
import io.element.android.libraries.matrix.api.media.MediaFile
class FakeMediaFile(private val path: String) : MediaFile {
override fun path(): String {
return path
}
override fun close() = Unit
}

7
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt

@ -16,10 +16,9 @@ @@ -16,10 +16,9 @@
package io.element.android.libraries.matrix.test.media
import android.net.Uri
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
import java.io.File
import io.element.android.libraries.matrix.api.media.MediaFile
class FakeMediaLoader : MatrixMediaLoader {
@ -41,11 +40,11 @@ class FakeMediaLoader : MatrixMediaLoader { @@ -41,11 +40,11 @@ class FakeMediaLoader : MatrixMediaLoader {
}
}
override suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<Uri> {
override suspend fun loadMediaFile(source: MatrixMediaSource, mimeType: String?): Result<MediaFile> {
return if (shouldFail) {
Result.failure(RuntimeException())
} else {
return Result.success(Uri.fromFile(File("path")))
return Result.success(FakeMediaFile(""))
}
}
}

Loading…
Cancel
Save