diff --git a/ElementX/Sources/Other/Extensions/AttributedString.swift b/ElementX/Sources/Other/Extensions/AttributedString.swift index f5027c7ab..668f5484d 100644 --- a/ElementX/Sources/Other/Extensions/AttributedString.swift +++ b/ElementX/Sources/Other/Extensions/AttributedString.swift @@ -18,7 +18,12 @@ import Foundation extension AttributedString { var formattedComponents: [AttributedStringBuilderComponent] { - runs[\.blockquote].map { value, range in + var components = [AttributedStringBuilderComponent]() + + for (index, run) in runs[\.blockquote].enumerated() { + let value = run.0 + let range = run.1 + var attributedString = AttributedString(self[range]) // Remove trailing new lines if any @@ -29,8 +34,10 @@ extension AttributedString { let isBlockquote = value != nil - return AttributedStringBuilderComponent(attributedString: attributedString, isBlockquote: isBlockquote) + components.append(AttributedStringBuilderComponent(id: index, attributedString: attributedString, isBlockquote: isBlockquote)) } + + return components } /// Replaces the specified placeholder with a string that links to the specified URL. diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderProtocol.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderProtocol.swift index 1c244265c..21124dd13 100644 --- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderProtocol.swift +++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilderProtocol.swift @@ -16,7 +16,8 @@ import Foundation -struct AttributedStringBuilderComponent: Hashable { +struct AttributedStringBuilderComponent: Hashable, Identifiable { + let id: Int let attributedString: AttributedString let isBlockquote: Bool } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift index 3464362cd..68ffba554 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/FormattedBodyText.swift @@ -93,7 +93,7 @@ struct FormattedBodyText: View { /// The attributed components laid out for the bubbles timeline style. var bubbleLayout: some View { TimelineBubbleLayout(spacing: 8) { - ForEach(attributedComponents, id: \.self) { component in + ForEach(attributedComponents) { component in // Ignore if the string contains only the layout correction if String(component.attributedString.characters) == layoutDirection.isolateLayoutUnicodeString { EmptyView() @@ -123,7 +123,7 @@ struct FormattedBodyText: View { // Make a second iteration through the components adding fixed width blockquotes // which are used for layout calculations but won't be rendered. - ForEach(attributedComponents, id: \.self) { component in + ForEach(attributedComponents) { component in if component.isBlockquote { MessageText(attributedString: component.attributedString.mergingAttributes(blockquoteAttributes)) .fixedSize(horizontal: false, vertical: true) @@ -138,7 +138,7 @@ struct FormattedBodyText: View { /// The attributed components laid out for the plain timeline style. var plainLayout: some View { VStack(alignment: .leading, spacing: 8.0) { - ForEach(attributedComponents, id: \.self) { component in + ForEach(attributedComponents) { component in if component.isBlockquote { HStack(spacing: 4.0) { Rectangle() diff --git a/changelog.d/2286.bugfix b/changelog.d/2286.bugfix new file mode 100644 index 000000000..c9c7d1ebb --- /dev/null +++ b/changelog.d/2286.bugfix @@ -0,0 +1 @@ +Fix timeline entries flickering when a lot of mention pills present \ No newline at end of file