forked from shadowfacts/Tusker
Initial pass at message content rendering
This commit is contained in:
parent
5dacb787a6
commit
354b3469a8
|
@ -16,14 +16,100 @@ class StatusTableViewCell: UITableViewCell {
|
|||
@IBOutlet weak var usernameLabel: 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) {
|
||||
displayNameLabel.text = status.account.displayName
|
||||
usernameLabel.text = "@\(status.account.acct)"
|
||||
self.status = status
|
||||
|
||||
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 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)")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue