Initial pass at message content rendering

This commit is contained in:
Shadowfacts 2018-08-17 23:09:59 -04:00
parent 5cf1163651
commit 8b3f1ba30d
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
1 changed files with 90 additions and 4 deletions

View File

@ -16,14 +16,100 @@ class StatusTableViewCell: UITableViewCell {
@IBOutlet weak var usernameLabel: UILabel! @IBOutlet weak var usernameLabel: UILabel!
@IBOutlet weak var contentLabel: UILabel! @IBOutlet weak var contentLabel: UILabel!
var status: Status!
var layoutManager: NSLayoutManager!
var textContainer: NSTextContainer!
var textStorage: NSTextStorage!
var links: [NSRange: URL] = [:]
func updateUI(for status: Status) { func updateUI(for status: Status) {
displayNameLabel.text = status.account.displayName self.status = status
usernameLabel.text = "@\(status.account.acct)"
let account: Account
if let reblog = status.reblog {
account = reblog.account
} else {
account = status.account
}
displayNameLabel.text = account.displayName
usernameLabel.text = "@\(account.acct)"
let doc = try! SwiftSoup.parse(status.content) let doc = try! SwiftSoup.parse(status.content)
let text = (try! doc.body()?.text())! let body = doc.body()!
print("---")
print(status.content)
print("---")
contentLabel.text = text let text = attributedTextForNode(body)
contentLabel.attributedText = text
contentLabel.isUserInteractionEnabled = true
contentLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapOnContentLabel(_:))))
// https://stackoverflow.com/a/28519273/4731558
layoutManager = NSLayoutManager()
textContainer = NSTextContainer(size: .zero)
textStorage = NSTextStorage(attributedString: text)
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = contentLabel.lineBreakMode
textContainer.maximumNumberOfLines = contentLabel.numberOfLines
}
func attributedTextForNode(_ node: Node) -> NSAttributedString {
switch node {
case let node as TextNode:
return NSAttributedString(string: node.text())
case let node as Element:
let attributed = NSMutableAttributedString()
node.getChildNodes().forEach { child in
attributed.append(attributedTextForNode(child))
}
switch node.tagName() {
case "br":
attributed.append(NSAttributedString(string: "\n"))
case "a":
let linkRange = NSRange(location: 0, length: attributed.length)
let linkAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.blue
]
attributed.setAttributes(linkAttributes, range: linkRange)
let link = try! node.attr("href")
links[linkRange] = URL(string: link)!
default:
break
}
return attributed
default:
fatalError("Unexpected node type: \(type(of: node))")
}
}
@objc func handleTapOnContentLabel(_ tapGesture: UITapGestureRecognizer) {
guard let view = tapGesture.view else { fatalError() }
let locationOfTouchInLabel = tapGesture.location(in: view)
let labelSize = view.bounds.size
let textBoundingBox = layoutManager.usedRect(for: textContainer)
let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x,
y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y)
let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x,
y: locationOfTouchInLabel.y - textContainerOffset.y)
let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
let link = links.first { (range, _) -> Bool in
range.contains(indexOfCharacter)
}
if let (_, url) = link {
print("Open URL: \(url)")
}
} }
} }