Merge pull request #2384 from element-hq/feature/bma/replyOnRedactedRendering
Reply on redacted and UTD rendering
This commit is contained in:
commit
76beb6bec4
224 changed files with 308 additions and 30 deletions
1
changelog.d/2318.misc
Normal file
1
changelog.d/2318.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Render correctly in reply to data when Event cannot be decrypted or has been redacted
|
||||||
|
|
@ -53,6 +53,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalViewConfiguration
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
import androidx.compose.ui.platform.ViewConfiguration
|
import androidx.compose.ui.platform.ViewConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
@ -92,6 +93,7 @@ import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
|
||||||
import io.element.android.libraries.designsystem.components.EqualWidthColumn
|
import io.element.android.libraries.designsystem.components.EqualWidthColumn
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.icons.CompoundDrawables
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.swipe.SwipeableActionsState
|
import io.element.android.libraries.designsystem.swipe.SwipeableActionsState
|
||||||
|
|
@ -648,18 +650,53 @@ private fun ReplyToContent(
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
Text(
|
ReplyToContentText(metadata)
|
||||||
text = metadata?.text.orEmpty(),
|
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
|
||||||
textAlign = TextAlign.Start,
|
|
||||||
color = ElementTheme.materialColors.secondary,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ReplyToContentText(metadata: InReplyToMetadata?) {
|
||||||
|
val text = when (metadata) {
|
||||||
|
InReplyToMetadata.Redacted -> stringResource(id = CommonStrings.common_message_removed)
|
||||||
|
InReplyToMetadata.UnableToDecrypt -> stringResource(id = CommonStrings.common_waiting_for_decryption_key)
|
||||||
|
is InReplyToMetadata.Text -> metadata.text
|
||||||
|
is InReplyToMetadata.Thumbnail -> metadata.text
|
||||||
|
null -> ""
|
||||||
|
}
|
||||||
|
val iconResourceId = when (metadata) {
|
||||||
|
InReplyToMetadata.Redacted -> CompoundDrawables.ic_compound_delete
|
||||||
|
InReplyToMetadata.UnableToDecrypt -> CompoundDrawables.ic_compound_time
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
val fontStyle = when (metadata) {
|
||||||
|
is InReplyToMetadata.Informative -> FontStyle.Italic
|
||||||
|
else -> FontStyle.Normal
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
if (iconResourceId != null) {
|
||||||
|
Icon(
|
||||||
|
resourceId = iconResourceId,
|
||||||
|
tint = MaterialTheme.colorScheme.secondary,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
|
fontStyle = fontStyle,
|
||||||
|
textAlign = TextAlign.Start,
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
maxLines = 2,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TimelineItemEventRowPreview() = ElementPreview {
|
internal fun TimelineItemEventRowPreview() = ElementPreview {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.InReplyToDetails
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun TimelineItemEventRowWithReplyInformativePreview(
|
||||||
|
@PreviewParameter(InReplyToDetailsInformativeProvider::class) inReplyToDetails: InReplyToDetails,
|
||||||
|
) = ElementPreview {
|
||||||
|
TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails)
|
||||||
|
}
|
||||||
|
|
||||||
|
class InReplyToDetailsInformativeProvider : InReplyToDetailsProvider() {
|
||||||
|
override val values: Sequence<InReplyToDetails>
|
||||||
|
get() = sequenceOf(
|
||||||
|
RedactedContent,
|
||||||
|
UnableToDecryptContent(UnableToDecryptContent.Data.Unknown),
|
||||||
|
).map {
|
||||||
|
aInReplyToDetails(
|
||||||
|
eventContent = it,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,11 @@ import kotlinx.collections.immutable.persistentMapOf
|
||||||
internal fun TimelineItemEventRowWithReplyPreview(
|
internal fun TimelineItemEventRowWithReplyPreview(
|
||||||
@PreviewParameter(InReplyToDetailsProvider::class) inReplyToDetails: InReplyToDetails,
|
@PreviewParameter(InReplyToDetailsProvider::class) inReplyToDetails: InReplyToDetails,
|
||||||
) = ElementPreview {
|
) = ElementPreview {
|
||||||
|
TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails: InReplyToDetails) {
|
||||||
Column {
|
Column {
|
||||||
sequenceOf(false, true).forEach {
|
sequenceOf(false, true).forEach {
|
||||||
ATimelineItemEventRow(
|
ATimelineItemEventRow(
|
||||||
|
|
@ -83,7 +88,7 @@ internal fun TimelineItemEventRowWithReplyPreview(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
|
open class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
|
||||||
override val values: Sequence<InReplyToDetails>
|
override val values: Sequence<InReplyToDetails>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
aMessageContent(
|
aMessageContent(
|
||||||
|
|
@ -156,7 +161,7 @@ class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
|
||||||
type = type,
|
type = type,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun aInReplyToDetails(
|
protected fun aInReplyToDetails(
|
||||||
eventContent: EventContent,
|
eventContent: EventContent,
|
||||||
) = InReplyToDetails(
|
) = InReplyToDetails(
|
||||||
eventId = EventId("\$event"),
|
eventId = EventId("\$event"),
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,20 @@ 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.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.FailedToParseMessageLikeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
|
||||||
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.ProfileChangeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
|
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.StickerContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
|
||||||
|
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.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
|
||||||
|
|
@ -35,17 +43,20 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
internal sealed interface InReplyToMetadata {
|
internal sealed interface InReplyToMetadata {
|
||||||
val text: String?
|
|
||||||
|
|
||||||
data class Thumbnail(
|
data class Thumbnail(
|
||||||
val attachmentThumbnailInfo: AttachmentThumbnailInfo
|
val attachmentThumbnailInfo: AttachmentThumbnailInfo
|
||||||
) : InReplyToMetadata {
|
) : InReplyToMetadata {
|
||||||
override val text: String? = attachmentThumbnailInfo.textContent
|
val text: String = attachmentThumbnailInfo.textContent.orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Text(
|
data class Text(
|
||||||
override val text: String
|
val text: String
|
||||||
) : InReplyToMetadata
|
) : InReplyToMetadata
|
||||||
|
|
||||||
|
sealed interface Informative : InReplyToMetadata
|
||||||
|
|
||||||
|
data object Redacted : Informative
|
||||||
|
data object UnableToDecrypt : Informative
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -103,7 +114,8 @@ internal fun InReplyToDetails.metadata(): InReplyToMetadata? = when (eventConten
|
||||||
AttachmentThumbnailInfo(
|
AttachmentThumbnailInfo(
|
||||||
thumbnailSource = MediaSource(eventContent.url),
|
thumbnailSource = MediaSource(eventContent.url),
|
||||||
textContent = eventContent.body,
|
textContent = eventContent.body,
|
||||||
type = AttachmentThumbnailType.Image
|
type = AttachmentThumbnailType.Image,
|
||||||
|
blurHash = eventContent.info.blurhash,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
is PollContent -> InReplyToMetadata.Thumbnail(
|
is PollContent -> InReplyToMetadata.Thumbnail(
|
||||||
|
|
@ -112,5 +124,13 @@ internal fun InReplyToDetails.metadata(): InReplyToMetadata? = when (eventConten
|
||||||
type = AttachmentThumbnailType.Poll,
|
type = AttachmentThumbnailType.Poll,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else -> null
|
is RedactedContent -> InReplyToMetadata.Redacted
|
||||||
|
is UnableToDecryptContent -> InReplyToMetadata.UnableToDecrypt
|
||||||
|
is FailedToParseMessageLikeContent,
|
||||||
|
is FailedToParseStateContent,
|
||||||
|
is ProfileChangeContent,
|
||||||
|
is RoomMembershipContent,
|
||||||
|
is StateContent,
|
||||||
|
UnknownContent,
|
||||||
|
null -> null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,23 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.media.AudioInfo
|
import io.element.android.libraries.matrix.api.media.AudioInfo
|
||||||
import io.element.android.libraries.matrix.api.media.FileInfo
|
import io.element.android.libraries.matrix.api.media.FileInfo
|
||||||
|
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||||
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.EventContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
|
||||||
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.OtherState
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
|
||||||
|
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.StickerContent
|
||||||
|
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.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.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
|
@ -45,11 +55,13 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.media.aMediaSource
|
import io.element.android.libraries.matrix.test.media.aMediaSource
|
||||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||||
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
||||||
|
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class InReplyToMetadataKtTest {
|
class InReplyToMetadataKtTest {
|
||||||
|
|
@ -72,7 +84,7 @@ class InReplyToMetadataKtTest {
|
||||||
messageType = ImageMessageType(
|
messageType = ImageMessageType(
|
||||||
body = "body",
|
body = "body",
|
||||||
source = aMediaSource(),
|
source = aMediaSource(),
|
||||||
info = null,
|
info = anImageInfo(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).metadata()
|
).metadata()
|
||||||
|
|
@ -84,7 +96,33 @@ class InReplyToMetadataKtTest {
|
||||||
thumbnailSource = aMediaSource(),
|
thumbnailSource = aMediaSource(),
|
||||||
textContent = "body",
|
textContent = "body",
|
||||||
type = AttachmentThumbnailType.Image,
|
type = AttachmentThumbnailType.Image,
|
||||||
blurHash = null,
|
blurHash = A_BLUR_HASH,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `a sticker message content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = StickerContent(
|
||||||
|
body = "body",
|
||||||
|
info = anImageInfo(),
|
||||||
|
url = "url"
|
||||||
|
)
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isEqualTo(
|
||||||
|
InReplyToMetadata.Thumbnail(
|
||||||
|
attachmentThumbnailInfo = AttachmentThumbnailInfo(
|
||||||
|
thumbnailSource = aMediaSource(url = "url"),
|
||||||
|
textContent = "body",
|
||||||
|
type = AttachmentThumbnailType.Image,
|
||||||
|
blurHash = A_BLUR_HASH,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -100,16 +138,7 @@ class InReplyToMetadataKtTest {
|
||||||
messageType = VideoMessageType(
|
messageType = VideoMessageType(
|
||||||
body = "body",
|
body = "body",
|
||||||
source = aMediaSource(),
|
source = aMediaSource(),
|
||||||
info = VideoInfo(
|
info = aVideoInfo(),
|
||||||
duration = null,
|
|
||||||
height = null,
|
|
||||||
width = null,
|
|
||||||
mimetype = null,
|
|
||||||
size = null,
|
|
||||||
thumbnailInfo = null,
|
|
||||||
thumbnailSource = aMediaSource(),
|
|
||||||
blurhash = null
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).metadata()
|
).metadata()
|
||||||
|
|
@ -121,7 +150,7 @@ class InReplyToMetadataKtTest {
|
||||||
thumbnailSource = aMediaSource(),
|
thumbnailSource = aMediaSource(),
|
||||||
textContent = "body",
|
textContent = "body",
|
||||||
type = AttachmentThumbnailType.Video,
|
type = AttachmentThumbnailType.Video,
|
||||||
blurHash = null,
|
blurHash = A_BLUR_HASH,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -277,11 +306,115 @@ class InReplyToMetadataKtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `any other content`() = runTest {
|
fun `redacted content`() = runTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
anInReplyToDetails(
|
anInReplyToDetails(
|
||||||
eventContent = RedactedContent
|
eventContent = RedactedContent
|
||||||
).metadata()
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isEqualTo(InReplyToMetadata.Redacted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `unable to decrypt content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = UnableToDecryptContent(UnableToDecryptContent.Data.Unknown)
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isEqualTo(InReplyToMetadata.UnableToDecrypt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `failed to parse message content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = FailedToParseMessageLikeContent("", "")
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `failed to parse state content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = FailedToParseStateContent("", "", "")
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `profile change content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = ProfileChangeContent("", "", "", "")
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `room membership content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = RoomMembershipContent(A_USER_ID, null)
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `state content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = StateContent("", OtherState.RoomJoinRules)
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `unknown content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = UnknownContent
|
||||||
|
).metadata()
|
||||||
|
}.test {
|
||||||
|
awaitItem().let {
|
||||||
|
assertThat(it).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `null content`() = runTest {
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
anInReplyToDetails(
|
||||||
|
eventContent = null
|
||||||
|
).metadata()
|
||||||
}.test {
|
}.test {
|
||||||
awaitItem().let {
|
awaitItem().let {
|
||||||
assertThat(it).isNull()
|
assertThat(it).isNull()
|
||||||
|
|
@ -306,6 +439,31 @@ fun anInReplyToDetails(
|
||||||
textContent = textContent,
|
textContent = textContent,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun aVideoInfo(): VideoInfo {
|
||||||
|
return VideoInfo(
|
||||||
|
duration = 1.minutes,
|
||||||
|
height = 100,
|
||||||
|
width = 100,
|
||||||
|
mimetype = "video/mp4",
|
||||||
|
size = 1000,
|
||||||
|
thumbnailInfo = null,
|
||||||
|
thumbnailSource = aMediaSource(),
|
||||||
|
blurhash = A_BLUR_HASH,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anImageInfo(): ImageInfo {
|
||||||
|
return ImageInfo(
|
||||||
|
height = 100,
|
||||||
|
width = 100,
|
||||||
|
mimetype = "image/jpeg",
|
||||||
|
size = 1000,
|
||||||
|
thumbnailInfo = null,
|
||||||
|
thumbnailSource = aMediaSource(),
|
||||||
|
blurhash = A_BLUR_HASH,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun testEnv(content: @Composable () -> Any?): Any? {
|
private fun testEnv(content: @Composable () -> Any?): Any? {
|
||||||
var result: Any? = null
|
var result: Any? = null
|
||||||
|
|
|
||||||
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