From 690a177f6b9e9226dad408b26f49c7d33e367952 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Wed, 13 May 2026 11:49:44 +0200 Subject: [PATCH] apply last character font size to the attachment --- .../Sources/Other/Pills/MessageText.swift | 24 +++++++++++++++++-- .../Timeline/View/Style/TimelineStyler.swift | 10 ++++++++ .../TimelineItemViews/FormattedBodyText.swift | 2 +- ...-different-layout-languages-iPad-en-GB.png | 4 ++-- ...different-layout-languages-iPad-pseudo.png | 4 ++-- ...ifferent-layout-languages-iPhone-en-GB.png | 4 ++-- ...fferent-layout-languages-iPhone-pseudo.png | 4 ++-- ...-different-layout-languages-iPad-en-GB.png | 4 ++-- ...different-layout-languages-iPad-pseudo.png | 4 ++-- ...ifferent-layout-languages-iPhone-en-GB.png | 4 ++-- ...fferent-layout-languages-iPhone-pseudo.png | 4 ++-- 11 files changed, 49 insertions(+), 19 deletions(-) diff --git a/ElementX/Sources/Other/Pills/MessageText.swift b/ElementX/Sources/Other/Pills/MessageText.swift index 7eece0bb7..845e13256 100644 --- a/ElementX/Sources/Other/Pills/MessageText.swift +++ b/ElementX/Sources/Other/Pills/MessageText.swift @@ -102,14 +102,34 @@ struct MessageText: UIViewRepresentable { size: CGSize(width: trailingReservedSize.width, height: max(trailingReservedSize.height, 1))) + // Inherit the font from the preceding character so the appended runs + // (newline and attachment) carry the same line metrics as the surrounding + // text — otherwise a small default font on those characters can shrink the + // line height and clip e.g. a font-boosted lone emoji. + let trailingFont = baseText.length > 0 + ? baseText.attribute(.font, at: baseText.length - 1, effectiveRange: nil) + : nil + // When the last paragraph's natural text direction doesn't match the layout // direction, the inline attachment would land on the wrong side and overlap the // overlaid timestamp. Force it onto its own line so the bubble just grows taller. if !lastParagraphDirectionMatchesLayout(in: combined) { - combined.append(NSAttributedString(string: "\n")) + let newlineString = NSMutableAttributedString(string: "\n") + if let trailingFont { + newlineString.addAttribute(.font, + value: trailingFont, + range: NSRange(location: 0, length: newlineString.length)) + } + combined.append(newlineString) } - combined.append(NSAttributedString(attachment: attachment)) + let attachmentString = NSMutableAttributedString(attachment: attachment) + if let trailingFont { + attachmentString.addAttribute(.font, + value: trailingFont, + range: NSRange(location: 0, length: attachmentString.length)) + } + combined.append(attachmentString) } return combined diff --git a/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift b/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift index d67025977..2fe83923b 100644 --- a/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift +++ b/ElementX/Sources/Screens/Timeline/View/Style/TimelineStyler.swift @@ -152,6 +152,15 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview { canBeRepliedTo: true, sender: .test, content: .init(body: "באמת! -- house!")) + + static let bigEmoji = TextRoomTimelineItem(id: .randomEvent, + timestamp: .mock, + isOutgoing: true, + isEditable: false, + canBeRepliedTo: true, + shouldBoost: true, + sender: .test, + content: .init(body: "😮")) static var testView: some View { VStack(spacing: 0) { @@ -172,6 +181,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview { TextRoomTimelineView(timelineItem: rtlStringThatContainsLtr) TextRoomTimelineView(timelineItem: ltrStringThatFinishesInRtl) TextRoomTimelineView(timelineItem: rtlStringThatFinishesInLtr) + TextRoomTimelineView(timelineItem: bigEmoji) } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift index 6cbdd77ca..dce11e997 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift @@ -24,7 +24,7 @@ struct FormattedBodyText: View { private var attributedComponents: [AttributedStringBuilderComponent] { var adjustedAttributedString = attributedString - // Required to allow the underlying TextView to use body font when no font is specifie in the AttributedString. + // Required to allow the underlying TextView to use body font when no font is specified in the AttributedString. adjustedAttributedString.mergeAttributes(defaultAttributesContainer, mergePolicy: .keepCurrent) let string = String(attributedString.characters) diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-en-GB.png index b90bdac90..09205448d 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d9ea384798ed026735ed3d875f55bcfb56f329957e87ff51c101d723985bdaf -size 105891 +oid sha256:daa12b1efbc92c4dccf9a562a65389f75cc4fe3d85841d657f7a16d47f06a07b +size 126617 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-pseudo.png index e3aa07250..a8293cee5 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7b7852f0ba84a9692db2943eafd77517e40d22de0b82347ccde0e316ed6b299 -size 110670 +oid sha256:0cb0b55bd81599cae6dc6074f7b063ca541ebbd1703873339d6e44e23a93509d +size 132787 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-en-GB.png index 8fafae07c..164d1849a 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9054993c31c97deb1e8830fb7e3ec5b056b0422434c8f0ca98249542c952f8f -size 62340 +oid sha256:61f1b79a8425e639afbbe3b6b508d4f7e0c3282e513a3a39eed365c6dacc63bc +size 82269 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-pseudo.png index 2723c998c..2594e3c52 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-LTR-with-different-layout-languages-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:855838858b0c0cffe293175bc327172abd136e83f09843e156c87ec11fc2418a -size 65773 +oid sha256:773e8b830d6874356aa538d88b5ab6d7ffa08852a5a8539fa491cfeddb88275c +size 86925 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-en-GB.png index bcbf28712..530c09538 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5668b46725738b0818b93e354d3f82fd9d61eeae86a057112e378a406666bbba -size 104283 +oid sha256:499bf1736192faf92378530ef2da344088a842587ccd3bb33cd943faf3a65d43 +size 124605 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-pseudo.png index a06aa63df..f015046c3 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62565ccd3424d2e0d0f04823b3a36d2d6a98e793f172b4fa149536a02683c318 -size 109345 +oid sha256:15a353e80323637bd0fe1037c82fa1d68ee6ff438050c6ef7aad61e1648cd19f +size 130697 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-en-GB.png index c3025dd44..4ee01ad60 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc85f143df29944f9da45f8afa556c97034308ec6be9db427b90bec6ec820743 -size 60347 +oid sha256:8d6b9aeb5a9ba5120a473a1c1458d6be66a42ec18f8688e999fb25a00ac01980 +size 80042 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-pseudo.png index 04ea410d0..f9a03276e 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/timelineItemStyler.Bubbles-RTL-with-different-layout-languages-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0d0728ba0ca764a8beb2a46f813707f9505ee7d02ac5610a101913e7d8868924 -size 64053 +oid sha256:f184da565bdea14e33c8e65ae8dc8f69049cce7ab833e33fd3136f2d5069cd23 +size 84843