From 7a426ab1e78425d18e27cc3450421da024194f51 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 4 Nov 2022 09:10:48 +0000 Subject: [PATCH 1/3] add dedicated redacted message type in order to render it separately --- .../main/kotlin/app/dapk/st/engine/Models.kt | 10 ++++- .../app/dapk/st/design/components/Bubble.kt | 43 +++++++++++++++++-- .../app/dapk/st/messenger/MessengerScreen.kt | 1 + .../st/messenger/state/MessengerReducer.kt | 2 + .../RoomEventsToNotifiableMapper.kt | 1 + .../app/dapk/st/engine/LocalEchoMapper.kt | 1 + .../app/dapk/st/engine/MappingExtensions.kt | 3 +- .../app/dapk/st/matrix/sync/RoomState.kt | 15 ++++--- .../sync/internal/room/RoomEventsDecrypter.kt | 3 +- .../sync/internal/sync/RoomDataSource.kt | 8 ++-- .../sync/internal/sync/RoomEventCreator.kt | 7 +++ .../sync/internal/sync/RoomProcessor.kt | 1 + .../internal/sync/UnreadEventsProcessor.kt | 1 + 13 files changed, 79 insertions(+), 17 deletions(-) diff --git a/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt b/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt index 4efb5d6..d253b33 100644 --- a/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt +++ b/chat-engine/src/main/kotlin/app/dapk/st/engine/Models.kt @@ -124,6 +124,15 @@ sealed class RoomEvent { } + data class Redacted( + override val eventId: EventId, + override val utcTimestamp: Long, + override val author: RoomMember, + ) : RoomEvent() { + override val edited: Boolean = false + override val meta: MessageMeta = MessageMeta.FromServer + } + data class Message( override val eventId: EventId, override val utcTimestamp: Long, @@ -131,7 +140,6 @@ sealed class RoomEvent { override val author: RoomMember, override val meta: MessageMeta, override val edited: Boolean = false, - val redacted: Boolean = false, ) : RoomEvent() data class Reply( diff --git a/design-library/src/main/kotlin/app/dapk/st/design/components/Bubble.kt b/design-library/src/main/kotlin/app/dapk/st/design/components/Bubble.kt index f03c16d..345dde5 100644 --- a/design-library/src/main/kotlin/app/dapk/st/design/components/Bubble.kt +++ b/design-library/src/main/kotlin/app/dapk/st/design/components/Bubble.kt @@ -8,6 +8,11 @@ import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Recycling +import androidx.compose.material.icons.outlined.DeleteOutline +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -31,12 +36,14 @@ import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest private val ENCRYPTED_MESSAGE = RichText(listOf(RichText.Part.Normal("Encrypted message"))) +private val DELETED_MESSAGE = RichText(listOf(RichText.Part.Italic("Message deleted"))) sealed interface BubbleModel { val event: Event data class Text(val content: RichText, override val event: Event) : BubbleModel data class Encrypted(override val event: Event) : BubbleModel + data class Redacted(override val event: Event) : BubbleModel data class Image(val imageContent: ImageContent, val imageRequest: ImageRequest, override val event: Event) : BubbleModel { data class ImageContent(val width: Int?, val height: Int?, val url: String) } @@ -64,6 +71,7 @@ fun MessageBubble(bubble: BubbleMeta, model: BubbleModel, status: @Composable () is BubbleModel.Encrypted -> EncryptedBubble(bubble, model, status, itemisedLongClick) is BubbleModel.Image -> ImageBubble(bubble, model, status, onItemClick = { actions.onImageClick(model) }, itemisedLongClick) is BubbleModel.Reply -> ReplyBubble(bubble, model, status, itemisedLongClick) + is BubbleModel.Redacted -> RedactedBubble(bubble, model, status) } } @@ -156,6 +164,8 @@ private fun ReplyBubble(bubble: BubbleMeta, model: BubbleModel.Reply, status: @C is BubbleModel.Reply -> { // TODO - a reply to a reply } + + is BubbleModel.Redacted -> RedactedContent(bubble) } } @@ -180,6 +190,8 @@ private fun ReplyBubble(bubble: BubbleMeta, model: BubbleModel.Reply, status: @C is BubbleModel.Reply -> { // TODO - a reply to a reply } + + is BubbleModel.Redacted -> RedactedContent(bubble) } Footer(model.event, bubble, status) @@ -206,10 +218,29 @@ private fun Int.scalerFor(max: Float): Float { return max / this } +@Composable +private fun RedactedBubble(bubble: BubbleMeta, model: BubbleModel.Redacted, status: @Composable () -> Unit) { + Bubble(bubble) { + if (bubble.isNotSelf()) { + AuthorName(model.event, bubble) + } + RedactedContent(bubble) + Footer(model.event, bubble, status) + } +} + +@Composable +private fun RedactedContent(bubble: BubbleMeta) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 4.dp, end = 4.dp)) { + Icon(modifier = Modifier.height(20.dp), imageVector = Icons.Outlined.DeleteOutline, contentDescription = null) + Spacer(Modifier.width(4.dp)) + TextContent(bubble, text = DELETED_MESSAGE, fontSize = 13) + } +} @OptIn(ExperimentalFoundationApi::class) @Composable -private fun Bubble(bubble: BubbleMeta, onItemClick: () -> Unit, onLongClick: () -> Unit, content: @Composable () -> Unit) { +private fun Bubble(bubble: BubbleMeta, onItemClick: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null, content: @Composable () -> Unit) { Box(modifier = Modifier.padding(start = 6.dp)) { Box( Modifier @@ -217,7 +248,7 @@ private fun Bubble(bubble: BubbleMeta, onItemClick: () -> Unit, onLongClick: () .clip(bubble.shape) .background(bubble.background) .height(IntrinsicSize.Max) - .combinedClickable(onLongClick = onLongClick, onClick = onItemClick), + .combinedClickable(onLongClick = onLongClick, onClick = onItemClick ?: {}), ) { Column( Modifier @@ -247,12 +278,16 @@ private fun Footer(event: BubbleModel.Event, bubble: BubbleMeta, status: @Compos } @Composable -private fun TextContent(bubble: BubbleMeta, text: RichText) { +private fun TextContent(bubble: BubbleMeta, text: RichText, isAlternative: Boolean = false, fontSize: Int = 15) { val annotatedText = text.toAnnotatedText() val uriHandler = LocalUriHandler.current ClickableText( text = annotatedText, - style = TextStyle(color = bubble.textColor(), fontSize = 15.sp, textAlign = TextAlign.Start), + style = TextStyle( + color = if (isAlternative) bubble.textColor().copy(alpha = 0.8f) else bubble.textColor(), + fontSize = fontSize.sp, + textAlign = TextAlign.Start + ), modifier = Modifier.wrapContentSize(), onClick = { annotatedText.getStringAnnotations("url", it, it).firstOrNull()?.let { diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt index e1c4c32..83bad7e 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/MessengerScreen.kt @@ -316,6 +316,7 @@ private fun RoomEvent.toModel(): BubbleModel { return when (this) { is RoomEvent.Message -> BubbleModel.Text(this.content.toApp(), event) is RoomEvent.Encrypted -> BubbleModel.Encrypted(event) + is RoomEvent.Redacted -> BubbleModel.Redacted(event) is RoomEvent.Image -> { val imageRequest = LocalImageRequestFactory.current .memoryCacheKey(this.imageMeta.url) diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/state/MessengerReducer.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/state/MessengerReducer.kt index 0d66d8b..b7e7c8f 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/state/MessengerReducer.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/state/MessengerReducer.kt @@ -176,6 +176,7 @@ private fun RoomEvent.toSendMessageReply() = SendMessage.TextMessage.Reply( originalMessage = when (this) { is RoomEvent.Image -> TODO() is RoomEvent.Reply -> TODO() + is RoomEvent.Redacted -> TODO() is RoomEvent.Message -> this.content.asString() is RoomEvent.Encrypted -> error("Should never happen") }, @@ -190,6 +191,7 @@ private fun initialComposerState(initialAttachments: List?) = private fun BubbleModel.findCopyableContent(): CopyableResult = when (this) { is BubbleModel.Encrypted -> CopyableResult.NothingToCopy + is BubbleModel.Redacted -> CopyableResult.NothingToCopy is BubbleModel.Image -> CopyableResult.NothingToCopy is BubbleModel.Reply -> this.reply.findCopyableContent() is BubbleModel.Text -> CopyableResult.Content(CopyToClipboard.Copyable.Text(this.content.asString())) diff --git a/features/notifications/src/main/kotlin/app/dapk/st/notifications/RoomEventsToNotifiableMapper.kt b/features/notifications/src/main/kotlin/app/dapk/st/notifications/RoomEventsToNotifiableMapper.kt index e53d31c..d15c5cc 100644 --- a/features/notifications/src/main/kotlin/app/dapk/st/notifications/RoomEventsToNotifiableMapper.kt +++ b/features/notifications/src/main/kotlin/app/dapk/st/notifications/RoomEventsToNotifiableMapper.kt @@ -15,6 +15,7 @@ class RoomEventsToNotifiableMapper { is RoomEvent.Message -> this.content.asString() is RoomEvent.Reply -> this.message.toNotifiableContent() is RoomEvent.Encrypted -> "Encrypted message" + is RoomEvent.Redacted -> "Deleted message" } } diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/LocalEchoMapper.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/LocalEchoMapper.kt index 93e3740..a415b78 100644 --- a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/LocalEchoMapper.kt +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/LocalEchoMapper.kt @@ -48,6 +48,7 @@ internal class LocalEchoMapper(private val metaMapper: MetaMapper) { is RoomEvent.Reply -> this.copy(message = this.message.mergeWith(echo)) is RoomEvent.Image -> this.copy(meta = metaMapper.toMeta(echo)) is RoomEvent.Encrypted -> this.copy(meta = metaMapper.toMeta(echo)) + is RoomEvent.Redacted -> this } } diff --git a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt index 94a7587..64bc368 100644 --- a/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt +++ b/matrix-chat-engine/src/main/kotlin/app/dapk/st/engine/MappingExtensions.kt @@ -88,9 +88,10 @@ fun MatrixRoomState.engine() = RoomState( fun MatrixRoomEvent.engine(): RoomEvent = when (this) { is MatrixRoomEvent.Image -> RoomEvent.Image(this.eventId, this.utcTimestamp, this.imageMeta.engine(), this.author, this.meta.engine(), this.edited) - is MatrixRoomEvent.Message -> RoomEvent.Message(this.eventId, this.utcTimestamp, this.content, this.author, this.meta.engine(), this.edited, this.redacted) + is MatrixRoomEvent.Message -> RoomEvent.Message(this.eventId, this.utcTimestamp, this.content, this.author, this.meta.engine(), this.edited) is MatrixRoomEvent.Reply -> RoomEvent.Reply(this.message.engine(), this.replyingTo.engine()) is MatrixRoomEvent.Encrypted -> RoomEvent.Encrypted(this.eventId, this.utcTimestamp, this.author, this.meta.engine()) + is MatrixRoomEvent.Redacted -> RoomEvent.Redacted(this.eventId, this.utcTimestamp, this.author) } fun MatrixRoomEvent.Image.ImageMeta.engine() = RoomEvent.Image.ImageMeta( diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/RoomState.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/RoomState.kt index 98ccab6..79ed163 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/RoomState.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/RoomState.kt @@ -16,7 +16,6 @@ sealed class RoomEvent { abstract val utcTimestamp: Long abstract val author: RoomMember abstract val meta: MessageMeta - abstract val redacted: Boolean @Serializable @SerialName("encrypted") @@ -26,7 +25,6 @@ sealed class RoomEvent { @SerialName("author") override val author: RoomMember, @SerialName("meta") override val meta: MessageMeta, @SerialName("edited") val edited: Boolean = false, - @SerialName("redacted") override val redacted: Boolean = false, @SerialName("encrypted_content") val encryptedContent: MegOlmV1, ) : RoomEvent() { @@ -40,6 +38,16 @@ sealed class RoomEvent { } + @Serializable + @SerialName("redacted") + data class Redacted( + @SerialName("event_id") override val eventId: EventId, + @SerialName("timestamp") override val utcTimestamp: Long, + @SerialName("author") override val author: RoomMember, + ) : RoomEvent() { + override val meta: MessageMeta = MessageMeta.FromServer + } + @Serializable @SerialName("message") data class Message( @@ -49,7 +57,6 @@ sealed class RoomEvent { @SerialName("author") override val author: RoomMember, @SerialName("meta") override val meta: MessageMeta, @SerialName("edited") val edited: Boolean = false, - @SerialName("redacted") override val redacted: Boolean = false, ) : RoomEvent() @Serializable @@ -63,7 +70,6 @@ sealed class RoomEvent { override val utcTimestamp: Long = message.utcTimestamp override val author: RoomMember = message.author override val meta: MessageMeta = message.meta - override val redacted: Boolean = message.redacted } @@ -76,7 +82,6 @@ sealed class RoomEvent { @SerialName("author") override val author: RoomMember, @SerialName("meta") override val meta: MessageMeta, @SerialName("edited") val edited: Boolean = false, - @SerialName("redacted") override val redacted: Boolean = false, ) : RoomEvent() { @Serializable diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypter.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypter.kt index 3e2c540..79dbf2e 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypter.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypter.kt @@ -29,6 +29,7 @@ internal class RoomEventsDecrypter( ) is RoomEvent.Image -> event + is RoomEvent.Redacted -> event } private suspend fun RoomEvent.Encrypted.decrypt(userCredentials: UserCredentials) = when (val result = this.decryptContent()) { @@ -51,7 +52,6 @@ internal class RoomEventsDecrypter( author = this.author, meta = this.meta, edited = this.edited, - redacted = this.redacted, content = richMessageParser.parse(content.body ?: "") ) @@ -61,7 +61,6 @@ internal class RoomEventsDecrypter( author = this.author, meta = this.meta, edited = this.edited, - redacted = this.redacted, imageMeta = RoomEvent.Image.ImageMeta( width = content.info?.width, height = content.info?.height, diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomDataSource.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomDataSource.kt index aecbe6b..794ff24 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomDataSource.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomDataSource.kt @@ -33,8 +33,8 @@ class RoomDataSource( roomStore.remove(roomsLeft) } - suspend fun redact(roomId: RoomId, event: EventId) { - val eventToRedactFromCache = roomCache[roomId]?.events?.find { it.eventId == event } + suspend fun redact(roomId: RoomId, eventId: EventId) { + val eventToRedactFromCache = roomCache[roomId]?.events?.find { it.eventId == eventId } val redactedEvent = when { eventToRedactFromCache != null -> { eventToRedactFromCache.redact().also { redacted -> @@ -44,14 +44,14 @@ class RoomDataSource( } } - else -> roomStore.findEvent(event)?.redact() + else -> roomStore.findEvent(eventId)?.redact() } redactedEvent?.let { roomStore.persist(roomId, listOf(it)) } } } -private fun RoomEvent.redact() = RoomEvent.Message(this.eventId, this.utcTimestamp, RichText.of("Redacted"), this.author, this.meta, redacted = true) +private fun RoomEvent.redact() = RoomEvent.Redacted(this.eventId, this.utcTimestamp, this.author) private fun RoomState.replaceEvent(old: RoomEvent, new: RoomEvent): RoomState { val updatedEvents = this.events.toMutableList().apply { diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt index 5ee8a21..74c7622 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt @@ -83,6 +83,7 @@ internal class TimelineEventMapper( is RoomEvent.Reply -> relationEvent.message is RoomEvent.Image -> relationEvent is RoomEvent.Encrypted -> relationEvent + is RoomEvent.Redacted -> relationEvent } ) } @@ -115,6 +116,7 @@ internal class TimelineEventMapper( is RoomEvent.Message -> original.message.edited(incomingEdit) is RoomEvent.Reply -> original.message is RoomEvent.Encrypted -> original.message + is RoomEvent.Redacted -> original.message } ) @@ -127,6 +129,11 @@ internal class TimelineEventMapper( // can't edit encrypted messages null } + + is RoomEvent.Redacted -> { + // can't edit redacted + null + } } } } diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomProcessor.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomProcessor.kt index ef90cb8..5f1d3f7 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomProcessor.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomProcessor.kt @@ -79,4 +79,5 @@ private fun RoomEvent.toTextContent(): String = when (this) { is RoomEvent.Message -> this.content.asString() is RoomEvent.Reply -> this.message.toTextContent() is RoomEvent.Encrypted -> "Encrypted message" + is RoomEvent.Redacted -> "Message deleted" } \ No newline at end of file diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/UnreadEventsProcessor.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/UnreadEventsProcessor.kt index b6db3f8..6c5a0c6 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/UnreadEventsProcessor.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/UnreadEventsProcessor.kt @@ -47,6 +47,7 @@ internal class UnreadEventsProcessor( is RoomEvent.Reply -> it.message.author.id == selfId is RoomEvent.Image -> it.author.id == selfId is RoomEvent.Encrypted -> it.author.id == selfId + is RoomEvent.Redacted -> it.author.id == selfId } }.map { it.eventId } roomStore.insertUnread(overview.roomId, eventsFromOthers) From d3070d578ab3650b6fe7f9cf49888f037887e7bf Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 4 Nov 2022 09:15:02 +0000 Subject: [PATCH 2/3] removing manual redacted text fallback and using empty instead --- .../sync/internal/sync/RoomEventCreator.kt | 10 +++++----- .../sync/internal/sync/message/PartBuilder.kt | 19 ++++++++++++------- .../internal/room/RoomEventsDecrypterTest.kt | 1 - .../internal/sync/RoomEventCreatorTest.kt | 4 ++-- .../kotlin/fixture/RoomEventFixture.kt | 3 +-- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt index 74c7622..24fcef9 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreator.kt @@ -96,7 +96,7 @@ internal class TimelineEventMapper( ApiTimelineEvent.TimelineMessage.Content.Ignored -> throw IllegalStateException() } - private suspend fun ApiTimelineEvent.TimelineMessage.toFallbackTextMessage() = this.toTextMessage(content = this.asTextContent().body ?: "redacted") + private suspend fun ApiTimelineEvent.TimelineMessage.toFallbackTextMessage() = this.toTextMessage(content = this.asTextContent().body ?: "") private suspend fun ApiTimelineEvent.TimelineMessage.handleEdit(editedEventId: EventId, lookup: Lookup): RoomEvent? { return lookup(editedEventId).fold( @@ -148,7 +148,7 @@ internal class TimelineEventMapper( is ApiTimelineEvent.TimelineMessage.Content.Text -> original.toTextMessage( utcTimestamp = incomingEdit.utcTimestamp, - content = incomingEdit.asTextContent().let { it.formattedBody ?: it.body }?.removePrefix(" * ") ?: "redacted", + content = incomingEdit.asTextContent().let { it.formattedBody ?: it.body }?.removePrefix(" * ") ?: "", edited = true, ) @@ -158,7 +158,7 @@ internal class TimelineEventMapper( } private fun RoomEvent.Message.edited(edit: ApiTimelineEvent.TimelineMessage) = this.copy( - content = richMessageParser.parse(edit.asTextContent().let { it.formattedBody ?: it.body }?.removePrefix(" * ") ?: "redacted"), + content = richMessageParser.parse(edit.asTextContent().let { it.formattedBody ?: it.body }?.removePrefix(" * ") ?: ""), edited = true, ) @@ -167,7 +167,7 @@ internal class TimelineEventMapper( is ApiTimelineEvent.TimelineMessage.Content.Image -> source.toImageMessage(userCredentials, roomId) is ApiTimelineEvent.TimelineMessage.Content.Text -> source.toTextMessage( roomId, - content = source.asTextContent().formattedBody ?: source.content.body ?: "redacted" + content = source.asTextContent().formattedBody ?: source.content.body ?: "" ) ApiTimelineEvent.TimelineMessage.Content.Ignored -> throw IllegalStateException() @@ -175,7 +175,7 @@ internal class TimelineEventMapper( } private suspend fun ApiTimelineEvent.TimelineMessage.toTextMessage( - content: String = this.asTextContent().formattedBody ?: this.asTextContent().body ?: "redacted", + content: String = this.asTextContent().formattedBody ?: this.asTextContent().body ?: "", edited: Boolean = false, utcTimestamp: Long = this.utcTimestamp, ) = with(roomEventFactory) { toTextMessage(roomId, content, edited, utcTimestamp) } diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/message/PartBuilder.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/message/PartBuilder.kt index 2cbf4e1..e71a548 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/message/PartBuilder.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/message/PartBuilder.kt @@ -37,15 +37,20 @@ internal class PartBuilder { fun build(): List { flushNormalBuffer() - val last = parts.last() - if (last is RichText.Part.Normal) { - parts.removeLast() - val newContent = last.content.trimEnd() - if (newContent.isNotEmpty()) { - parts.add(last.copy(content = newContent)) + return when(parts.isEmpty()) { + true -> parts + else -> { + val last = parts.last() + if (last is RichText.Part.Normal) { + parts.removeLast() + val newContent = last.content.trimEnd() + if (newContent.isNotEmpty()) { + parts.add(last.copy(content = newContent)) + } + } + parts } } - return parts } private fun flushNormalBuffer() { diff --git a/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypterTest.kt b/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypterTest.kt index dea7f06..ee3bbd0 100644 --- a/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypterTest.kt +++ b/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/room/RoomEventsDecrypterTest.kt @@ -95,5 +95,4 @@ private fun RoomEvent.Encrypted.toText(text: String) = RoomEvent.Message( this.author, this.meta, this.edited, - this.redacted, ) \ No newline at end of file diff --git a/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreatorTest.kt b/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreatorTest.kt index 45ab70b..1cff200 100644 --- a/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreatorTest.kt +++ b/matrix/services/sync/src/test/kotlin/app/dapk/st/matrix/sync/internal/sync/RoomEventCreatorTest.kt @@ -88,7 +88,7 @@ internal class RoomEventCreatorTest { } @Test - fun `given text event without body then maps to redacted room message`() = runTest { + fun `given text event without body then maps to empty room message`() = runTest { fakeRoomMembersService.givenMember(A_ROOM_ID, A_SENDER.id, A_SENDER) val result = with(roomEventCreator) { A_TEXT_EVENT_WITHOUT_CONTENT.toRoomEvent(A_USER_CREDENTIALS, A_ROOM_ID, EMPTY_LOOKUP) } @@ -96,7 +96,7 @@ internal class RoomEventCreatorTest { result shouldBeEqualTo aMatrixRoomMessageEvent( eventId = A_TEXT_EVENT_WITHOUT_CONTENT.id, utcTimestamp = A_TEXT_EVENT_WITHOUT_CONTENT.utcTimestamp, - content = RichText.of("redacted"), + content = RichText(emptyList()), author = A_SENDER, ) } diff --git a/matrix/services/sync/src/testFixtures/kotlin/fixture/RoomEventFixture.kt b/matrix/services/sync/src/testFixtures/kotlin/fixture/RoomEventFixture.kt index 4228454..0d20981 100644 --- a/matrix/services/sync/src/testFixtures/kotlin/fixture/RoomEventFixture.kt +++ b/matrix/services/sync/src/testFixtures/kotlin/fixture/RoomEventFixture.kt @@ -34,8 +34,7 @@ fun anEncryptedRoomMessageEvent( meta: MessageMeta = MessageMeta.FromServer, encryptedContent: RoomEvent.Encrypted.MegOlmV1 = aMegolmV1(), edited: Boolean = false, - redacted: Boolean = false, -) = RoomEvent.Encrypted(eventId, utcTimestamp, author, meta, edited, redacted, encryptedContent) +) = RoomEvent.Encrypted(eventId, utcTimestamp, author, meta, edited, encryptedContent) fun aMegolmV1( cipherText: CipherText = CipherText("a-cipher"), From 2739aa8ba573c1ec7a2d7c4228bfd8601a927922 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 4 Nov 2022 09:27:16 +0000 Subject: [PATCH 3/3] fixing test compilation errors --- chat-engine/src/testFixtures/kotlin/fixture/Fixtures.kt | 3 +-- .../test/kotlin/app/dapk/st/messenger/MessengerReducerTest.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/chat-engine/src/testFixtures/kotlin/fixture/Fixtures.kt b/chat-engine/src/testFixtures/kotlin/fixture/Fixtures.kt index b36c6be..1b00d15 100644 --- a/chat-engine/src/testFixtures/kotlin/fixture/Fixtures.kt +++ b/chat-engine/src/testFixtures/kotlin/fixture/Fixtures.kt @@ -28,8 +28,7 @@ fun anEncryptedRoomMessageEvent( author: RoomMember = aRoomMember(), meta: MessageMeta = MessageMeta.FromServer, edited: Boolean = false, - redacted: Boolean = false, -) = RoomEvent.Message(eventId, utcTimestamp, content, author, meta, edited, redacted) +) = RoomEvent.Message(eventId, utcTimestamp, content, author, meta, edited) fun aRoomImageMessageEvent( eventId: EventId = anEventId(), diff --git a/features/messenger/src/test/kotlin/app/dapk/st/messenger/MessengerReducerTest.kt b/features/messenger/src/test/kotlin/app/dapk/st/messenger/MessengerReducerTest.kt index 91c0540..5ac645d 100644 --- a/features/messenger/src/test/kotlin/app/dapk/st/messenger/MessengerReducerTest.kt +++ b/features/messenger/src/test/kotlin/app/dapk/st/messenger/MessengerReducerTest.kt @@ -28,7 +28,6 @@ private const val READ_RECEIPTS_ARE_DISABLED = true private val A_ROOM_ID = aRoomId("messenger state room id") private const val A_MESSAGE_CONTENT = "message content" private val AN_EVENT_ID = anEventId("state event") -private const val ROOM_IS_MUTED = true private val A_SELF_ID = aUserId("self") private val A_MESSENGER_PAGE_STATE = aMessengerStateWithEvent(AN_EVENT_ID, A_SELF_ID) private val A_MESSAGE_ATTACHMENT = MessageAttachment(AndroidUri("a-uri"), MimeType.Image) @@ -314,6 +313,7 @@ class MessengerReducerTest { originalMessage = when (this) { is RoomEvent.Image -> TODO() is RoomEvent.Reply -> TODO() + is RoomEvent.Redacted -> TODO() is RoomEvent.Message -> this.content.asString() is RoomEvent.Encrypted -> error("Should never happen") },