ノート表示の強化と柔軟なリンク・HTML対応の導入
- ノートの表示処理を、通常テキスト・リンク自動検出・HTML埋め込みの三通りで動的に切り替える新ロジックを導入 - ノート内にHTMLが含まれる場合のパース&レンダリングをサポート - テキストから自動でURLを抽出し、クリック可能なリンクとして表示できるように改良 - 表示部分の変更に合わせ、既存のTextウィジェット処理をattributedStringによる表示へと切り替え
This commit is contained in:
@@ -232,7 +232,7 @@ struct EventDetailView: View {
|
|||||||
Image(systemName: "note.text")
|
Image(systemName: "note.text")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.frame(width: 20)
|
.frame(width: 20)
|
||||||
Text(notes)
|
Text(attributedString(from: notes))
|
||||||
.textSelection(.enabled)
|
.textSelection(.enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,4 +257,60 @@ struct EventDetailView: View {
|
|||||||
formatter.locale = Locale(identifier: "ja_JP")
|
formatter.locale = Locale(identifier: "ja_JP")
|
||||||
return formatter.string(from: date)
|
return formatter.string(from: date)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func isHTML(_ string: String) -> Bool {
|
||||||
|
let htmlPatterns = ["<a ", "<p>", "<p ", "<br", "<div", "<span", "<b>", "<i>", "<ul", "<ol", "<li"]
|
||||||
|
let lowercased = string.lowercased()
|
||||||
|
return htmlPatterns.contains { lowercased.contains($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func attributedString(from notes: String) -> AttributedString {
|
||||||
|
if isHTML(notes) {
|
||||||
|
return attributedStringFromHTML(notes)
|
||||||
|
} else {
|
||||||
|
return attributedStringWithLinks(notes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func attributedStringFromHTML(_ html: String) -> AttributedString {
|
||||||
|
let styledHTML = """
|
||||||
|
<style>
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||||
|
</style>
|
||||||
|
\(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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user