diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 5ac1533d..908c0a95 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -71,7 +71,7 @@ D62D2422217AA7E1005076CC /* UserActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2421217AA7E1005076CC /* UserActivityManager.swift */; }; D62D2424217ABF3F005076CC /* NSUserActivity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */; }; D62D2426217ABF63005076CC /* UserActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62D2425217ABF63005076CC /* UserActivityType.swift */; }; - D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Trim.swift */; }; + D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; }; D6333B772138D94E00CE884A /* ComposeMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B762138D94E00CE884A /* ComposeMediaView.swift */; }; D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; }; D641C773213CAA25004B4513 /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */; }; @@ -298,7 +298,7 @@ D62D2421217AA7E1005076CC /* UserActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityManager.swift; sourceTree = ""; }; D62D2423217ABF3F005076CC /* NSUserActivity+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSUserActivity+Extensions.swift"; sourceTree = ""; }; D62D2425217ABF63005076CC /* UserActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivityType.swift; sourceTree = ""; }; - D6333B362137838300CE884A /* AttributedString+Trim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Trim.swift"; sourceTree = ""; }; + D6333B362137838300CE884A /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = ""; }; D6333B762138D94E00CE884A /* ComposeMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeMediaView.swift; sourceTree = ""; }; D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+TimeAgo.swift"; sourceTree = ""; }; D641C772213CAA25004B4513 /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = ""; }; @@ -769,7 +769,7 @@ D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */, D663626B21361C6700C9CBA2 /* Account+Preferences.swift */, D66362742137068A00C9CBA2 /* Visibility+Helpers.swift */, - D6333B362137838300CE884A /* AttributedString+Trim.swift */, + D6333B362137838300CE884A /* AttributedString+Helpers.swift */, D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */, D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */, ); @@ -1388,7 +1388,7 @@ 04496BD721625361001F1B23 /* ContentLabel.swift in Sources */, D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */, D6C693CA2161253F007D6A6D /* SilentActionPermissionsTableViewController.swift in Sources */, - D6333B372137838300CE884A /* AttributedString+Trim.swift in Sources */, + D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */, D6B8DB342182A59300424AF7 /* UIAlertController+Visibility.swift in Sources */, D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */, D641C777213CAA9E004B4513 /* ActionNotificationTableViewCell.swift in Sources */, diff --git a/Tusker/Extensions/AttributedString+Trim.swift b/Tusker/Extensions/AttributedString+Helpers.swift similarity index 57% rename from Tusker/Extensions/AttributedString+Trim.swift rename to Tusker/Extensions/AttributedString+Helpers.swift index e49ea310..6ad67cdc 100644 --- a/Tusker/Extensions/AttributedString+Trim.swift +++ b/Tusker/Extensions/AttributedString+Helpers.swift @@ -10,15 +10,22 @@ import Foundation extension NSMutableAttributedString { - func trimTrailingCharactersInSet(_ charSet: CharacterSet) { + var fullRange: NSRange { + return NSRange(location: 0, length: self.length) + } + + func trimLeadingCharactersInSet(_ charSet: CharacterSet) { var range = (string as NSString).rangeOfCharacter(from: charSet) -// while range.length != 0 && range.location == 0 { -// replaceCharacters(in: range, with: "") -// range = (string as NSString).rangeOfCharacter(from: charSet) -// } + while range.length != 0 && range.location == 0 { + replaceCharacters(in: range, with: "") + range = (string as NSString).rangeOfCharacter(from: charSet) + } + } + + func trimTrailingCharactersInSet(_ charSet: CharacterSet) { + var range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards) - range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards) while range.length != 0 && range.length + range.location == length { replaceCharacters(in: range, with: "") range = (string as NSString).rangeOfCharacter(from: charSet, options: .backwards) diff --git a/Tusker/Views/ContentLabel.swift b/Tusker/Views/ContentLabel.swift index d4436e62..1a6639ed 100644 --- a/Tusker/Views/ContentLabel.swift +++ b/Tusker/Views/ContentLabel.swift @@ -89,8 +89,6 @@ class ContentLabel: LinkLabel { // this would get trimmed and cause range out of bounds crashes mutAttrString.trimTrailingCharactersInSet(.whitespacesAndNewlines) - mutAttrString.addAttribute(.font, value: font!, range: NSRange(location: 0, length: mutAttrString.length)) - self.links = [] let linkAttributes: [NSAttributedString.Key: Any] = [ .foregroundColor: UIColor.blue, @@ -125,11 +123,46 @@ class ContentLabel: LinkLabel { case "a": if let link = try? node.attr("href"), let url = URL(string: link) { - let linkRange = NSRange(location: 0, length: attributed.length) - links[linkRange] = url + links[attributed.fullRange] = url } case "p": attributed.append(NSAttributedString(string: "\n\n")) + case "em", "i": + attributed.addAttribute(.font, value: UIFont.italicSystemFont(ofSize: font!.pointSize), range: attributed.fullRange) + case "strong", "b": + attributed.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: font!.pointSize), range: attributed.fullRange) + case "del": + attributed.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: attributed.fullRange) + case "code": + attributed.addAttribute(.font, value: UIFont(name: "Menlo", size: font!.pointSize)!, range: attributed.fullRange) + case "pre": + attributed.addAttribute(.font, value: UIFont(name: "Menlo", size: font!.pointSize)!, range: attributed.fullRange) + attributed.append(NSAttributedString(string: "\n\n")) + case "ol", "ul": + attributed.trimLeadingCharactersInSet(.whitespacesAndNewlines) + attributed.append(NSAttributedString(string: "\n")) + break + case "li": + let parentEl = node.parent()! + let parentTag = parentEl.tagName() + let bullet: NSAttributedString + if parentTag == "ol" { + let index = (try? node.elementSiblingIndex()) ?? 0 + // we use the monospace digit font so that the periods of all the list items line up + bullet = NSAttributedString(string: "\(index + 1).\t", attributes: [.font: UIFont.monospacedDigitSystemFont(ofSize: font!.pointSize, weight: .regular)]) + } else if parentTag == "ul" { + bullet = NSAttributedString(string: "\u{2022}\t") + } else { + bullet = NSAttributedString(string: "") + } + // inserting bullets at the beginning of the string shifts all the links down, so we adjust the link ranges + for (range, url) in links { + let newRange = NSRange(location: range.location + bullet.length - 1, length: range.length) + links[newRange] = url + links.removeValue(forKey: range) + } + attributed.insert(bullet, at: 0) + attributed.append(NSAttributedString(string: "\n")) default: break }