Skip to content

Commit 02900b5

Browse files
Fix markdown-formatter customization accessibility (#3101)
1 parent 6053178 commit 02900b5

File tree

5 files changed

+116
-10
lines changed

5 files changed

+116
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1818
### ✅ Added
1919
- Validates file size limit per attachment type defined in Stream's Dashboard [#3105](https://github.com/GetStream/stream-chat-swift/pull/3105)
2020
- Make it easier to customize `ComposerVC.updateContent()` [#3112](https://github.com/GetStream/stream-chat-swift/pull/3112)
21+
- Add support markdown font styling customization [#3101](https://github.com/GetStream/stream-chat-swift/pull/3101)
22+
2123
### 🐞 Fixed
2224
- Fix support for markdown ordered list with all numbers [#3090](https://github.com/GetStream/stream-chat-swift/pull/3090)
2325
- Fix support for markdown italic and bold styles inside snake-styled text [#3094](https://github.com/GetStream/stream-chat-swift/pull/3094)

DemoApp/StreamChat/StreamChatWrapper+DemoApp.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,17 @@ extension StreamChatWrapper {
6060
Components.default.messageActionsVC = DemoChatMessageActionsVC.self
6161
Components.default.reactionsSorting = { $0.type.position < $1.type.position }
6262
Components.default.messageLayoutOptionsResolver = DemoChatMessageLayoutOptionsResolver()
63+
64+
// Customize MarkdownFormatter
65+
let defaultFormatter = DefaultMarkdownFormatter()
66+
defaultFormatter.styles.bodyFont.color = .systemOrange
67+
defaultFormatter.styles.codeFont.color = .systemPurple
68+
defaultFormatter.styles.h1Font.color = .systemBlue
69+
defaultFormatter.styles.h2Font.color = .systemRed
70+
defaultFormatter.styles.h3Font.color = .systemYellow
71+
defaultFormatter.styles.h4Font.color = .systemGreen
72+
defaultFormatter.styles.h5Font.color = .systemBrown
73+
defaultFormatter.styles.h6Font.color = .systemPink
74+
Appearance.default.formatters.markdownFormatter = defaultFormatter
6375
}
6476
}

Scripts/updateDependency.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ if [[ $dependency_directory == *"DifferenceKit"* ]]; then
7474
fi
7575

7676
if [[ $dependency_directory == *"SwiftyMarkdown"* ]]; then
77-
# We currently use customized version of SwiftyLineProcessor.swift
77+
# We currently use customized version of SwiftyMarkdown
7878
git restore $output_directory/SwiftyMarkdown/SwiftyLineProcessor.swift || true
7979
git restore $output_directory/SwiftyMarkdown/SwiftyTokeniser.swift || true
8080
fi

Sources/StreamChatUI/Appearance+Formatters/MarkdownFormatter.swift

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ public protocol MarkdownFormatter {
1919

2020
/// Default implementation for the Markdown formatter
2121
open class DefaultMarkdownFormatter: MarkdownFormatter {
22-
enum Attributes {
23-
enum Code {
24-
static let fontName: String = "CourierNewPSMT"
25-
}
26-
}
22+
public var styles: MarkdownStyles
23+
public var markdownRegexPattern: String
2724

28-
private let markdownRegexPattern: String =
29-
"((?:\\`(.*?)\\`)|(?:\\*{1,2}(.*?)\\*{1,2})|(?:\\~{2}(.*?)\\~{2})|(?:\\_{1,2}(.*?)\\_{1,2})|^(>){1}|(#){1,6}|(=){3,10}|(-){1,3}|(\\d{1,3}\\.)|(?:\\[(.*?)\\])(?:\\((.*?)\\))|(?:\\[(.*?)\\])(?:\\[(.*?)\\])|(\\]\\:))+"
25+
private let defaultMarkdownRegex = "((?:\\`(.*?)\\`)|(?:\\*{1,2}(.*?)\\*{1,2})|(?:\\~{2}(.*?)\\~{2})|(?:\\_{1,2}(.*?)\\_{1,2})|^(>){1}|(#){1,6}|(=){3,10}|(-){1,3}|(\\d{1,3}\\.)|(?:\\[(.*?)\\])(?:\\((.*?)\\))|(?:\\[(.*?)\\])(?:\\[(.*?)\\])|(\\]\\:))+"
26+
27+
public init() {
28+
styles = MarkdownStyles()
29+
markdownRegexPattern = defaultMarkdownRegex
30+
}
3031

3132
private lazy var regex: NSRegularExpression? = {
3233
guard let regex = try? NSRegularExpression(pattern: markdownRegexPattern, options: .anchorsMatchLines) else {
@@ -43,7 +44,98 @@ open class DefaultMarkdownFormatter: MarkdownFormatter {
4344

4445
open func format(_ string: String) -> NSAttributedString {
4546
let markdownFormatter = SwiftyMarkdown(string: string)
46-
markdownFormatter.code.fontName = Attributes.Code.fontName
47+
modify(swiftyMarkdownFont: markdownFormatter.code, with: styles.codeFont)
48+
modify(swiftyMarkdownFont: markdownFormatter.body, with: styles.bodyFont)
49+
modify(swiftyMarkdownFont: markdownFormatter.link, with: styles.linkFont)
50+
modify(swiftyMarkdownFont: markdownFormatter.h1, with: styles.h1Font)
51+
modify(swiftyMarkdownFont: markdownFormatter.h2, with: styles.h2Font)
52+
modify(swiftyMarkdownFont: markdownFormatter.h3, with: styles.h3Font)
53+
modify(swiftyMarkdownFont: markdownFormatter.h4, with: styles.h4Font)
54+
modify(swiftyMarkdownFont: markdownFormatter.h5, with: styles.h5Font)
55+
modify(swiftyMarkdownFont: markdownFormatter.h6, with: styles.h6Font)
4756
return markdownFormatter.attributedString()
4857
}
58+
59+
private func modify(swiftyMarkdownFont: FontProperties, with font: MarkdownFont) {
60+
if let fontName = font.name {
61+
swiftyMarkdownFont.fontName = fontName
62+
}
63+
if let fontSize = font.size {
64+
swiftyMarkdownFont.fontSize = fontSize
65+
}
66+
if let fontColor = font.color {
67+
swiftyMarkdownFont.color = fontColor
68+
}
69+
if let fontStyle = font.styling?.asSwiftyMarkdownFontStyle() {
70+
swiftyMarkdownFont.fontStyle = fontStyle
71+
}
72+
}
73+
}
74+
75+
/// Configures the font style properties for base Markdown elements
76+
public struct MarkdownStyles {
77+
/// The regular paragraph font.
78+
public var bodyFont: MarkdownFont = .init()
79+
80+
/// The font used for coding blocks in markdown text.
81+
public var codeFont: MarkdownFont = .init()
82+
83+
/// The font used for links found in markdown text.
84+
public var linkFont: MarkdownFont = .init()
85+
86+
/// The font used for H1 headers in markdown text.
87+
public var h1Font: MarkdownFont = .init()
88+
89+
/// The font used for H2 headers in markdown text.
90+
public var h2Font: MarkdownFont = .init()
91+
92+
/// The font used for H3 headers in markdown text.
93+
public var h3Font: MarkdownFont = .init()
94+
95+
/// The font used for H4 headers in markdown text.
96+
public var h4Font: MarkdownFont = .init()
97+
98+
/// The font used for H5 headers in markdown text.
99+
public var h5Font: MarkdownFont = .init()
100+
101+
/// The font used for H6 headers in markdown text.
102+
public var h6Font: MarkdownFont = .init()
103+
104+
public init() {
105+
codeFont.name = "CourierNewPSMT"
106+
}
107+
}
108+
109+
public struct MarkdownFont {
110+
public var name: String?
111+
public var size: Double?
112+
public var color: UIColor?
113+
public var styling: MarkdownFontStyle?
114+
115+
public init() {
116+
name = nil
117+
size = nil
118+
color = nil
119+
styling = nil
120+
}
121+
}
122+
123+
public enum MarkdownFontStyle: Int {
124+
case normal
125+
case bold
126+
case italic
127+
case boldItalic
128+
129+
func asSwiftyMarkdownFontStyle() -> FontStyle {
130+
switch self {
131+
case .normal:
132+
return .normal
133+
case .bold:
134+
return .bold
135+
case .italic:
136+
return .italic
137+
case .boldItalic:
138+
return .boldItalic
139+
}
140+
}
49141
}

Tests/StreamChatUITests/Utils/DefaultMarkdownFormatter_Tests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ final class DefaultMarkdownFormatter_Tests: XCTestCase {
234234
XCTAssertEqual(expectedBoldAttributedSubstring, attributedString.attributedSubstring(from: range).string)
235235
} else if let fontAttribute = fontAttribute,
236236
let fontNameAttribute = fontAttribute.fontDescriptor.fontAttributes[.name] as? String,
237-
fontNameAttribute == DefaultMarkdownFormatter.Attributes.Code.fontName {
237+
fontNameAttribute == DefaultMarkdownFormatter().styles.codeFont.name {
238238
XCTAssertEqual(expectedCodeAttributedSubstring, attributedString.attributedSubstring(from: range).string)
239239
} else if let linkAttribute = attributes[.link] as? NSURL,
240240
let url = linkAttribute.absoluteString {

0 commit comments

Comments
 (0)