From aacb24bcf814be6f04bf61d1ccc7c6984504f98d Mon Sep 17 00:00:00 2001 From: Nicolas Mauri Date: Mon, 27 Nov 2023 16:24:51 +0100 Subject: [PATCH] Fix a rendering issue when a message starts with a list (#1915) (#2152) --- .../View/Timeline/FormattedBodyText.swift | 10 ++- .../View/Timeline/TextRoomTimelineView.swift | 82 ++++++++++++++----- .../test_textRoomTimelineView.1.png | 3 - .../test_textRoomTimelineView.2.png | 3 - .../test_textRoomTimelineView.Bubble-RTL.png | 3 + .../test_textRoomTimelineView.Bubble.png | 3 + .../test_textRoomTimelineView.Plain-RTL.png | 3 + .../test_textRoomTimelineView.Plain.png | 3 + changelog.d/1915.bugfix | 1 + 9 files changed, 83 insertions(+), 28 deletions(-) delete mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.1.png delete mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.2.png create mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble-RTL.png create mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble.png create mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain-RTL.png create mode 100644 UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain.png create mode 100644 changelog.d/1915.bugfix diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift index ed8dc50a1..a1a48c99e 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift @@ -33,7 +33,12 @@ struct FormattedBodyText: View { }() private var attributedComponents: [AttributedStringBuilderComponent] { - var adjustedAttributedString = AttributedString(layoutDirection.isolateLayoutUnicodeString) + attributedString + AttributedString(additionalWhitespacesSuffix) + var adjustedAttributedString = attributedString + AttributedString(additionalWhitespacesSuffix) + + // If this is not a list, force the writing direction by adding the correct unicode character. + if !String(attributedString.characters).starts(with: "\t") { + adjustedAttributedString = AttributedString(layoutDirection.isolateLayoutUnicodeString) + adjustedAttributedString + } // Required to allow the underlying TextView to use body font when no font is specifie in the AttributedString. adjustedAttributedString.mergeAttributes(defaultAttributesContainer, mergePolicy: .keepCurrent) @@ -198,7 +203,8 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview {

Text

Hello world """, - "

This is a list

\n\n" + "

This is a list

\n\n", + "" ] let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder()) diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/TextRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/TextRoomTimelineView.swift index 0007664c8..0d0331728 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/TextRoomTimelineView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/TextRoomTimelineView.swift @@ -41,32 +41,60 @@ struct TextRoomTimelineView_Previews: PreviewProvider, TestablePreview { static var previews: some View { body.environmentObject(viewModel.context) + .previewDisplayName("Bubble") body .environment(\.timelineStyle, .plain) .environmentObject(viewModel.context) + .previewDisplayName("Plain") + body + .environmentObject(viewModel.context) + .environment(\.layoutDirection, .rightToLeft) + .previewDisplayName("Bubble RTL") + body + .environment(\.timelineStyle, .plain) + .environmentObject(viewModel.context) + .environment(\.layoutDirection, .rightToLeft) + .previewDisplayName("Plain RTL") } static var body: some View { - VStack(alignment: .leading, spacing: 20.0) { - TextRoomTimelineView(timelineItem: itemWith(text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", - timestamp: "Now", - isOutgoing: false, - senderId: "Bob")) - - TextRoomTimelineView(timelineItem: itemWith(text: "Some other text", - timestamp: "Later", - isOutgoing: true, - senderId: "Anne")) - - TextRoomTimelineView(timelineItem: itemWith(text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", - timestamp: "Now", - isOutgoing: false, - senderId: "Bob")) - - TextRoomTimelineView(timelineItem: itemWith(text: "Some other text", - timestamp: "Later", - isOutgoing: true, - senderId: "Anne")) + ScrollView { + VStack(alignment: .leading, spacing: 20.0) { + TextRoomTimelineView(timelineItem: itemWith(text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", + timestamp: "Now", + isOutgoing: false, + senderId: "Bob")) + + TextRoomTimelineView(timelineItem: itemWith(text: "Some other text", + timestamp: "Later", + isOutgoing: true, + senderId: "Anne")) + + TextRoomTimelineView(timelineItem: itemWith(text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.", + timestamp: "Now", + isOutgoing: false, + senderId: "Bob")) + + TextRoomTimelineView(timelineItem: itemWith(text: "Some other text", + timestamp: "Later", + isOutgoing: true, + senderId: "Anne")) + + TextRoomTimelineView(timelineItem: itemWith(text: "טקסט אחר", + timestamp: "Later", + isOutgoing: true, + senderId: "Anne")) + + TextRoomTimelineView(timelineItem: itemWith(html: "
  1. First item
  2. Second item
  3. Third item
", + timestamp: "Later", + isOutgoing: true, + senderId: "Anne")) + + TextRoomTimelineView(timelineItem: itemWith(html: "
  1. פריט ראשון
  2. הפריט השני
  3. פריט שלישי
", + timestamp: "Later", + isOutgoing: true, + senderId: "Anne")) + } } } @@ -80,4 +108,18 @@ struct TextRoomTimelineView_Previews: PreviewProvider, TestablePreview { sender: .init(id: senderId), content: .init(body: text)) } + + private static func itemWith(html: String, timestamp: String, isOutgoing: Bool, senderId: String) -> TextRoomTimelineItem { + let builder = AttributedStringBuilder(cacheKey: "preview", permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder()) + let attributedString = builder.fromHTML(html) + + return TextRoomTimelineItem(id: .random, + timestamp: timestamp, + isOutgoing: isOutgoing, + isEditable: isOutgoing, + canBeRepliedTo: true, + isThreaded: false, + sender: .init(id: senderId), + content: .init(body: "", formattedBody: attributedString)) + } } diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.1.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.1.png deleted file mode 100644 index a41b127f7..000000000 --- a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:28393ef0e427739046c74311af565ecfc3d1e74696ccaec67a99135f590d58d3 -size 179423 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.2.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.2.png deleted file mode 100644 index 8851b65eb..000000000 --- a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:16f110dd908398601d5fd7548c44c3b9cb526b8ff88b0a790484398be2dbc7a9 -size 167600 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble-RTL.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble-RTL.png new file mode 100644 index 000000000..4fa62a4fc --- /dev/null +++ b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble-RTL.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62ac756d6cc4079a8262196872a69fd954b7cb7c6c36d620ef673cb29e03a29a +size 219583 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble.png new file mode 100644 index 000000000..df4faef02 --- /dev/null +++ b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Bubble.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7164e0fbc6e603de32225e7a260caed819c7b081c6ce2c8c56db0776c85b7dc +size 221052 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain-RTL.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain-RTL.png new file mode 100644 index 000000000..8a52dc44f --- /dev/null +++ b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain-RTL.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:654156e7f84b79b3f593e9fc28fe73bfbc656d617302cf7428b45e5fc2b90099 +size 198632 diff --git a/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain.png b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain.png new file mode 100644 index 000000000..c56064e8f --- /dev/null +++ b/UnitTests/__Snapshots__/PreviewTests/test_textRoomTimelineView.Plain.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7e0e45c9bda3defd344e3762eec47e8cc2da57035fd0460acce9b4b1a790c24 +size 197095 diff --git a/changelog.d/1915.bugfix b/changelog.d/1915.bugfix new file mode 100644 index 000000000..e15ac7128 --- /dev/null +++ b/changelog.d/1915.bugfix @@ -0,0 +1 @@ +Lists at the beginning of messages were displayed incorrectly.