From 2217803825c6af5d64146f953ba242850a211ad7 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Mon, 11 May 2026 17:11:18 +0200 Subject: [PATCH] update all the timeline item views to use the new implemementation with nstextattachment --- ElementX.xcodeproj/project.pbxproj | 10 --- .../AudioFileEventsTimelineView.swift | 2 +- .../FileMediaEventsTimelineView.swift | 2 +- .../AudioRoomTimelineView.swift | 2 +- .../EmoteRoomTimelineView.swift | 6 +- .../FileRoomTimelineView.swift | 8 +- .../TimelineItemViews/FormattedBodyText.swift | 75 +++++++++---------- .../ImageRoomTimelineView.swift | 4 +- .../LocationRoomTimelineView.swift | 3 +- .../NoticeRoomTimelineView.swift | 6 +- .../TextRoomTimelineView.swift | 4 +- .../VideoRoomTimelineView.swift | 4 +- 12 files changed, 57 insertions(+), 69 deletions(-) diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 0e6053a15..42a334bf3 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -352,7 +352,6 @@ 3A2640C52505BAB3D983A92A /* RemotePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A05E85E4872C3221C5C287 /* RemotePreference.swift */; }; 3A64A93A651A3CB8774ADE8E /* SwiftOGG in Frameworks */ = {isa = PBXBuildFile; productRef = 3FE40E79C36E7903121E6E3B /* SwiftOGG */; }; 3A68752BB9D51B8713C0FC2C /* AuthenticationStartScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A768CA51A59B8A5D8C8FD599 /* AuthenticationStartScreen.swift */; }; - 3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */; }; 3AA9E878FDCFF85664AC071F /* ComposerDraftService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D70253004A5AEC9C73D6A4F /* ComposerDraftService.swift */; }; 3B0718607B0665D163142DAE /* SDKGeneratedMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C5BFCB7257F7A3CF70F5DA9 /* SDKGeneratedMocks.swift */; }; 3B0F9B57D25B07E66F15762A /* MediaUploadPreviewScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2E7C987AE5DC9087BB19F7D /* MediaUploadPreviewScreenModels.swift */; }; @@ -1409,7 +1408,6 @@ EE4F6D6F54B8F09F10CA66BE /* ClassicAppAES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384A744714571BAF138C6B86 /* ClassicAppAES.swift */; }; EE56238683BC3ECA9BA00684 /* GlobalSearchScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA4D639E27D5882A6A71AECF /* GlobalSearchScreenViewModelTests.swift */; }; EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */; }; - EEAE954289DE813A61656AE0 /* LayoutDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */; }; EEB9C1555C63B93CA9C372C2 /* EmojiPickerScreenHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5E29E9A22F45534FBD5B58 /* EmojiPickerScreenHeaderView.swift */; }; EEC40663922856C65D1E0DF5 /* KeychainControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */; }; EED33AFD9334EFD7398707A6 /* VisualListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD529C89924EE32CE307F36F /* VisualListItem.swift */; }; @@ -1496,7 +1494,6 @@ FA5A7E32B1920FCB4EEDC1BA /* RoomDetailsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6493AC9979CEB1410302BFE3 /* RoomDetailsScreenCoordinator.swift */; }; FA71CD334F2D2289BEF0D749 /* SecureBackupRecoveryKeyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */; }; FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; }; - FB0A9D06FC9122E37992D962 /* LayoutDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */; }; FB595EC9C00AB32F39034055 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A37E2FACFD041CE466223CD /* SceneDelegate.swift */; }; FBD402E3170EB1ED0D1AA672 /* EncryptionKeyProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2355398E4A55DA5A89128AD1 /* EncryptionKeyProvider.swift */; }; FBF09B6C900415800DDF2A21 /* EmojiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C113E0CB7E15E9765B1817A /* EmojiProvider.swift */; }; @@ -1871,7 +1868,6 @@ 2A5C6FBF97B6EED3D4FA5EFF /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = ""; }; 2A7BE2B89310058659E6F459 /* accountsV2 */ = {isa = PBXFileReference; path = accountsV2; sourceTree = ""; }; 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingHook.swift; sourceTree = ""; }; - 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineTests.swift; sourceTree = ""; }; 2ADF12A50186B75C68017B61 /* DeclineAndBlockScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenViewModelTests.swift; sourceTree = ""; }; 2AE807361805463F5AEDD1CA /* VoiceMessagePreviewComposer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessagePreviewComposer.swift; sourceTree = ""; }; 2AE83A3DD63BCFBB956FE5CB /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Localizable.stringsdict; sourceTree = ""; }; @@ -2714,7 +2710,6 @@ C0FEA560929DD73FFEF8C3DF /* HomeScreenEmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenEmptyStateView.swift; sourceTree = ""; }; C11397904D19CFF0E3689F0E /* SpaceScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpaceScreenModels.swift; sourceTree = ""; }; C142248014E08E885E323E56 /* Avatars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Avatars.swift; sourceTree = ""; }; - C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutDirection.swift; sourceTree = ""; }; C1511766C534367700C8DD75 /* RoomNotificationModeProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomNotificationModeProxy.swift; sourceTree = ""; }; C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeView.swift; sourceTree = ""; }; C258C9C815272911A5B132C3 /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = ""; }; @@ -4251,7 +4246,6 @@ E3877D3CFAC1D33823359BAF /* HTMLParserStyle.swift */, 4E2245243369B99216C7D84E /* ImageCache.swift */, 045253F9967A535EE5B16691 /* Label.swift */, - C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */, F72EFC8C634469F9262659C7 /* NSItemProvider.swift */, 95BAC0F6C9644336E9567EE6 /* NSRegularExpresion.swift */, 5327E3B3C58BEB0E65F4CF98 /* Observable.swift */, @@ -4993,7 +4987,6 @@ 18B223FA339BF53085328DEE /* SpaceScreenViewModelTests.swift */, 6DF438EAFC732D2D95D34BF6 /* StartChatViewModelTests.swift */, 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */, - 2AB2C848BB9A7A9B618B7B89 /* TextBasedRoomTimelineTests.swift */, 9AA3AF94A06D319BB37E52DA /* TimelineItemFactoryTests.swift */, ED0AD0C652385F69FA90FAF5 /* TimelineMediaPreviewDataSourceTests.swift */, 5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */, @@ -7783,7 +7776,6 @@ EBE13FAB4E29738AC41BD3E5 /* InfoPlistReader.swift in Sources */, 8691186F9B99BCDDB7CACDD8 /* KeychainController.swift in Sources */, A440D4BC02088482EC633A88 /* KeychainControllerProtocol.swift in Sources */, - FB0A9D06FC9122E37992D962 /* LayoutDirection.swift in Sources */, D3ED5692672892F9F1E7375A /* LiveLocationSession.swift in Sources */, 0728314DD51AC3819F818EA8 /* LogLevel.swift in Sources */, AD2A81B65A9F6163012086F1 /* MXLog.swift in Sources */, @@ -7961,7 +7953,6 @@ 6189B4ABD535CE526FA1107B /* StartChatViewModelTests.swift in Sources */, 1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */, E75CE800B3E64D0F7F8E228D /* TemplateScreenViewModelTests.swift in Sources */, - 3A7DD0D13B0FB8876D69D829 /* TextBasedRoomTimelineTests.swift in Sources */, 0D4EB2ABAA5FE8CB10FDBCB8 /* TimelineItemFactoryTests.swift in Sources */, C02DE5F62C81FB9E173C3D2F /* TimelineMediaPreviewDataSourceTests.swift in Sources */, F6BF52CB027393EE03CEC523 /* TimelineMediaPreviewViewModelTests.swift in Sources */, @@ -8446,7 +8437,6 @@ C900127318820AD04D6C90B8 /* LabsScreenModels.swift in Sources */, EC1A0E85CEE50BF0C64EEFA5 /* LabsScreenViewModel.swift in Sources */, D23BA23864EA7BA3F353C0D1 /* LabsScreenViewModelProtocol.swift in Sources */, - EEAE954289DE813A61656AE0 /* LayoutDirection.swift in Sources */, EFF735EC040BEB669AFBAB50 /* LeaveSpaceHandleProxy.swift in Sources */, DD21CE51DF9BD04FC8155972 /* LeaveSpaceHandleSDKMock.swift in Sources */, DA8AE352C8FFCD47327811CA /* LeaveSpaceModels.swift in Sources */, diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/AudioFileEventsTimelineView.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/AudioFileEventsTimelineView.swift index 765d2f81b..3dd467a60 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/AudioFileEventsTimelineView.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/AudioFileEventsTimelineView.swift @@ -17,7 +17,7 @@ struct AudioMediaEventsTimelineView: View { fileSize: timelineItem.content.fileSize, caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, - additionalWhitespaces: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, isAudioFile: true) .accessibilityLabel(L10n.commonAudio) .frame(maxWidth: .infinity, alignment: .leading) diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/FileMediaEventsTimelineView.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/FileMediaEventsTimelineView.swift index 7bf4b9a8e..a55ebca8a 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/FileMediaEventsTimelineView.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/View/TimelineViews/FileMediaEventsTimelineView.swift @@ -17,7 +17,7 @@ struct FileMediaEventsTimelineView: View { fileSize: timelineItem.content.fileSize, caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, - additionalWhitespaces: timelineItem.additionalWhitespaces()) + trailingReservedSize: timelineItem.trailingReservedSize) .accessibilityLabel(L10n.commonFile) .frame(maxWidth: .infinity, alignment: .leading) .bubbleBackground(isOutgoing: timelineItem.isOutgoing) diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift index 6bf8b9d96..97f1ea315 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift @@ -19,7 +19,7 @@ struct AudioRoomTimelineView: View { fileSize: timelineItem.content.fileSize, caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, - additionalWhitespaces: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, shouldBoost: timelineItem.shouldBoost, isAudioFile: true) { context?.send(viewAction: .mediaTapped(itemID: timelineItem.id)) diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/EmoteRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/EmoteRoomTimelineView.swift index c1736d1ce..16e3f5b6f 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/EmoteRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/EmoteRoomTimelineView.swift @@ -15,9 +15,11 @@ struct EmoteRoomTimelineView: View, TextBasedRoomTimelineViewProtocol { var body: some View { TimelineStyler(timelineItem: timelineItem) { if let attributedString = timelineItem.content.formattedBody { - FormattedBodyText(attributedString: attributedString, additionalWhitespacesCount: timelineItem.additionalWhitespaces()) + FormattedBodyText(attributedString: attributedString, + trailingReservedSize: timelineItem.trailingReservedSize) } else { - FormattedBodyText(text: timelineItem.content.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces()) + FormattedBodyText(text: timelineItem.content.body, + trailingReservedSize: timelineItem.trailingReservedSize) } } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift index 584a5d036..1a44bc67e 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift @@ -19,7 +19,7 @@ struct FileRoomTimelineView: View { fileSize: timelineItem.content.fileSize, caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, - additionalWhitespaces: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, shouldBoost: timelineItem.shouldBoost) { context?.send(viewAction: .mediaTapped(itemID: timelineItem.id)) } @@ -35,7 +35,7 @@ struct MediaFileRoomTimelineContent: View { let fileSize: UInt? let caption: String? let formattedCaption: AttributedString? - let additionalWhitespaces: Int + var trailingReservedSize: CGSize = .zero var shouldBoost = false var isAudioFile = false @@ -66,11 +66,11 @@ struct MediaFileRoomTimelineContent: View { if let formattedCaption { FormattedBodyText(attributedString: formattedCaption, - additionalWhitespacesCount: additionalWhitespaces, + trailingReservedSize: trailingReservedSize, boostFontSize: shouldBoost) } else if let caption { FormattedBodyText(text: caption, - additionalWhitespacesCount: additionalWhitespaces, + trailingReservedSize: trailingReservedSize, boostFontSize: shouldBoost) } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift index 59409b5fc..8549d0e45 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift @@ -12,7 +12,7 @@ struct FormattedBodyText: View { @Environment(\.layoutDirection) private var layoutDirection private let attributedString: AttributedString - private let additionalWhitespacesCount: Int + private let trailingReservedSize: CGSize private let boostFontSize: Bool private let defaultAttributesContainer: AttributeContainer = { @@ -22,14 +22,9 @@ struct FormattedBodyText: View { container.foregroundColor = UIColor.compound.textPrimary return container }() - + private var attributedComponents: [AttributedStringBuilderComponent] { - 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 - } + var adjustedAttributedString = attributedString // Required to allow the underlying TextView to use body font when no font is specifie in the AttributedString. adjustedAttributedString.mergeAttributes(defaultAttributesContainer, mergePolicy: .keepCurrent) @@ -44,24 +39,19 @@ struct FormattedBodyText: View { } init(attributedString: AttributedString, - additionalWhitespacesCount: Int = 0, + trailingReservedSize: CGSize = .zero, boostFontSize: Bool = false) { self.attributedString = attributedString - self.additionalWhitespacesCount = additionalWhitespacesCount + self.trailingReservedSize = trailingReservedSize self.boostFontSize = boostFontSize } - init(text: String, additionalWhitespacesCount: Int = 0, boostFontSize: Bool = false) { + init(text: String, trailingReservedSize: CGSize = .zero, boostFontSize: Bool = false) { self.init(attributedString: AttributedString(text), - additionalWhitespacesCount: additionalWhitespacesCount, + trailingReservedSize: trailingReservedSize, boostFontSize: boostFontSize) } - /// These is needed to create the slightly off inlined timestamp effect - private var additionalWhitespacesSuffix: String { - .generateBreakableWhitespaceEnd(whitespaceCount: additionalWhitespacesCount, layoutDirection: layoutDirection) - } - var body: some View { layout .tint(.compound.textLinkExternal) @@ -71,36 +61,39 @@ struct FormattedBodyText: View { /// The attributed components laid out for the bubbles timeline style. var layout: some View { - TimelineBubbleLayout(spacing: 8) { - ForEach(attributedComponents) { component in - // Ignore if the string contains only the layout correction - if String(component.attributedString.characters) == layoutDirection.isolateLayoutUnicodeString { - EmptyView() - } else { - switch component.type { - case .blockquote: - BlockquoteView(attributedString: component.attributedString, mode: .rendering) - .timelineBubbleLayoutSize(.bubbleWidth(mode: .rendering)) - case .codeBlock: - CodeBlockView(attributedString: component.attributedString, mode: .rendering) - .timelineBubbleLayoutSize(.bubbleWidth(mode: .rendering)) - .contextMenu { - Button(L10n.actionCopy) { - UIPasteboard.general.string = component.attributedString.string - } + // The trailing reserved area must only be applied to the last plain text + // component so that the bubble's natural size accommodates the overlaid + // timestamp, and TextKit decides whether to keep the timestamp on the last + // line or push it to a new one. + let components = attributedComponents + let lastPlainTextIndex = components.lastIndex { $0.type == .plainText } + + return TimelineBubbleLayout(spacing: 8) { + ForEach(Array(components.enumerated()), id: \.element.id) { index, component in + switch component.type { + case .blockquote: + BlockquoteView(attributedString: component.attributedString, mode: .rendering) + .timelineBubbleLayoutSize(.bubbleWidth(mode: .rendering)) + case .codeBlock: + CodeBlockView(attributedString: component.attributedString, mode: .rendering) + .timelineBubbleLayoutSize(.bubbleWidth(mode: .rendering)) + .contextMenu { + Button(L10n.actionCopy) { + UIPasteboard.general.string = component.attributedString.string } - case .plainText: - MessageText(attributedString: component.attributedString) - .padding(.horizontal, 4) - .fixedSize(horizontal: false, vertical: true) - .timelineBubbleLayoutSize(.natural) - } + } + case .plainText: + MessageText(attributedString: component.attributedString, + trailingReservedSize: index == lastPlainTextIndex ? trailingReservedSize : .zero) + .padding(.horizontal, 4) + .fixedSize(horizontal: false, vertical: true) + .timelineBubbleLayoutSize(.natural) } } // Make a second iteration through the components adding naturally sized versions of the // block quotes and code blocks which are used for layout calculations but won't be rendered. - ForEach(attributedComponents) { component in + ForEach(components) { component in switch component.type { case .blockquote: BlockquoteView(attributedString: component.attributedString, mode: .layout) diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift index 08f9e1ca8..23a508bc4 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift @@ -32,11 +32,11 @@ struct ImageRoomTimelineView: View { if let attributedCaption = timelineItem.content.formattedCaption { FormattedBodyText(attributedString: attributedCaption, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } else if let caption = timelineItem.content.caption { FormattedBodyText(text: caption, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/LocationRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/LocationRoomTimelineView.swift index 316e47478..83ff4be04 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/LocationRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/LocationRoomTimelineView.swift @@ -37,7 +37,8 @@ struct LocationRoomTimelineView: View { .aspectRatio(mapAspectRatio, contentMode: .fit) .clipped() } else { - FormattedBodyText(text: timelineItem.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces()) + FormattedBodyText(text: timelineItem.body, + trailingReservedSize: timelineItem.trailingReservedSize) } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/NoticeRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/NoticeRoomTimelineView.swift index 85c1889d4..c09d84520 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/NoticeRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/NoticeRoomTimelineView.swift @@ -18,9 +18,11 @@ struct NoticeRoomTimelineView: View, TextBasedRoomTimelineViewProtocol { Label { if let attributedString = timelineItem.content.formattedBody { - FormattedBodyText(attributedString: attributedString, additionalWhitespacesCount: timelineItem.additionalWhitespaces()) + FormattedBodyText(attributedString: attributedString, + trailingReservedSize: timelineItem.trailingReservedSize) } else { - FormattedBodyText(text: timelineItem.content.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces()) + FormattedBodyText(text: timelineItem.content.body, + trailingReservedSize: timelineItem.trailingReservedSize) } } icon: { CompoundIcon(\.info, size: .small, relativeTo: .compound.bodyLG) diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift index 20b64d2a5..379b7872d 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift @@ -28,11 +28,11 @@ struct TextRoomTimelineView: View, TextBasedRoomTimelineViewProtocol { VStack(alignment: .leading, spacing: 8) { if let attributedString = timelineItem.content.formattedBody { FormattedBodyText(attributedString: attributedString, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } else { FormattedBodyText(text: timelineItem.body, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift index cc297ad5d..9aa022c2f 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift @@ -33,11 +33,11 @@ struct VideoRoomTimelineView: View { if let attributedCaption = timelineItem.content.formattedCaption { FormattedBodyText(attributedString: attributedCaption, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } else if let caption = timelineItem.content.caption { FormattedBodyText(text: caption, - additionalWhitespacesCount: timelineItem.additionalWhitespaces(), + trailingReservedSize: timelineItem.trailingReservedSize, boostFontSize: timelineItem.shouldBoost) } }