From 95d6b6e58b4ab6fbaa467c353f90e0f0f0788cf6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 11:40:07 +0200 Subject: [PATCH 01/10] Thread decoration: create the ThreadDecoration ui --- .../components/TimelineItemEventRow.kt | 108 ++++++++++++------ .../res/drawable/ic_thread_decoration.xml | 15 +++ 2 files changed, 87 insertions(+), 36 deletions(-) create mode 100644 libraries/designsystem/src/main/res/drawable/ic_thread_decoration.xml diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 7e21ff649d..122fa03b25 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -75,6 +75,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent +import io.element.android.libraries.designsystem.R import io.element.android.libraries.designsystem.colors.AvatarColorsProvider import io.element.android.libraries.designsystem.components.EqualWidthColumn import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -84,6 +85,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.swipe.SwipeableActionsState import io.element.android.libraries.designsystem.swipe.rememberSwipeableActionsState import io.element.android.libraries.designsystem.text.toPx +import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId @@ -370,14 +372,6 @@ private fun MessageEventBubbleContent( onPollAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, @SuppressLint("ModifierParameter") bubbleModifier: Modifier = Modifier, // need to rename this modifier to distinguish it from the following ones ) { - val timestampPosition = when (event.content) { - is TimelineItemImageContent, - is TimelineItemVideoContent, - is TimelineItemLocationContent -> TimestampPosition.Overlay - is TimelineItemPollContent -> TimestampPosition.Below - else -> TimestampPosition.Default - } - val replyToDetails = event.inReplyTo as? InReplyTo.Ready // Long clicks are not not automatically propagated from a `clickable` // to its `combinedClickable` parent so we do it manually @@ -398,6 +392,21 @@ private fun MessageEventBubbleContent( ) } + @Composable + fun ThreadDecoration( + modifier: Modifier = Modifier + ) { + Row(modifier, verticalAlignment = Alignment.CenterVertically) { + Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = "Thread", + style = ElementTheme.typography.fontBodyXsRegular, + color = ElementTheme.colors.textPrimary, + ) + } + } + @Composable fun ContentAndTimestampView( timestampPosition: TimestampPosition, @@ -450,47 +459,74 @@ private fun MessageEventBubbleContent( /** Groups the different components in a Column with some space between them. */ @Composable fun CommonLayout( + timestampPosition: TimestampPosition, + showThreadDecoration: Boolean, inReplyToDetails: InReplyTo.Ready?, modifier: Modifier = Modifier ) { - var modifierWithPadding: Modifier = Modifier - var contentModifier: Modifier = Modifier - EqualWidthColumn(modifier = modifier, spacing = 8.dp) { - when { - inReplyToDetails != null -> { - val senderName = inReplyToDetails.senderDisplayName ?: inReplyToDetails.senderId.value - val attachmentThumbnailInfo = attachmentThumbnailInfoForInReplyTo(inReplyToDetails) - val text = textForInReplyTo(inReplyToDetails) - ReplyToContent( - senderName = senderName, - text = text, - attachmentThumbnailInfo = attachmentThumbnailInfo, - modifier = Modifier - .padding(top = 8.dp, start = 8.dp, end = 8.dp) - .clip(RoundedCornerShape(6.dp)) - .clickable(enabled = true, onClick = inReplyToClick), - ) - if (timestampPosition == TimestampPosition.Overlay) { - modifierWithPadding = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp) - contentModifier = Modifier.clip(RoundedCornerShape(12.dp)) - } else { - contentModifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 0.dp, bottom = 8.dp) - } - } - timestampPosition != TimestampPosition.Overlay -> { - contentModifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 8.dp, bottom = 8.dp) + val modifierWithPadding: Modifier + val contentModifier: Modifier + when { + inReplyToDetails != null -> { + if (timestampPosition == TimestampPosition.Overlay) { + modifierWithPadding = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp) + contentModifier = Modifier.clip(RoundedCornerShape(12.dp)) + } else { + contentModifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 0.dp, bottom = 8.dp) + modifierWithPadding = Modifier } } + timestampPosition != TimestampPosition.Overlay -> { + modifierWithPadding = Modifier + contentModifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 8.dp, bottom = 8.dp) + } + else -> { + modifierWithPadding = Modifier + contentModifier = Modifier + } + } + EqualWidthColumn(modifier = modifier, spacing = 8.dp) { + if (showThreadDecoration) { + ThreadDecoration(modifier = Modifier.padding(top = 8.dp, start = 12.dp, end = 12.dp)) + } + if (inReplyToDetails != null) { + val senderName = inReplyToDetails.senderDisplayName ?: inReplyToDetails.senderId.value + val attachmentThumbnailInfo = attachmentThumbnailInfoForInReplyTo(inReplyToDetails) + val text = textForInReplyTo(inReplyToDetails) + val topPadding = if (showThreadDecoration) 0.dp else 8.dp + ReplyToContent( + senderName = senderName, + text = text, + attachmentThumbnailInfo = attachmentThumbnailInfo, + modifier = Modifier + .padding(top = topPadding, start = 8.dp, end = 8.dp) + .clip(RoundedCornerShape(6.dp)) + .clickable(enabled = true, onClick = inReplyToClick), + ) + } ContentAndTimestampView( timestampPosition = timestampPosition, - contentModifier = contentModifier, modifier = modifierWithPadding, + contentModifier = contentModifier, ) } } - CommonLayout(inReplyToDetails = replyToDetails, modifier = bubbleModifier) + val timestampPosition = when (event.content) { + is TimelineItemImageContent, + is TimelineItemVideoContent, + is TimelineItemLocationContent -> TimestampPosition.Overlay + is TimelineItemPollContent -> TimestampPosition.Below + else -> TimestampPosition.Default + } + val replyToDetails = event.inReplyTo as? InReplyTo.Ready + CommonLayout( + showThreadDecoration = false, + timestampPosition = timestampPosition, + inReplyToDetails = replyToDetails, + modifier = bubbleModifier + ) } @Composable diff --git a/libraries/designsystem/src/main/res/drawable/ic_thread_decoration.xml b/libraries/designsystem/src/main/res/drawable/ic_thread_decoration.xml new file mode 100644 index 0000000000..09d4ad4ace --- /dev/null +++ b/libraries/designsystem/src/main/res/drawable/ic_thread_decoration.xml @@ -0,0 +1,15 @@ + + + + + From b6be98988406c8f7230c98708e65d114ebf1d9bb Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 12:05:50 +0200 Subject: [PATCH 02/10] Thread decoration: add and branch isThreaded method --- .../messages/impl/timeline/TimelineStateProvider.kt | 2 ++ .../impl/timeline/components/TimelineItemEventRow.kt | 11 ++++++----- .../factories/event/TimelineItemEventFactory.kt | 2 ++ .../messages/impl/timeline/model/TimelineItem.kt | 1 + .../features/messages/fixtures/aMessageEvent.kt | 2 ++ .../timeline/groups/TimelineItemGrouperTest.kt | 1 + .../matrix/api/timeline/item/event/EventContent.kt | 1 + .../api/timeline/item/event/EventTimelineItem.kt | 5 +++++ .../impl/timeline/item/event/EventMessageMapper.kt | 1 + .../libraries/matrix/test/room/RoomSummaryFixture.kt | 2 ++ 10 files changed, 23 insertions(+), 5 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index 8a4d45e40c..1374f4aef4 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -111,6 +111,7 @@ internal fun aTimelineItemEvent( groupPosition: TimelineItemGroupPosition = TimelineItemGroupPosition.None, sendState: LocalEventSendState = LocalEventSendState.Sent(eventId), inReplyTo: InReplyTo? = null, + isThreaded: Boolean = false, debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), timelineItemReactions: TimelineItemReactions = aTimelineItemReactions(), ): TimelineItem.Event { @@ -129,6 +130,7 @@ internal fun aTimelineItemEvent( localSendState = sendState, inReplyTo = inReplyTo, debugInfo = debugInfo, + isThreaded = isThreaded, origin = null ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 122fa03b25..befb576696 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -522,7 +522,7 @@ private fun MessageEventBubbleContent( } val replyToDetails = event.inReplyTo as? InReplyTo.Ready CommonLayout( - showThreadDecoration = false, + showThreadDecoration = event.isThreaded, timestampPosition = timestampPosition, inReplyToDetails = replyToDetails, modifier = bubbleModifier @@ -707,7 +707,7 @@ private fun ContentToPreviewWithReply() { body = "A long text which will be displayed on several lines and" + " hopefully can be manually adjusted to test different behaviors." ), - inReplyTo = aInReplyToReady(replyContent), + inReplyTo = aInReplyToReady(replyContent, true), groupPosition = TimelineItemGroupPosition.First, ), isHighlighted = false, @@ -729,7 +729,7 @@ private fun ContentToPreviewWithReply() { content = aTimelineItemImageContent().copy( aspectRatio = 5f ), - inReplyTo = aInReplyToReady(replyContent), + inReplyTo = aInReplyToReady(replyContent, false), groupPosition = TimelineItemGroupPosition.Last, ), isHighlighted = false, @@ -750,11 +750,12 @@ private fun ContentToPreviewWithReply() { } private fun aInReplyToReady( - replyContent: String + replyContent: String, + isThreaded: Boolean, ): InReplyTo.Ready { return InReplyTo.Ready( eventId = EventId("\$event"), - content = MessageContent(replyContent, null, false, TextMessageType(replyContent, null)), + content = MessageContent(replyContent, null, false, isThreaded, TextMessageType(replyContent, null)), senderId = UserId("@Sender:domain"), senderDisplayName = "Sender", senderAvatarUrl = null, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt index 4cb249af72..14f8429c85 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemEventFactory.kt @@ -71,6 +71,7 @@ class TimelineItemEventFactory @Inject constructor( url = senderAvatarUrl, size = AvatarSize.TimelineSender ) + currentTimelineItem.event return TimelineItem.Event( id = currentTimelineItem.uniqueId.toString(), eventId = currentTimelineItem.eventId, @@ -85,6 +86,7 @@ class TimelineItemEventFactory @Inject constructor( reactionsState = currentTimelineItem.computeReactionsState(), localSendState = currentTimelineItem.event.localSendState, inReplyTo = currentTimelineItem.event.inReplyTo(), + isThreaded = currentTimelineItem.event.isThreaded(), debugInfo = currentTimelineItem.event.debugInfo, origin = currentTimelineItem.event.origin, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index b1a5c245b9..8f00dfb0dd 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -66,6 +66,7 @@ sealed interface TimelineItem { val reactionsState: TimelineItemReactions, val localSendState: LocalEventSendState?, val inReplyTo: InReplyTo?, + val isThreaded: Boolean, val debugInfo: TimelineItemDebugInfo, val origin: TimelineItemEventOrigin?, ) : TimelineItem { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/fixtures/aMessageEvent.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/fixtures/aMessageEvent.kt index 4f1edcb64f..6d944075d1 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/fixtures/aMessageEvent.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/fixtures/aMessageEvent.kt @@ -37,6 +37,7 @@ internal fun aMessageEvent( isMine: Boolean = true, content: TimelineItemEventContent = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false), inReplyTo: InReplyTo? = null, + isThreaded: Boolean = false, debugInfo: TimelineItemDebugInfo = aTimelineItemDebugInfo(), sendState: LocalEventSendState = LocalEventSendState.Sent(AN_EVENT_ID), ) = TimelineItem.Event( @@ -52,5 +53,6 @@ internal fun aMessageEvent( localSendState = sendState, inReplyTo = inReplyTo, debugInfo = debugInfo, + isThreaded = isThreaded, origin = null ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/groups/TimelineItemGrouperTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/groups/TimelineItemGrouperTest.kt index d5ce31f87a..4c43a8552f 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/groups/TimelineItemGrouperTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/timeline/groups/TimelineItemGrouperTest.kt @@ -44,6 +44,7 @@ class TimelineItemGrouperTest { reactionsState = aTimelineItemReactions(count = 0), localSendState = LocalEventSendState.Sent(AN_EVENT_ID), inReplyTo = null, + isThreaded = false, debugInfo = aTimelineItemDebugInfo(), origin = null ) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt index b16e8d2694..a3edf80bee 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt @@ -32,6 +32,7 @@ data class MessageContent( val body: String, val inReplyTo: InReplyTo?, val isEdited: Boolean, + val isThreaded: Boolean, val type: MessageType? ) : EventContent diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt index 50bf5f8ce5..49108f8d54 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt @@ -40,6 +40,11 @@ data class EventTimelineItem( fun inReplyTo(): InReplyTo? { return (content as? MessageContent)?.inReplyTo } + + fun isThreaded(): Boolean { + return (content as? MessageContent)?.isThreaded ?: false + } + fun hasNotLoadedInReplyTo(): Boolean { val details = inReplyTo() return details is InReplyTo.NotLoaded diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt index 330a06da62..d7df699a57 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventMessageMapper.kt @@ -68,6 +68,7 @@ class EventMessageMapper { body = it.body(), inReplyTo = inReplyToEvent, isEdited = it.isEdited(), + isThreaded = it.isThreaded(), type = type ) } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index 59bac7ad40..12b0325da5 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -147,6 +147,7 @@ fun aMessageContent( body: String = "body", inReplyTo: InReplyTo? = null, isEdited: Boolean = false, + isThreaded: Boolean = false, messageType: MessageType = TextMessageType( body = body, formatted = null @@ -155,6 +156,7 @@ fun aMessageContent( body = body, inReplyTo = inReplyTo, isEdited = isEdited, + isThreaded = isThreaded, type = messageType ) From ef69a85e365cad4317e735495aeb72dc4b922a73 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 12:11:09 +0200 Subject: [PATCH 03/10] Thread decoration : add changelog --- changelog.d/1236.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1236.feature diff --git a/changelog.d/1236.feature b/changelog.d/1236.feature new file mode 100644 index 0000000000..8ad652361a --- /dev/null +++ b/changelog.d/1236.feature @@ -0,0 +1 @@ +Display a thread decorator in timeline so we know when a message is coming from a thread. From 7021fc0fe5a0c1458ff9f6e07c20107b0ce2d178 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 14:13:51 +0200 Subject: [PATCH 04/10] Thread decoration : fix test compilation --- .../eventformatter/impl/DefaultRoomLastMessageFormatterTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTests.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTests.kt index 494c63784d..0f22105635 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTests.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLastMessageFormatterTests.kt @@ -153,7 +153,7 @@ class DefaultRoomLastMessageFormatterTests { fun `Message contents`() { val body = "Shared body" fun createMessageContent(type: MessageType): MessageContent { - return MessageContent(body, null, false, type) + return MessageContent(body, null, false, false,type) } val sharedContentMessagesTypes = arrayOf( From c0e518e0505d203c57ff2e66d16a2655eca21cf4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 16:00:44 +0200 Subject: [PATCH 05/10] Thread decoration: add "Reply in thread" context --- .../features/messages/impl/MessagesPresenter.kt | 4 +++- .../impl/actionlist/ActionListPresenter.kt | 6 +++++- .../impl/actionlist/model/TimelineItemAction.kt | 1 + .../timeline/components/TimelineItemEventRow.kt | 2 +- .../MessageComposerPresenterTest.kt | 2 +- .../impl/src/main/res/values/localazy.xml | 2 ++ .../textcomposer/MessageComposerMode.kt | 3 ++- .../libraries/textcomposer/TextComposer.kt | 14 ++++++++++++-- .../ui-strings/src/main/res/values/localazy.xml | 17 +++++++++++------ 9 files changed, 38 insertions(+), 13 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt index 50b3dca2d1..8c985d45d9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesPresenter.kt @@ -209,7 +209,8 @@ class MessagesPresenter @AssistedInject constructor( TimelineItemAction.Copy -> handleCopyContents(targetEvent) TimelineItemAction.Redact -> handleActionRedact(targetEvent) TimelineItemAction.Edit -> handleActionEdit(targetEvent, composerState) - TimelineItemAction.Reply -> handleActionReply(targetEvent, composerState) + TimelineItemAction.Reply, + TimelineItemAction.ReplyInThread -> handleActionReply(targetEvent, composerState) TimelineItemAction.Developer -> handleShowDebugInfoAction(targetEvent) TimelineItemAction.Forward -> handleForwardAction(targetEvent) TimelineItemAction.ReportContent -> handleReportAction(targetEvent) @@ -312,6 +313,7 @@ class MessagesPresenter @AssistedInject constructor( is TimelineItemUnknownContent -> null } val composerMode = MessageComposerMode.Reply( + isThreaded = targetEvent.isThreaded, senderName = targetEvent.safeSenderName, eventId = targetEvent.eventId, attachmentThumbnailInfo = attachmentThumbnailInfo, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt index b179261c72..e87523d702 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenter.kt @@ -130,7 +130,11 @@ class ActionListPresenter @Inject constructor( if (timelineItem.isRemote) { // Can only reply or forward messages already uploaded to the server if (userCanSendMessage) { - add(TimelineItemAction.Reply) + if (timelineItem.isThreaded) { + add(TimelineItemAction.ReplyInThread) + } else { + add(TimelineItemAction.Reply) + } } add(TimelineItemAction.Forward) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt index 7a8a1fa1db..331edfa1a5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/model/TimelineItemAction.kt @@ -32,6 +32,7 @@ sealed class TimelineItemAction( data object Copy : TimelineItemAction(CommonStrings.action_copy, VectorIcons.Copy) data object Redact : TimelineItemAction(CommonStrings.action_remove, VectorIcons.Delete, destructive = true) data object Reply : TimelineItemAction(CommonStrings.action_reply, VectorIcons.Reply) + data object ReplyInThread : TimelineItemAction(CommonStrings.action_reply_in_thread, VectorIcons.Reply) data object Edit : TimelineItemAction(CommonStrings.action_edit, VectorIcons.Edit) data object Developer : TimelineItemAction(CommonStrings.action_view_source, VectorIcons.DeveloperMode) data object ReportContent : TimelineItemAction(CommonStrings.action_report_content, VectorIcons.ReportContent, destructive = true) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index befb576696..0158372c79 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -400,7 +400,7 @@ private fun MessageEventBubbleContent( Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) Spacer(modifier = Modifier.width(4.dp)) Text( - text = "Thread", + text = stringResource(CommonStrings.common_thread), style = ElementTheme.typography.fontBodyXsRegular, color = ElementTheme.colors.textPrimary, ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt index d1d4a54073..07a4800ffb 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt @@ -598,7 +598,7 @@ fun anEditMode( transactionId: TransactionId? = null, ) = MessageComposerMode.Edit(eventId, message, transactionId) -fun aReplyMode() = MessageComposerMode.Reply(A_USER_NAME, null, AN_EVENT_ID, A_MESSAGE) +fun aReplyMode() = MessageComposerMode.Reply(A_USER_NAME, null, false, AN_EVENT_ID, A_MESSAGE) fun aQuoteMode() = MessageComposerMode.Quote(AN_EVENT_ID, A_MESSAGE) private fun String.toMessage() = Message( diff --git a/features/roomdetails/impl/src/main/res/values/localazy.xml b/features/roomdetails/impl/src/main/res/values/localazy.xml index 717f503e22..7f0f4ddc30 100644 --- a/features/roomdetails/impl/src/main/res/values/localazy.xml +++ b/features/roomdetails/impl/src/main/res/values/localazy.xml @@ -30,11 +30,13 @@ "You can change it in your %1$s." "global settings" "Default setting" + "Remove custom setting" "An error occurred while loading notification settings." "Failed restoring the default mode, please try again." "Failed setting the mode, please try again." "All messages" "Mentions and Keywords only" + "In this room, notify me for" "Block" "Blocked users won\'t be able to send you messages and all their messages will be hidden. You can unblock them anytime." "Block user" diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt index aa3e745ea2..3dbc652aaf 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/MessageComposerMode.kt @@ -41,6 +41,7 @@ sealed interface MessageComposerMode : Parcelable { class Reply( val senderName: String, val attachmentThumbnailInfo: AttachmentThumbnailInfo?, + val isThreaded: Boolean, override val eventId: EventId, override val defaultContent: String ) : Special(eventId, defaultContent) @@ -60,5 +61,5 @@ sealed interface MessageComposerMode : Parcelable { get() = this is Reply val inThread: Boolean - get() = false // TODO + get() = this is Reply && isThreaded } diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index 3cc09ce09f..c407e678dd 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -183,9 +183,13 @@ fun TextComposer( if (composerMode is MessageComposerMode.Special) { ComposerModeView(composerMode = composerMode, onResetComposerMode = onResetComposerMode) } - TextInput( state = state, + placeholder = if (composerMode.inThread) { + stringResource(id = CommonStrings.action_reply_in_thread) + } else { + stringResource(id = CommonStrings.rich_text_editor_composer_placeholder) + }, roundedCorners = roundedCorners, bgColor = bgColor, onError = onError, @@ -237,6 +241,7 @@ fun TextComposer( @Composable private fun TextInput( state: RichTextEditorState, + placeholder: String, roundedCorners: RoundedCornerShape, bgColor: Color, modifier: Modifier = Modifier, @@ -262,7 +267,7 @@ private fun TextInput( // Placeholder if (state.messageHtml.isEmpty()) { Text( - stringResource(CommonStrings.common_message), + placeholder, style = defaultTypography.copy( color = ElementTheme.colors.textDisabled, ), @@ -686,6 +691,7 @@ internal fun TextComposerReplyPreview() = ElementPreview { canSendMessage = false, onSendMessage = {}, composerMode = MessageComposerMode.Reply( + isThreaded = false, senderName = "Alice", eventId = EventId("$1234"), attachmentThumbnailInfo = null, @@ -701,6 +707,7 @@ internal fun TextComposerReplyPreview() = ElementPreview { canSendMessage = true, onSendMessage = {}, composerMode = MessageComposerMode.Reply( + isThreaded = true, senderName = "Alice", eventId = EventId("$1234"), attachmentThumbnailInfo = AttachmentThumbnailInfo( @@ -719,6 +726,7 @@ internal fun TextComposerReplyPreview() = ElementPreview { canSendMessage = true, onSendMessage = {}, composerMode = MessageComposerMode.Reply( + isThreaded = false, senderName = "Alice", eventId = EventId("$1234"), attachmentThumbnailInfo = AttachmentThumbnailInfo( @@ -737,6 +745,7 @@ internal fun TextComposerReplyPreview() = ElementPreview { canSendMessage = true, onSendMessage = {}, composerMode = MessageComposerMode.Reply( + isThreaded = false, senderName = "Alice", eventId = EventId("$1234"), attachmentThumbnailInfo = AttachmentThumbnailInfo( @@ -755,6 +764,7 @@ internal fun TextComposerReplyPreview() = ElementPreview { canSendMessage = true, onSendMessage = {}, composerMode = MessageComposerMode.Reply( + isThreaded = false, senderName = "Alice", eventId = EventId("$1234"), attachmentThumbnailInfo = AttachmentThumbnailInfo( diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index d6f9f2cbaf..3098b9b5b3 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -1,6 +1,5 @@ - "Use an identity server to invite by email. ""Use the default (%(defaultIdentityServerName)s)"" or manage in ""Settings""." "Hide password" "Mentions only" "Muted" @@ -37,6 +36,8 @@ "Learn more" "Leave" "Leave room" + "Manage account" + "Manage devices" "Next" "No" "Not now" @@ -47,6 +48,7 @@ "React" "Remove" "Reply" + "Reply in thread" "Report bug" "Report Content" "Retry" @@ -65,8 +67,12 @@ "Take photo" "View Source" "Yes" + "Ongoing call" + "Tap to return to the call" + "☎️ Call in progress" "About" "Acceptable use policy" + "Advanced settings" "Analytics" "Audio" "Bubbles" @@ -85,6 +91,7 @@ "Forward message" "GIF" "Image" + "In reply to %1$s" "This Matrix ID can\'t be found, so the invite might not be received." "Leaving room" "Link copied to clipboard" @@ -99,15 +106,16 @@ "Password" "People" "Permalink" - "Final votes: %1$s" "Total votes: %1$s" "Results will show after the poll has ended" "Privacy policy" + "Reaction" "Reactions" "Refreshing…" "Replying to %1$s" "Report a bug" "Report submitted" + "Rich text editor" "Room name" "e.g. your project name" "Search for someone" @@ -126,6 +134,7 @@ "Syncing" "Text" "Third-party notices" + "Thread" "Topic" "What is this room about?" "Unable to decrypt" @@ -162,10 +171,6 @@ "Are you sure that you want to leave this room? This room is not public and you won\'t be able to rejoin without an invite." "Are you sure that you want to leave the room?" "%1$s Android" - - "%(count)s room" - "%(count)s rooms" - "%1$d member" "%1$d members" From e7869e7c143becf6eacfb9f18289bc52f5ff9ff9 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 13 Sep 2023 14:14:25 +0000 Subject: [PATCH 06/10] Update screenshots --- ..._null_MessageComposerViewDark_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...null_MessageComposerViewLight_0_null_0,NEXUS_5,1.0,en].png | 4 ++-- ...es.impl_null_MessagesViewDark_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...s.impl_null_MessagesViewLight_0_null_2,NEXUS_5,1.0,en].png | 4 ++-- ...null_TextComposerFormatting-D-1_2_null,NEXUS_5,1.0,en].png | 4 ++-- ...null_TextComposerFormatting-N-1_3_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png | 4 ++-- ...ser_null_TextComposerSimple-D-0_1_null,NEXUS_5,1.0,en].png | 4 ++-- ...ser_null_TextComposerSimple-N-0_2_null,NEXUS_5,1.0,en].png | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewDark_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewDark_0_null_0,NEXUS_5,1.0,en].png index ee0937d439..67b7525ddc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewDark_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewDark_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3ea303577f655368800debe9c40e1292dc08a20da7f2ea6ddddb87f8407b112 -size 10431 +oid sha256:6bf428927e9a3493284d9fa7ba307b51315ed52b317a60ac345e87ba70849d0f +size 10523 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewLight_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewLight_0_null_0,NEXUS_5,1.0,en].png index e537e910e3..8007500f81 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewLight_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.messagecomposer_null_MessageComposerViewLight_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b646c06e55b50b64eb7b566fbc0bcafa7f7e348398f87152d008a47e7448f4e0 -size 10736 +oid sha256:6eced1d7173c2d0100351f5bb9cd14c649a826b2e355e426b9c6d4add90015d9 +size 10833 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewDark_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewDark_0_null_2,NEXUS_5,1.0,en].png index eb75a98270..8d7e2dcf95 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewDark_0_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewDark_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd991a67e7d6c1169e08e62cb74ed6fa7d12ad7f91d69bbfa778e0053efebfec -size 52284 +oid sha256:c329165fa341a2130b43a448b8bba465f1e5f458136efa6da80f2cdeee9d6caa +size 52369 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewLight_0_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewLight_0_null_2,NEXUS_5,1.0,en].png index 9603a65588..ec09599aca 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewLight_0_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl_null_MessagesViewLight_0_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d421656ae8ad316e65f406c74dffa2ceb4e47b868b7f033f9cc4139e3e6be788 -size 53909 +oid sha256:2b4e5e9d920ea2a7733453e030bb365c9e2af7263de8fe216ab56088e0861fa5 +size 53997 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-D-1_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-D-1_2_null,NEXUS_5,1.0,en].png index 760cf75800..f9dc3f8b9a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-D-1_2_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-D-1_2_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0e4c8da669ee5383a7d0f828a3300b923ec38ab5e04bc388da0e83f1cf1ccf3 -size 38291 +oid sha256:1f065f63fb37fa9a5441cfaeca04e867e4e8f6f744dd02a83c459fc128ee353d +size 38384 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-N-1_3_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-N-1_3_null,NEXUS_5,1.0,en].png index 0b9f9f3ab7..ca3a85e52c 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-N-1_3_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerFormatting-N-1_3_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f26aa7b13403cfaa864778a6ec5c26edde5932f3d887c7148d3a2b9f60f6e6a -size 36392 +oid sha256:a5ded1cbc536c544b0cb188ba0a333a541157eaf1772cd0e06c7338307549adc +size 36483 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png index 37e8a8561f..3c7754c726 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e65e15c721a939ed700719cacbdee57e1ccb89d984e88bdb5ed772c4b583472a -size 81494 +oid sha256:dd9b6fc48c755f51edaff00131b864a0c95bedc5d29133e010b885054cf7c954 +size 81601 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png index 466f321959..77acf98598 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49f6d3b7f93008640abf30a5a65ddca6845e16343ef97c3450faf9dd6d9b9cec -size 78788 +oid sha256:b6b4ad7b6549da6c449827498b14057df0ea3990ecf1d05fa82b1247d218834e +size 78890 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-D-0_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-D-0_1_null,NEXUS_5,1.0,en].png index d6beb7c22c..06fbfc6c7f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-D-0_1_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-D-0_1_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a998d3db9e4454fe74f31028b1dc61e4d6c07c824192f5e75563234dedf0b26 -size 44108 +oid sha256:267f482ceddeadea4c3b580d6783fed1048015fa05a11e385dd547e60f72e1e8 +size 44206 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-N-0_2_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-N-0_2_null,NEXUS_5,1.0,en].png index 863e8b8628..a237bcce80 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-N-0_2_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerSimple-N-0_2_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97ab0a0b64ea7704a1557fc34b24d7caea34f9951948f5f5637f0bda596288dd -size 41455 +oid sha256:9f5e7ab52469b406509964d71f12475df546973f1382944ce7f2e1a437e4f880 +size 41536 From 62cabff39af341669e8b39461ada0c02630533c2 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 13 Sep 2023 16:36:35 +0200 Subject: [PATCH 07/10] Thread decoration: update preview with new changes --- .../timeline/components/TimelineItemEventRow.kt | 8 ++++---- .../libraries/textcomposer/TextComposer.kt | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 0158372c79..95a28131d3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -707,7 +707,7 @@ private fun ContentToPreviewWithReply() { body = "A long text which will be displayed on several lines and" + " hopefully can be manually adjusted to test different behaviors." ), - inReplyTo = aInReplyToReady(replyContent, true), + inReplyTo = aInReplyToReady(replyContent), groupPosition = TimelineItemGroupPosition.First, ), isHighlighted = false, @@ -729,7 +729,8 @@ private fun ContentToPreviewWithReply() { content = aTimelineItemImageContent().copy( aspectRatio = 5f ), - inReplyTo = aInReplyToReady(replyContent, false), + inReplyTo = aInReplyToReady(replyContent), + isThreaded = true, groupPosition = TimelineItemGroupPosition.Last, ), isHighlighted = false, @@ -751,11 +752,10 @@ private fun ContentToPreviewWithReply() { private fun aInReplyToReady( replyContent: String, - isThreaded: Boolean, ): InReplyTo.Ready { return InReplyTo.Ready( eventId = EventId("\$event"), - content = MessageContent(replyContent, null, false, isThreaded, TextMessageType(replyContent, null)), + content = MessageContent(replyContent, null, false, false, TextMessageType(replyContent, null)), senderId = UserId("@Sender:domain"), senderDisplayName = "Sender", senderAvatarUrl = null, diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt index c407e678dd..de43424aae 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt @@ -702,6 +702,22 @@ internal fun TextComposerReplyPreview() = ElementPreview { onResetComposerMode = {}, enableTextFormatting = true, ) + TextComposer( + RichTextEditorState("", fake = true), + canSendMessage = false, + onSendMessage = {}, + composerMode = MessageComposerMode.Reply( + isThreaded = true, + senderName = "Alice", + eventId = EventId("$1234"), + attachmentThumbnailInfo = null, + defaultContent = "A message\n" + + "With several lines\n" + + "To preview larger textfields and long lines with overflow" + ), + onResetComposerMode = {}, + enableTextFormatting = true, + ) TextComposer( RichTextEditorState("A message", fake = true), canSendMessage = true, From 0dc0a05f82a2c2ebb82ac52678b53989777bce02 Mon Sep 17 00:00:00 2001 From: ElementBot Date: Wed, 13 Sep 2023 14:55:57 +0000 Subject: [PATCH 08/10] Update screenshots --- ...melineItemEventRowWithReplyDark_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...elineItemEventRowWithReplyLight_0_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png | 4 ++-- ...oser_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyDark_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyDark_0_null,NEXUS_5,1.0,en].png index c39b41db87..a41e57eecc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyDark_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyDark_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b991a34a137d82ff4dedf48316a05ebbc008233984b11af70e64889a5fb5eda8 -size 127438 +oid sha256:2bf08003a076d8a206782888cc2fc3df297e53478cd4c0e0aa5c8a26069bb7fa +size 128065 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyLight_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyLight_0_null,NEXUS_5,1.0,en].png index a6500ca748..9c01abd666 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyLight_0_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components_null_TimelineItemEventRowWithReplyLight_0_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43b6514716d18382c8962520928d9d2ff6d0f665b2471e8a24e5d2e44a25c88c -size 132295 +oid sha256:8f5f950fce40c10710eb7fe4b193b4623633acdedfcf9029d6e0920e0c8d43d6 +size 133043 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png index 3c7754c726..0d9c311dcc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-D-3_4_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dd9b6fc48c755f51edaff00131b864a0c95bedc5d29133e010b885054cf7c954 -size 81601 +oid sha256:69e98a3521ae6545700e395bff211b06bb02095b01d9c254b3e0d2d0b8b88d26 +size 80484 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png index 77acf98598..ef035d6cd5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.textcomposer_null_TextComposerReply-N-3_5_null,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6b4ad7b6549da6c449827498b14057df0ea3990ecf1d05fa82b1247d218834e -size 78890 +oid sha256:27dee9eaae6736a128107c9fd93048a677287a40d24c334223243b3c55f1cf69 +size 77686 From d70295d6c68618f62c4317bdb9bd4ed63dee7101 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 14 Sep 2023 12:35:20 +0200 Subject: [PATCH 09/10] Thread decoration : pr review --- .../impl/timeline/components/TimelineItemEventRow.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 95a28131d3..51711db0ae 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -24,6 +24,7 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.draggable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -396,9 +397,12 @@ private fun MessageEventBubbleContent( fun ThreadDecoration( modifier: Modifier = Modifier ) { - Row(modifier, verticalAlignment = Alignment.CenterVertically) { + Row( + modifier = modifier, + horizontalArrangement = spacedBy(4.dp, Alignment.Start), + verticalAlignment = Alignment.CenterVertically, + ) { Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) - Spacer(modifier = Modifier.width(4.dp)) Text( text = stringResource(CommonStrings.common_thread), style = ElementTheme.typography.fontBodyXsRegular, From e69e961a70b79ff740ed61dcd1b9f3029892d54c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Sep 2023 18:16:10 +0200 Subject: [PATCH 10/10] Avoid lint false positive. --- .../messages/impl/timeline/components/TimelineItemEventRow.kt | 4 ++-- .../io/element/android/libraries/designsystem/VectorIcons.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt index 51711db0ae..f492407690 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt @@ -76,7 +76,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent -import io.element.android.libraries.designsystem.R +import io.element.android.libraries.designsystem.VectorIcons import io.element.android.libraries.designsystem.colors.AvatarColorsProvider import io.element.android.libraries.designsystem.components.EqualWidthColumn import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -402,7 +402,7 @@ private fun MessageEventBubbleContent( horizontalArrangement = spacedBy(4.dp, Alignment.Start), verticalAlignment = Alignment.CenterVertically, ) { - Icon(resourceId = R.drawable.ic_thread_decoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) + Icon(resourceId = VectorIcons.ThreadDecoration, contentDescription = null, tint = ElementTheme.colors.iconSecondary) Text( text = stringResource(CommonStrings.common_thread), style = ElementTheme.typography.fontBodyXsRegular, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/VectorIcons.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/VectorIcons.kt index 20ebb85615..0194e86518 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/VectorIcons.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/VectorIcons.kt @@ -41,4 +41,5 @@ object VectorIcons { val Quote = R.drawable.ic_quote val Strikethrough = R.drawable.ic_strikethrough val Underline = R.drawable.ic_underline + val ThreadDecoration = R.drawable.ic_thread_decoration }