Introduce MatrixMediaSource
This commit is contained in:
parent
c3a1297c18
commit
4236b69705
27 changed files with 298 additions and 84 deletions
|
|
@ -27,6 +27,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
|
||||
private fun Modifier.defaultContentPadding(): Modifier = padding(
|
||||
horizontal = 12.dp, vertical = 6.dp
|
||||
|
|
@ -64,5 +65,9 @@ fun TimelineItemEventContentView(
|
|||
content = content,
|
||||
modifier = modifier,
|
||||
)
|
||||
is TimelineItemVideoContent -> TimelineItemVideoView(
|
||||
content = content,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,39 +18,38 @@ package io.element.android.features.messages.impl.timeline.components.event
|
|||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
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.timeline.model.event.TimelineItemImageContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContentProvider
|
||||
import io.element.android.libraries.designsystem.components.blurhash.BlurHashAsyncImage
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import kotlin.math.min
|
||||
|
||||
@Composable
|
||||
fun TimelineItemImageView(
|
||||
content: TimelineItemImageContent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val widthPercent = if (content.aspectRatio > 1f) {
|
||||
1f
|
||||
} else {
|
||||
0.7f
|
||||
}
|
||||
val maxHeight = min(300, content.height ?: Int.MAX_VALUE)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth(widthPercent)
|
||||
.heightIn(max = maxHeight.dp)
|
||||
.aspectRatio(content.aspectRatio),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
BlurHashAsyncImage(
|
||||
blurHash = content.blurhash,
|
||||
model = content.mediaRequestData,
|
||||
contentScale = ContentScale.Crop,
|
||||
model = MediaRequestData(content.mediaSource, MediaRequestData.Kind.Content),
|
||||
contentScale = ContentScale.Fit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.timeline.components.event
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
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.timeline.model.event.TimelineItemImageContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContentProvider
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
import io.element.android.libraries.designsystem.components.blurhash.BlurHashAsyncImage
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import kotlin.math.min
|
||||
|
||||
@Composable
|
||||
fun TimelineItemVideoView(
|
||||
content: TimelineItemVideoContent,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val maxHeight = min(300, content.height ?: Int.MAX_VALUE)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.heightIn(max = maxHeight.dp)
|
||||
.aspectRatio(content.aspectRatio),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
BlurHashAsyncImage(
|
||||
blurHash = content.blurhash,
|
||||
model = MediaRequestData(content.thumbnailSource, MediaRequestData.Kind.Content),
|
||||
contentScale = ContentScale.Fit,
|
||||
)
|
||||
Image(
|
||||
painterResource(id = androidx.media3.ui.R.drawable.exo_ic_play_circle_filled),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun TimelineItemVideoViewLightPreview(@PreviewParameter(TimelineItemImageContentProvider::class) content: TimelineItemImageContent) =
|
||||
ElementPreviewLight { ContentToPreview(content) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun TimelineItemVideoViewDarkPreview(@PreviewParameter(TimelineItemImageContentProvider::class) content: TimelineItemImageContent) =
|
||||
ElementPreviewDark { ContentToPreview(content) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(content: TimelineItemImageContent) {
|
||||
TimelineItemImageView(content)
|
||||
}
|
||||
|
|
@ -22,13 +22,14 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
|||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
import io.element.android.features.messages.impl.timeline.util.toHtmlDocument
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimelineItemContentMessageFactory @Inject constructor() {
|
||||
|
|
@ -49,10 +50,29 @@ class TimelineItemContentMessageFactory @Inject constructor() {
|
|||
}
|
||||
TimelineItemImageContent(
|
||||
body = messageType.body,
|
||||
mediaRequestData = MediaRequestData(
|
||||
url = messageType.url,
|
||||
kind = MediaRequestData.Kind.Content
|
||||
),
|
||||
height = messageType.info?.height?.toInt(),
|
||||
width = messageType.info?.width?.toInt(),
|
||||
mediaSource = messageType.source,
|
||||
blurhash = messageType.info?.blurhash,
|
||||
aspectRatio = aspectRatio
|
||||
)
|
||||
}
|
||||
is VideoMessageType -> {
|
||||
val height = messageType.info?.height?.toFloat()
|
||||
val width = messageType.info?.width?.toFloat()
|
||||
val aspectRatio = if (height != null && width != null) {
|
||||
width / height
|
||||
} else {
|
||||
0.7f
|
||||
}
|
||||
TimelineItemVideoContent(
|
||||
body = messageType.body,
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
videoSource = messageType.source,
|
||||
mimetype = messageType.info?.mimetype,
|
||||
width = messageType.info?.width?.toInt(),
|
||||
height = messageType.info?.height?.toInt(),
|
||||
duration = messageType.info?.duration ?: 0L,
|
||||
blurhash = messageType.info?.blurhash,
|
||||
aspectRatio = aspectRatio
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,13 +16,15 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.model.event
|
||||
|
||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
|
||||
|
||||
data class TimelineItemImageContent(
|
||||
val body: String,
|
||||
val mediaRequestData: MediaRequestData,
|
||||
val mediaSource: MatrixMediaSource,
|
||||
val blurhash: String?,
|
||||
val width: Int?,
|
||||
val height: Int?,
|
||||
val aspectRatio: Float
|
||||
) : TimelineItemEventContent{
|
||||
) : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemImageContent"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
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 TimelineItemImageContentProvider : PreviewParameterProvider<TimelineItemImageContent> {
|
||||
|
|
@ -30,7 +31,9 @@ open class TimelineItemImageContentProvider : PreviewParameterProvider<TimelineI
|
|||
|
||||
fun aTimelineItemImageContent() = TimelineItemImageContent(
|
||||
body = "a body",
|
||||
mediaRequestData = MediaRequestData(url = "", kind = MediaRequestData.Kind.Content),
|
||||
blurhash = null,
|
||||
mediaSource = MatrixMediaSource(""),
|
||||
blurhash = "TQF5:I_NtRE4kXt7Z#MwkCIARPjr",
|
||||
aspectRatio = 0.5f,
|
||||
height = null,
|
||||
width = null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.timeline.model.event
|
||||
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaSource
|
||||
|
||||
data class TimelineItemVideoContent(
|
||||
val body: String,
|
||||
val duration: Long,
|
||||
val videoSource: MatrixMediaSource,
|
||||
val thumbnailSource: MatrixMediaSource?,
|
||||
val aspectRatio: Float,
|
||||
val blurhash: String?,
|
||||
val height: Int?,
|
||||
val width: Int?,
|
||||
val mimetype: String?,
|
||||
) : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemImageContent"
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.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>
|
||||
get() = sequenceOf(
|
||||
aTimelineItemVideoContent(),
|
||||
aTimelineItemVideoContent().copy(aspectRatio = 1.0f),
|
||||
aTimelineItemVideoContent().copy(aspectRatio = 1.5f),
|
||||
)
|
||||
}
|
||||
|
||||
fun aTimelineItemVideoContent() = TimelineItemVideoContent(
|
||||
body = "a video",
|
||||
thumbnailSource = MatrixMediaSource(url = ""),
|
||||
blurhash = "TQF5:I_NtRE4kXt7Z#MwkCIARPjr",
|
||||
aspectRatio = 0.5f,
|
||||
duration = 0,
|
||||
videoSource = MatrixMediaSource(""),
|
||||
height = null,
|
||||
width = null,
|
||||
mimetype = null
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue