[Feature] Render m.sticker events (#2122)
* Render m.sticker events --------- Signed-off-by: Marco Antonio Alvarez <surakin@gmail.com> Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
edd07df96e
commit
378da8ce21
150 changed files with 378 additions and 25 deletions
1
changelog.d/1949.feature
Normal file
1
changelog.d/1949.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Render m.sticker events
|
||||||
|
|
@ -46,6 +46,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
import io.element.android.features.poll.api.create.CreatePollEntryPoint
|
import io.element.android.features.poll.api.create.CreatePollEntryPoint
|
||||||
import io.element.android.features.poll.api.create.CreatePollMode
|
import io.element.android.features.poll.api.create.CreatePollMode
|
||||||
|
|
@ -253,6 +254,19 @@ class MessagesFlowNode @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
overlay.show(navTarget)
|
overlay.show(navTarget)
|
||||||
}
|
}
|
||||||
|
is TimelineItemStickerContent -> {
|
||||||
|
val navTarget = NavTarget.MediaViewer(
|
||||||
|
mediaInfo = MediaInfo(
|
||||||
|
name = event.content.body,
|
||||||
|
mimeType = event.content.mimeType,
|
||||||
|
formattedFileSize = event.content.formattedFileSize,
|
||||||
|
fileExtension = event.content.fileExtension
|
||||||
|
),
|
||||||
|
mediaSource = event.content.mediaSource,
|
||||||
|
thumbnailSource = event.content.thumbnailSource,
|
||||||
|
)
|
||||||
|
overlay.show(navTarget)
|
||||||
|
}
|
||||||
is TimelineItemVideoContent -> {
|
is TimelineItemVideoContent -> {
|
||||||
val navTarget = NavTarget.MediaViewer(
|
val navTarget = NavTarget.MediaViewer(
|
||||||
mediaInfo = MediaInfo(
|
mediaInfo = MediaInfo(
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
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.TimelineItemUnknownContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
|
|
@ -351,6 +352,12 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
type = AttachmentThumbnailType.Image,
|
type = AttachmentThumbnailType.Image,
|
||||||
blurHash = targetEvent.content.blurhash,
|
blurHash = targetEvent.content.blurhash,
|
||||||
)
|
)
|
||||||
|
is TimelineItemStickerContent -> AttachmentThumbnailInfo(
|
||||||
|
thumbnailSource = targetEvent.content.thumbnailSource ?: targetEvent.content.mediaSource,
|
||||||
|
textContent = targetEvent.content.body,
|
||||||
|
type = AttachmentThumbnailType.Image,
|
||||||
|
blurHash = targetEvent.content.blurhash,
|
||||||
|
)
|
||||||
is TimelineItemVideoContent -> AttachmentThumbnailInfo(
|
is TimelineItemVideoContent -> AttachmentThumbnailInfo(
|
||||||
thumbnailSource = targetEvent.content.thumbnailSource,
|
thumbnailSource = targetEvent.content.thumbnailSource,
|
||||||
textContent = targetEvent.content.body,
|
textContent = targetEvent.content.body,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
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.TimelineItemUnknownContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
|
|
@ -239,6 +240,9 @@ private fun MessageSummary(event: TimelineItem.Event, modifier: Modifier = Modif
|
||||||
is TimelineItemImageContent -> {
|
is TimelineItemImageContent -> {
|
||||||
content = { ContentForBody(event.content.body) }
|
content = { ContentForBody(event.content.body) }
|
||||||
}
|
}
|
||||||
|
is TimelineItemStickerContent -> {
|
||||||
|
content = { ContentForBody(event.content.body) }
|
||||||
|
}
|
||||||
is TimelineItemVideoContent -> {
|
is TimelineItemVideoContent -> {
|
||||||
content = { ContentForBody(event.content.body) }
|
content = { ContentForBody(event.content.body) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ import io.element.android.features.messages.impl.timeline.model.bubble.BubbleSta
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent
|
||||||
|
|
@ -583,6 +584,7 @@ private fun MessageEventBubbleContent(
|
||||||
|
|
||||||
val timestampPosition = when (event.content) {
|
val timestampPosition = when (event.content) {
|
||||||
is TimelineItemImageContent,
|
is TimelineItemImageContent,
|
||||||
|
is TimelineItemStickerContent,
|
||||||
is TimelineItemVideoContent,
|
is TimelineItemVideoContent,
|
||||||
is TimelineItemLocationContent -> TimestampPosition.Overlay
|
is TimelineItemLocationContent -> TimestampPosition.Overlay
|
||||||
is TimelineItemPollContent -> TimestampPosition.Below
|
is TimelineItemPollContent -> TimestampPosition.Below
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageConten
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
|
@ -109,6 +110,10 @@ class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
|
||||||
body = "Image",
|
body = "Image",
|
||||||
type = ImageMessageType("Image", MediaSource("url"), null),
|
type = ImageMessageType("Image", MediaSource("url"), null),
|
||||||
),
|
),
|
||||||
|
aMessageContent(
|
||||||
|
body = "Sticker",
|
||||||
|
type = StickerMessageType("Image", MediaSource("url"), null),
|
||||||
|
),
|
||||||
aMessageContent(
|
aMessageContent(
|
||||||
body = "File",
|
body = "File",
|
||||||
type = FileMessageType("File", MediaSource("url"), null),
|
type = FileMessageType("File", MediaSource("url"), null),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
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.TimelineItemUnknownContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
|
|
@ -76,6 +77,10 @@ fun TimelineItemEventContentView(
|
||||||
content = content,
|
content = content,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
is TimelineItemStickerContent -> TimelineItemStickerView(
|
||||||
|
content = content,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
is TimelineItemVideoContent -> TimelineItemVideoView(
|
is TimelineItemVideoContent -> TimelineItemVideoView(
|
||||||
content = content,
|
content = content,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
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.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContentProvider
|
||||||
|
import io.element.android.libraries.designsystem.components.BlurHashAsyncImage
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
|
|
||||||
|
private const val STICKER_SIZE_IN_DP = 128
|
||||||
|
private const val DEFAULT_ASPECT_RATIO = 1.33f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TimelineItemStickerView(
|
||||||
|
content: TimelineItemStickerContent,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val safeAspectRatio = content.aspectRatio ?: DEFAULT_ASPECT_RATIO
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.heightIn(min = STICKER_SIZE_IN_DP.dp, max = STICKER_SIZE_IN_DP.dp)
|
||||||
|
.aspectRatio(safeAspectRatio, false),
|
||||||
|
contentAlignment = Alignment.TopStart,
|
||||||
|
) {
|
||||||
|
BlurHashAsyncImage(
|
||||||
|
model = MediaRequestData(content.preferredMediaSource, MediaRequestData.Kind.File(content.body, content.mimeType)),
|
||||||
|
blurHash = content.blurhash,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun TimelineItemStickerViewPreview(@PreviewParameter(TimelineItemStickerContentProvider::class) content: TimelineItemStickerContent) = ElementPreview {
|
||||||
|
TimelineItemStickerView(content)
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||||
|
|
@ -50,6 +51,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageConten
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
|
@ -93,6 +95,21 @@ class TimelineItemContentMessageFactory @Inject constructor(
|
||||||
fileExtension = fileExtensionExtractor.extractFromName(messageType.body)
|
fileExtension = fileExtensionExtractor.extractFromName(messageType.body)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is StickerMessageType -> {
|
||||||
|
val aspectRatio = aspectRatioOf(messageType.info?.width, messageType.info?.height)
|
||||||
|
TimelineItemStickerContent(
|
||||||
|
body = messageType.body,
|
||||||
|
mediaSource = messageType.source,
|
||||||
|
thumbnailSource = messageType.info?.thumbnailSource,
|
||||||
|
mimeType = messageType.info?.mimetype ?: MimeTypes.OctetStream,
|
||||||
|
blurhash = messageType.info?.blurhash,
|
||||||
|
width = messageType.info?.width?.toInt(),
|
||||||
|
height = messageType.info?.height?.toInt(),
|
||||||
|
aspectRatio = aspectRatio,
|
||||||
|
formattedFileSize = fileSizeFormatter.format(messageType.info?.size ?: 0),
|
||||||
|
fileExtension = fileExtensionExtractor.extractFromName(messageType.body)
|
||||||
|
)
|
||||||
|
}
|
||||||
is LocationMessageType -> {
|
is LocationMessageType -> {
|
||||||
val location = Location.fromGeoUri(messageType.geoUri)
|
val location = Location.fromGeoUri(messageType.geoUri)
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,43 @@
|
||||||
package io.element.android.features.messages.impl.timeline.factories.event
|
package io.element.android.features.messages.impl.timeline.factories.event
|
||||||
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
|
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
|
||||||
|
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
|
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TimelineItemContentStickerFactory @Inject constructor() {
|
class TimelineItemContentStickerFactory @Inject constructor(
|
||||||
|
private val fileSizeFormatter: FileSizeFormatter,
|
||||||
|
private val fileExtensionExtractor: FileExtensionExtractor
|
||||||
|
) {
|
||||||
|
private fun aspectRatioOf(width: Long?, height: Long?): Float? {
|
||||||
|
val result = if (height != null && width != null) {
|
||||||
|
width.toFloat() / height.toFloat()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
fun create(@Suppress("UNUSED_PARAMETER") content: StickerContent): TimelineItemEventContent {
|
return result?.takeIf { it.isFinite() }
|
||||||
return TimelineItemUnknownContent
|
}
|
||||||
|
|
||||||
|
fun create(content: StickerContent): TimelineItemEventContent {
|
||||||
|
|
||||||
|
val aspectRatio = aspectRatioOf(content.info.width, content.info.height)
|
||||||
|
|
||||||
|
return TimelineItemStickerContent(
|
||||||
|
body = content.body,
|
||||||
|
mediaSource = MediaSource(content.url),
|
||||||
|
thumbnailSource = content.info.thumbnailSource,
|
||||||
|
mimeType = content.info.mimetype ?: MimeTypes.OctetStream,
|
||||||
|
blurhash = content.info.blurhash,
|
||||||
|
width = content.info.width?.toInt(),
|
||||||
|
height = content.info.height?.toInt(),
|
||||||
|
aspectRatio = aspectRatio,
|
||||||
|
formattedFileSize = fileSizeFormatter.format(content.info.size ?: 0),
|
||||||
|
fileExtension = fileExtensionExtractor.extractFromName(content.body)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
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.TimelineItemUnknownContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
|
|
@ -54,6 +55,7 @@ internal fun TimelineItem.Event.canBeGrouped(): Boolean {
|
||||||
is TimelineItemTextBasedContent,
|
is TimelineItemTextBasedContent,
|
||||||
is TimelineItemEncryptedContent,
|
is TimelineItemEncryptedContent,
|
||||||
is TimelineItemImageContent,
|
is TimelineItemImageContent,
|
||||||
|
is TimelineItemStickerContent,
|
||||||
is TimelineItemFileContent,
|
is TimelineItemFileContent,
|
||||||
is TimelineItemVideoContent,
|
is TimelineItemVideoContent,
|
||||||
is TimelineItemAudioContent,
|
is TimelineItemAudioContent,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
import io.element.android.libraries.matrix.ui.messages.toPlainText
|
||||||
|
|
||||||
|
|
@ -45,6 +46,10 @@ fun InReplyTo.map() = when (this) {
|
||||||
val messageContent = content as MessageContent
|
val messageContent = content as MessageContent
|
||||||
(messageContent.type as? TextMessageType)?.toPlainText() ?: messageContent.body
|
(messageContent.type as? TextMessageType)?.toPlainText() ?: messageContent.body
|
||||||
}
|
}
|
||||||
|
is StickerContent -> {
|
||||||
|
val stickerContent = content as StickerContent
|
||||||
|
stickerContent.body
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,14 @@ package io.element.android.features.messages.impl.timeline.model
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||||
|
|
@ -98,6 +100,13 @@ internal fun InReplyToDetails.metadata(): InReplyToMetadata? = when (eventConten
|
||||||
)
|
)
|
||||||
else -> InReplyToMetadata.Text(textContent ?: eventContent.body)
|
else -> InReplyToMetadata.Text(textContent ?: eventContent.body)
|
||||||
}
|
}
|
||||||
|
is StickerContent -> InReplyToMetadata.Thumbnail(
|
||||||
|
AttachmentThumbnailInfo(
|
||||||
|
thumbnailSource = MediaSource(eventContent.url),
|
||||||
|
textContent = eventContent.body,
|
||||||
|
type = AttachmentThumbnailType.Image
|
||||||
|
)
|
||||||
|
)
|
||||||
is PollContent -> InReplyToMetadata.Thumbnail(
|
is PollContent -> InReplyToMetadata.Thumbnail(
|
||||||
AttachmentThumbnailInfo(
|
AttachmentThumbnailInfo(
|
||||||
textContent = eventContent.question,
|
textContent = eventContent.question,
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ fun TimelineItemEventContent.canReact(): Boolean =
|
||||||
is TimelineItemEncryptedContent,
|
is TimelineItemEncryptedContent,
|
||||||
is TimelineItemFileContent,
|
is TimelineItemFileContent,
|
||||||
is TimelineItemImageContent,
|
is TimelineItemImageContent,
|
||||||
|
is TimelineItemStickerContent,
|
||||||
is TimelineItemLocationContent,
|
is TimelineItemLocationContent,
|
||||||
is TimelineItemPollContent,
|
is TimelineItemPollContent,
|
||||||
is TimelineItemVoiceContent,
|
is TimelineItemVoiceContent,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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 io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
|
|
||||||
|
data class TimelineItemStickerContent(
|
||||||
|
val body: String,
|
||||||
|
val mediaSource: MediaSource,
|
||||||
|
val thumbnailSource: MediaSource?,
|
||||||
|
val formattedFileSize: String,
|
||||||
|
val fileExtension: String,
|
||||||
|
val mimeType: String,
|
||||||
|
val blurhash: String?,
|
||||||
|
val width: Int?,
|
||||||
|
val height: Int?,
|
||||||
|
val aspectRatio: Float?
|
||||||
|
) : TimelineItemEventContent {
|
||||||
|
override val type: String = "TimelineItemStickerContent"
|
||||||
|
|
||||||
|
val preferredMediaSource = if (mimeType == MimeTypes.Gif) {
|
||||||
|
mediaSource
|
||||||
|
} else {
|
||||||
|
thumbnailSource ?: mediaSource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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 androidx.media3.common.MimeTypes
|
||||||
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
|
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
||||||
|
|
||||||
|
open class TimelineItemStickerContentProvider : PreviewParameterProvider<TimelineItemStickerContent> {
|
||||||
|
override val values: Sequence<TimelineItemStickerContent>
|
||||||
|
get() = sequenceOf(
|
||||||
|
aTimelineItemStickerContent(),
|
||||||
|
aTimelineItemStickerContent().copy(aspectRatio = 1.0f),
|
||||||
|
aTimelineItemStickerContent().copy(aspectRatio = 1.5f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun aTimelineItemStickerContent() = TimelineItemStickerContent(
|
||||||
|
body = "a body",
|
||||||
|
mediaSource = MediaSource(""),
|
||||||
|
thumbnailSource = null,
|
||||||
|
mimeType = MimeTypes.IMAGE_JPEG,
|
||||||
|
blurhash = A_BLUR_HASH,
|
||||||
|
width = null,
|
||||||
|
height = 128,
|
||||||
|
aspectRatio = 0.5f,
|
||||||
|
formattedFileSize = "4MB",
|
||||||
|
fileExtension = "jpg"
|
||||||
|
)
|
||||||
|
|
@ -28,6 +28,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
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.TimelineItemUnknownContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
|
|
@ -53,6 +54,7 @@ class MessageSummaryFormatterImpl @Inject constructor(
|
||||||
is TimelineItemVoiceContent -> context.getString(CommonStrings.common_voice_message)
|
is TimelineItemVoiceContent -> context.getString(CommonStrings.common_voice_message)
|
||||||
is TimelineItemUnknownContent -> context.getString(CommonStrings.common_unsupported_event)
|
is TimelineItemUnknownContent -> context.getString(CommonStrings.common_unsupported_event)
|
||||||
is TimelineItemImageContent -> context.getString(CommonStrings.common_image)
|
is TimelineItemImageContent -> context.getString(CommonStrings.common_image)
|
||||||
|
is TimelineItemStickerContent -> context.getString(CommonStrings.common_sticker)
|
||||||
is TimelineItemVideoContent -> context.getString(CommonStrings.common_video)
|
is TimelineItemVideoContent -> context.getString(CommonStrings.common_video)
|
||||||
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
|
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
|
||||||
is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio)
|
is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio)
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,10 @@ internal fun TestScope.aTimelineItemsFactory(): TimelineItemsFactory {
|
||||||
htmlConverterProvider = FakeHtmlConverterProvider(),
|
htmlConverterProvider = FakeHtmlConverterProvider(),
|
||||||
),
|
),
|
||||||
redactedMessageFactory = TimelineItemContentRedactedFactory(),
|
redactedMessageFactory = TimelineItemContentRedactedFactory(),
|
||||||
stickerFactory = TimelineItemContentStickerFactory(),
|
stickerFactory = TimelineItemContentStickerFactory(
|
||||||
|
fileSizeFormatter = FakeFileSizeFormatter(),
|
||||||
|
fileExtensionExtractor = FileExtensionExtractorWithoutValidation()
|
||||||
|
),
|
||||||
pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()),
|
pollFactory = TimelineItemContentPollFactory(FakeFeatureFlagService(), FakePollContentStateFactory()),
|
||||||
utdFactory = TimelineItemContentUTDFactory(),
|
utdFactory = TimelineItemContentUTDFactory(),
|
||||||
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
|
roomMembershipFactory = TimelineItemContentRoomMembershipFactory(timelineEventFormatter),
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||||
|
|
@ -57,6 +58,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
|
@ -438,6 +440,30 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
assertThat(result).isEqualTo(expected)
|
assertThat(result).isEqualTo(expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test create StickerMessageType`() = runTest {
|
||||||
|
val sut = createTimelineItemContentStickerFactory()
|
||||||
|
val result = sut.create(
|
||||||
|
content = createStickerContent(
|
||||||
|
"body",
|
||||||
|
ImageInfo(32, 32, "image/webp", 8192, null, MediaSource("thumbnail://url"), null),
|
||||||
|
"url")
|
||||||
|
)
|
||||||
|
val expected = TimelineItemStickerContent(
|
||||||
|
body = "body",
|
||||||
|
mediaSource = MediaSource(url = "url", json = null),
|
||||||
|
thumbnailSource = MediaSource(url = "thumbnail://url", json = null),
|
||||||
|
formattedFileSize = "8192 Bytes",
|
||||||
|
fileExtension = "",
|
||||||
|
mimeType = MimeTypes.WebP,
|
||||||
|
blurhash = null,
|
||||||
|
width = 32,
|
||||||
|
height = 32,
|
||||||
|
aspectRatio = 1.0f
|
||||||
|
)
|
||||||
|
assertThat(result).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test create ImageMessageType with info`() = runTest {
|
fun `test create ImageMessageType with info`() = runTest {
|
||||||
val sut = createTimelineItemContentMessageFactory()
|
val sut = createTimelineItemContentMessageFactory()
|
||||||
|
|
@ -627,4 +653,20 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
featureFlagService = featureFlagService,
|
featureFlagService = featureFlagService,
|
||||||
htmlConverterProvider = FakeHtmlConverterProvider(htmlConverterTransform),
|
htmlConverterProvider = FakeHtmlConverterProvider(htmlConverterTransform),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun createStickerContent(
|
||||||
|
body: String = "Body",
|
||||||
|
inImageInfo: ImageInfo,
|
||||||
|
inUrl: String
|
||||||
|
): StickerContent {
|
||||||
|
return StickerContent (
|
||||||
|
body = body,
|
||||||
|
info = inImageInfo,
|
||||||
|
url = inUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
private fun createTimelineItemContentStickerFactory() = TimelineItemContentStickerFactory(
|
||||||
|
fileSizeFormatter = FakeFileSizeFormatter(),
|
||||||
|
fileExtensionExtractor = FileExtensionExtractorWithoutValidation()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.RedactedConte
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
|
|
@ -120,6 +121,9 @@ class DefaultRoomLastMessageFormatter @Inject constructor(
|
||||||
is ImageMessageType -> {
|
is ImageMessageType -> {
|
||||||
sp.getString(CommonStrings.common_image)
|
sp.getString(CommonStrings.common_image)
|
||||||
}
|
}
|
||||||
|
is StickerMessageType -> {
|
||||||
|
sp.getString(CommonStrings.common_sticker)
|
||||||
|
}
|
||||||
is LocationMessageType -> {
|
is LocationMessageType -> {
|
||||||
sp.getString(CommonStrings.common_shared_location)
|
sp.getString(CommonStrings.common_shared_location)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.RedactedConte
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
|
|
@ -165,6 +166,7 @@ class DefaultRoomLastMessageFormatterTest {
|
||||||
AudioMessageType(body, MediaSource("url"), null),
|
AudioMessageType(body, MediaSource("url"), null),
|
||||||
VoiceMessageType(body, MediaSource("url"), null, null),
|
VoiceMessageType(body, MediaSource("url"), null, null),
|
||||||
ImageMessageType(body, MediaSource("url"), null),
|
ImageMessageType(body, MediaSource("url"), null),
|
||||||
|
StickerMessageType(body, MediaSource("url"), null),
|
||||||
FileMessageType(body, MediaSource("url"), null),
|
FileMessageType(body, MediaSource("url"), null),
|
||||||
LocationMessageType(body, "geo:1,2", null),
|
LocationMessageType(body, "geo:1,2", null),
|
||||||
NoticeMessageType(body, null),
|
NoticeMessageType(body, null),
|
||||||
|
|
@ -196,6 +198,7 @@ class DefaultRoomLastMessageFormatterTest {
|
||||||
is AudioMessageType -> "Audio"
|
is AudioMessageType -> "Audio"
|
||||||
is VoiceMessageType -> "Voice message"
|
is VoiceMessageType -> "Voice message"
|
||||||
is ImageMessageType -> "Image"
|
is ImageMessageType -> "Image"
|
||||||
|
is StickerMessageType -> "Sticker"
|
||||||
is FileMessageType -> "File"
|
is FileMessageType -> "File"
|
||||||
is LocationMessageType -> "Shared location"
|
is LocationMessageType -> "Shared location"
|
||||||
is EmoteMessageType -> "* $senderName ${type.body}"
|
is EmoteMessageType -> "* $senderName ${type.body}"
|
||||||
|
|
@ -214,6 +217,7 @@ class DefaultRoomLastMessageFormatterTest {
|
||||||
is AudioMessageType -> "$senderName: Audio"
|
is AudioMessageType -> "$senderName: Audio"
|
||||||
is VoiceMessageType -> "$senderName: Voice message"
|
is VoiceMessageType -> "$senderName: Voice message"
|
||||||
is ImageMessageType -> "$senderName: Image"
|
is ImageMessageType -> "$senderName: Image"
|
||||||
|
is StickerMessageType -> "$senderName: Sticker"
|
||||||
is FileMessageType -> "$senderName: File"
|
is FileMessageType -> "$senderName: File"
|
||||||
is LocationMessageType -> "$senderName: Shared location"
|
is LocationMessageType -> "$senderName: Shared location"
|
||||||
is TextMessageType,
|
is TextMessageType,
|
||||||
|
|
@ -226,6 +230,7 @@ class DefaultRoomLastMessageFormatterTest {
|
||||||
is AudioMessageType -> true
|
is AudioMessageType -> true
|
||||||
is VoiceMessageType -> true
|
is VoiceMessageType -> true
|
||||||
is ImageMessageType -> true
|
is ImageMessageType -> true
|
||||||
|
is StickerMessageType -> true
|
||||||
is FileMessageType -> true
|
is FileMessageType -> true
|
||||||
is LocationMessageType -> false
|
is LocationMessageType -> false
|
||||||
is EmoteMessageType -> false
|
is EmoteMessageType -> false
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,12 @@ data class ImageMessageType(
|
||||||
val info: ImageInfo?
|
val info: ImageInfo?
|
||||||
) : MessageType
|
) : MessageType
|
||||||
|
|
||||||
|
data class StickerMessageType(
|
||||||
|
val body: String,
|
||||||
|
val source: MediaSource,
|
||||||
|
val info: ImageInfo?
|
||||||
|
) : MessageType
|
||||||
|
|
||||||
data class LocationMessageType(
|
data class LocationMessageType(
|
||||||
val body: String,
|
val body: String,
|
||||||
val geoUri: String,
|
val geoUri: String,
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageT
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
|
@ -231,6 +232,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
is EmoteMessageType -> "* $senderDisplayName ${messageType.body}"
|
is EmoteMessageType -> "* $senderDisplayName ${messageType.body}"
|
||||||
is FileMessageType -> messageType.body
|
is FileMessageType -> messageType.body
|
||||||
is ImageMessageType -> messageType.body
|
is ImageMessageType -> messageType.body
|
||||||
|
is StickerMessageType -> messageType.body
|
||||||
is NoticeMessageType -> messageType.body
|
is NoticeMessageType -> messageType.body
|
||||||
is TextMessageType -> messageType.toPlainText()
|
is TextMessageType -> messageType.toPlainText()
|
||||||
is VideoMessageType -> messageType.body
|
is VideoMessageType -> messageType.body
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageT
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
|
@ -234,6 +235,23 @@ class NotifiableEventResolverTest {
|
||||||
assertThat(result).isEqualTo(expectedResult)
|
assertThat(result).isEqualTo(expectedResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve event message sticker`() = runTest {
|
||||||
|
val sut = createNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
createNotificationData(
|
||||||
|
content = NotificationContent.MessageLike.RoomMessage(
|
||||||
|
senderId = A_USER_ID_2,
|
||||||
|
messageType = StickerMessageType("Sticker", MediaSource("url"), null),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val result = sut.resolveEvent(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID)
|
||||||
|
val expectedResult = createNotifiableMessageEvent(body = "Sticker")
|
||||||
|
assertThat(result).isEqualTo(expectedResult)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `resolve event message file`() = runTest {
|
fun `resolve event message file`() = runTest {
|
||||||
val sut = createNotifiableEventResolver(
|
val sut = createNotifiableEventResolver(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:2d3090c82ca29fbbce10efdb7d1720efe7a4eebb6fe2f871401fdc81f9c5a422
|
||||||
|
size 38433
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b0e56460df17a40455f62f6387ce169e70376561ec9fc74827e4ab63316a8210
|
||||||
|
size 51671
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:65dd1c851fa79f9180e371f4c0b0f0ba39b33040ee247ed2cfb754942db5def4
|
||||||
|
size 64822
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:8996238bb446dac62d49e322feab0b66e47de0a2b4b0f96e4f9294e5dd56c5e0
|
||||||
|
size 38518
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:3923a0d08cd0afdea404508886068c70c0653c79af558c44a4e96dc448e88fd0
|
||||||
|
size 51649
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fd3f2efe2de6b4709bfd91fff38c74f1444ff1508a159b4902e70dd65f6987b6
|
||||||
|
size 64144
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue