diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 650f2f1..36e9c7b 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -232,7 +232,7 @@ struct EventDetailView: View { Image(systemName: "note.text") .foregroundColor(.secondary) .frame(width: 20) - Text(notes) + Text(attributedString(from: notes)) .textSelection(.enabled) } } @@ -257,4 +257,60 @@ struct EventDetailView: View { formatter.locale = Locale(identifier: "ja_JP") return formatter.string(from: date) } + + private func isHTML(_ string: String) -> Bool { + let htmlPatterns = ["", "

", "", " AttributedString { + if isHTML(notes) { + return attributedStringFromHTML(notes) + } else { + return attributedStringWithLinks(notes) + } + } + + private func attributedStringFromHTML(_ html: String) -> AttributedString { + let styledHTML = """ + + \(html) + """ + guard let data = styledHTML.data(using: .utf8) else { + return AttributedString(html) + } + do { + let nsAttrStr = try NSAttributedString( + data: data, + options: [ + .documentType: NSAttributedString.DocumentType.html, + .characterEncoding: String.Encoding.utf8.rawValue + ], + documentAttributes: nil + ) + return AttributedString(nsAttrStr) + } catch { + return AttributedString(html) + } + } + + private func attributedStringWithLinks(_ text: String) -> AttributedString { + var attributedString = AttributedString(text) + guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { + return attributedString + } + let matches = detector.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count)) + for match in matches { + guard let range = Range(match.range, in: text), + let url = match.url, + let attrRange = Range(range, in: attributedString) else { + continue + } + attributedString[attrRange].link = url + } + return attributedString + } }