forked from shadowfacts/Tusker
95 lines
3.4 KiB
Swift
95 lines
3.4 KiB
Swift
//
|
|
// EmojiLabel.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 3/1/20.
|
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import Pachyderm
|
|
|
|
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
|
|
|
|
class EmojiLabel: UILabel {
|
|
|
|
private var emojiIdentifier: String?
|
|
private var emojiRequests: [ImageCache.Request] = []
|
|
|
|
func setEmojis(_ emojis: [Emoji], identifier: String) {
|
|
guard emojis.count > 0, let attributedText = attributedText else { return }
|
|
|
|
self.emojiIdentifier = identifier
|
|
emojiRequests.forEach { $0.cancel() }
|
|
emojiRequests = []
|
|
|
|
let matches = emojiRegex.matches(in: attributedText.string, options: [], range: attributedText.fullRange)
|
|
let emojiImages = CachedDictionary<UIImage>(name: "EmojiLabel Emoji Images")
|
|
|
|
let group = DispatchGroup()
|
|
|
|
for emoji in emojis {
|
|
// only make requests for emojis that are present in the text to avoid making unnecessary network requests
|
|
guard matches.contains(where: { (match) in
|
|
let matchShortcode = (attributedText.string as NSString).substring(with: match.range(at: 1))
|
|
return emoji.shortcode == matchShortcode
|
|
}) else {
|
|
continue
|
|
}
|
|
|
|
group.enter()
|
|
let request = ImageCache.emojis.get(emoji.url) { (data) in
|
|
defer { group.leave() }
|
|
guard let data = data, let image = UIImage(data: data) else {
|
|
return
|
|
}
|
|
emojiImages[emoji.shortcode] = image
|
|
}
|
|
if let request = request {
|
|
emojiRequests.append(request)
|
|
}
|
|
}
|
|
|
|
group.notify(queue: .main) { [weak self] in
|
|
// if e.g. the account changes before all emojis are loaded, don't bother trying to set them
|
|
guard let self = self, self.emojiIdentifier == identifier else { return }
|
|
|
|
let mutAttrString = NSMutableAttributedString(attributedString: attributedText)
|
|
// replaces the emojis starting from the end of the string as to not alter the indicies of preceeding emojis
|
|
for match in matches.reversed() {
|
|
let shortcode = (mutAttrString.string as NSString).substring(with: match.range(at: 1))
|
|
guard let emojiImage = emojiImages[shortcode] else {
|
|
continue
|
|
}
|
|
|
|
let attachment = NSTextAttachment(emojiImage: emojiImage, in: self.font, with: self.textColor)
|
|
let attachmentStr = NSAttributedString(attachment: attachment)
|
|
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
|
}
|
|
|
|
self.attributedText = mutAttrString
|
|
self.setNeedsLayout()
|
|
self.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
func removeEmojis() {
|
|
emojiIdentifier = nil
|
|
emojiRequests.forEach { $0.cancel() }
|
|
emojiRequests = []
|
|
}
|
|
|
|
}
|
|
|
|
extension EmojiLabel {
|
|
func updateForAccountDisplayName(account: Account) {
|
|
if Preferences.shared.hideCustomEmojiInUsernames {
|
|
self.text = account.displayNameWithoutCustomEmoji
|
|
self.removeEmojis()
|
|
} else {
|
|
self.text = account.displayOrUserName
|
|
self.setEmojis(account.emojis, identifier: account.id)
|
|
}
|
|
}
|
|
}
|