block - // - or, just define a `NSBackgroundColorAttributeName` attribute - attributedString.enumerateAttribute(.DTTextBlocks, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in - guard let value = value as? NSArray, - let dtTextBlock = value.firstObject as? DTTextBlock, - dtTextBlock.backgroundColor == temporaryBlockquoteMarkingColor else { - return - } - - attributedString.addAttribute(.MatrixBlockquote, value: true, range: range) - } - - attributedString.enumerateAttribute(.backgroundColor, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in - guard let value = value as? UIColor, - value == temporaryBlockquoteMarkingColor else { - return - } - - attributedString.removeAttribute(.backgroundColor, range: range) - attributedString.addAttribute(.MatrixBlockquote, value: true, range: range) - } - } - - private func replaceMarkedCodeBlocks(_ attributedString: NSMutableAttributedString) { - attributedString.enumerateAttribute(.backgroundColor, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in - if let value = value as? UIColor, - value == temporaryCodeBlockMarkingColor { - attributedString.addAttribute(.backgroundColor, value: UIColor.compound._bgCodeBlock as Any, range: range) - attributedString.removeAttribute(.link, range: range) - } - } - } - func addMatrixEntityPermalinkAttributesTo(_ attributedString: NSMutableAttributedString) { attributedString.enumerateAttribute(.link, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in if value != nil { @@ -324,53 +351,6 @@ struct AttributedStringBuilderV2: AttributedStringBuilderProtocol { attributedString.addAttribute(.link, value: finalURL, range: range) } - - private func removeDTCoreTextArtifacts(_ attributedString: NSMutableAttributedString) { - guard attributedString.length > 0 else { - return - } - - // DTCoreText adds a newline at the end of plain text ( https://github.com/Cocoanetics/DTCoreText/issues/779 ) - // or after a blockquote section. - // Trim trailing whitespace and newlines in the string content - while (attributedString.string as NSString).hasSuffixCharacter(from: .whitespacesAndNewlines) { - attributedString.deleteCharacters(in: .init(location: attributedString.length - 1, length: 1)) - } - } - - private var defaultCSS: String { - """ - blockquote { - background: \(temporaryBlockquoteMarkingColor.toHexString()); - display: block; - } - pre,code { - background-color: \(temporaryCodeBlockMarkingColor.toHexString()); - display: inline; - white-space: pre; - font-size: 0.9em; - -coretext-fontname: .AppleSystemUIFontMonospaced-Regular; - } - h1,h2,h3 { - font-size: 1.2em; - } - """ - } -} - -private extension UIColor { - func toHexString() -> String { - var red: CGFloat = 0.0 - var green: CGFloat = 0.0 - var blue: CGFloat = 0.0 - var alpha: CGFloat = 0.0 - - getRed(&red, green: &green, blue: &blue, alpha: &alpha) - - let rgb = Int(red * 255) << 16 | Int(green * 255) << 8 | Int(blue * 255) << 0 - - return NSString(format: "#%06x", rgb) as String - } } private struct TextParsingMatch { @@ -396,3 +376,23 @@ private struct TextParsingMatch { } } } + +private extension NSMutableAttributedString { + func setFontPreservingSymbolicTraits(_ newFont: UIFont) { + enumerateAttribute(.font, in: NSRange(location: 0, length: length)) { value, range, _ in + if let oldFont = value as? UIFont { + // keep the traits (bold, italic, etc.) + let traits = oldFont.fontDescriptor.symbolicTraits + if let descriptor = newFont.fontDescriptor.withSymbolicTraits(traits) { + let updatedFont = UIFont(descriptor: descriptor, size: newFont.pointSize) + addAttribute(.font, value: updatedFont, range: range) + } else { + // fallback if traits can't be applied + addAttribute(.font, value: newFont, range: range) + } + } else { + addAttribute(.font, value: newFont, range: range) + } + } + } +} diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift index 11b86e624..ef1232385 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift @@ -134,24 +134,35 @@ struct FormattedBodyText: View { struct FormattedBodyText_Previews: PreviewProvider, TestablePreview { static var previews: some View { - body + body(AttributedStringBuilderV1(cacheKey: "v1", mentionBuilder: MentionBuilder())) + .previewLayout(.sizeThatFits) + + body(AttributedStringBuilderV2(cacheKey: "v2", mentionBuilder: MentionBuilder())) + .previewLayout(.sizeThatFits) } @ViewBuilder - static var body: some View { + static func body(_ attributedStringBuilder: AttributedStringBuilderProtocol) -> some View { let htmlStrings = [ """ - Plain text\n - !room:matrix.org\n - https://www.matrix.org\n - www.matrix.org\n + Plain text +
+ !room:matrix.org +
+ https://www.matrix.org +
+ www.matrix.org +
matrix.org +
+ what's sup dude? +
+ thumbs if you liked it, sub if you loved it """, """ Text before blockquote -- bold italic -Text after blockquote +bold italic+ Text after blockquote """, """First blockquote with a link in it@@ -165,6 +176,21 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview {And a simple reply here.
""", """ ++ """, + """struct ContentView: View { + var body: some View { + VStack { + Text("Knock, knock!") + .padding() + .background(Color.yellow, in: RoundedRectangle(cornerRadius: 8)) + Text("Who's there?") + } + .padding() + } + } ++Hello worldText
Hello world@@ -178,8 +204,6 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview { "test
\ntest
" ] - let attributedStringBuilder = AttributedStringBuilder(mentionBuilder: MentionBuilder()) - ScrollView { VStack(alignment: .leading, spacing: 24.0) { ForEach(htmlStrings, id: \.self) { htmlString in diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png index d62e13f25..a805e2205 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a5300140d0d125b42c74b95e136ca19e809d0ca441f63dcf3e0eff2c38c0522 -size 319205 +oid sha256:934392ab4fdab8bd7bdb73ec3fde03c80ec86c045af86c7af0d43f2b9c973307 +size 431642 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-1.png new file mode 100644 index 000000000..8841dbf66 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-en-GB-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555d7ae30575387972f64caa2d324bcb5511c27aad11b80a0d74daafe0a80651 +size 403362 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png index d62e13f25..a805e2205 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a5300140d0d125b42c74b95e136ca19e809d0ca441f63dcf3e0eff2c38c0522 -size 319205 +oid sha256:934392ab4fdab8bd7bdb73ec3fde03c80ec86c045af86c7af0d43f2b9c973307 +size 431642 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-1.png new file mode 100644 index 000000000..8841dbf66 --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPad-pseudo-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:555d7ae30575387972f64caa2d324bcb5511c27aad11b80a0d74daafe0a80651 +size 403362 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-0.png index 58191e1c4..1e18a0b07 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:974272940990f0fd78e1f403c74ba9714fe8662d79399e91f63307bc35421fdd -size 247463 +oid sha256:c32002366537dbb2498693c6404bbb7f04c8e2b6d4276c27cf8e7b6da726c41d +size 327007 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-1.png new file mode 100644 index 000000000..79e77d47a --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-en-GB-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:070581019f6b97ffdad6ebb5b895211e1359c3f77f05b34c9addfafc3fe4b7aa +size 302644 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-0.png index 58191e1c4..1e18a0b07 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:974272940990f0fd78e1f403c74ba9714fe8662d79399e91f63307bc35421fdd -size 247463 +oid sha256:c32002366537dbb2498693c6404bbb7f04c8e2b6d4276c27cf8e7b6da726c41d +size 327007 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-1.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-1.png new file mode 100644 index 000000000..79e77d47a --- /dev/null +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/formattedBodyText.iPhone-16-pseudo-1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:070581019f6b97ffdad6ebb5b895211e1359c3f77f05b34c9addfafc3fe4b7aa +size 302644