Unify emoji replacement code
This commit is contained in:
parent
e7d9e3780e
commit
1c0291b1dd
|
@ -19,10 +19,15 @@ protocol BaseEmojiLabel: AnyObject {
|
|||
}
|
||||
|
||||
extension BaseEmojiLabel {
|
||||
func replaceEmojis(in string: String, emojis: [Emoji], identifier: String, completion: @escaping (NSAttributedString) -> Void) {
|
||||
let matches = emojiRegex.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
|
||||
func replaceEmojis(in attributedString: NSAttributedString, emojis: [Emoji], identifier: String?, completion: @escaping (_ attributedString: NSAttributedString, _ didReplaceEmojis: Bool) -> Void) {
|
||||
guard !emojis.isEmpty else {
|
||||
completion(attributedString, false)
|
||||
return
|
||||
}
|
||||
|
||||
let matches = emojiRegex.matches(in: attributedString.string, options: [], range: NSRange(location: 0, length: attributedString.length))
|
||||
guard !matches.isEmpty else {
|
||||
completion(NSAttributedString(string: string))
|
||||
completion(attributedString, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -33,8 +38,8 @@ extension BaseEmojiLabel {
|
|||
|
||||
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 = (string as NSString).substring(with: match.range(at: 1))
|
||||
guard matches.contains(where: { (match) -> Bool in
|
||||
let matchShortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
||||
return emoji.shortcode == matchShortcode
|
||||
}) else {
|
||||
continue
|
||||
|
@ -57,7 +62,7 @@ extension BaseEmojiLabel {
|
|||
}
|
||||
|
||||
guard foundEmojis else {
|
||||
completion(NSAttributedString(string: string))
|
||||
completion(attributedString, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -65,10 +70,10 @@ extension BaseEmojiLabel {
|
|||
// 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(string: string)
|
||||
let mutAttrString = NSMutableAttributedString(attributedString: attributedString)
|
||||
// replaces the emojis starting from the end of the string as to not alter the indices of preceeding emojis
|
||||
for match in matches.reversed() {
|
||||
let shortcode = (string as NSString).substring(with: match.range(at: 1))
|
||||
let shortcode = (attributedString.string as NSString).substring(with: match.range(at: 1))
|
||||
guard let emojiImage = emojiImages[shortcode] else {
|
||||
continue
|
||||
}
|
||||
|
@ -78,7 +83,11 @@ extension BaseEmojiLabel {
|
|||
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
||||
}
|
||||
|
||||
completion(mutAttrString)
|
||||
completion(mutAttrString, true)
|
||||
}
|
||||
}
|
||||
|
||||
func replaceEmojis(in string: String, emojis: [Emoji], identifier: String?, completion: @escaping (_ attributedString: NSAttributedString, _ didReplaceEmojis: Bool) -> Void) {
|
||||
replaceEmojis(in: NSAttributedString(string: string), emojis: emojis, identifier: identifier, completion: completion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import SafariServices
|
|||
|
||||
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
|
||||
|
||||
class ContentTextView: LinkTextView {
|
||||
class ContentTextView: LinkTextView, BaseEmojiLabel {
|
||||
|
||||
weak var navigationDelegate: TuskerNavigationDelegate?
|
||||
weak var overrideMastodonController: MastodonController?
|
||||
|
@ -24,6 +24,11 @@ class ContentTextView: LinkTextView {
|
|||
|
||||
private(set) var hasEmojis = false
|
||||
|
||||
var emojiIdentifier: String?
|
||||
var emojiRequests: [ImageCache.Request] = []
|
||||
var emojiFont: UIFont { defaultFont }
|
||||
var emojiTextColor: UIColor { defaultColor }
|
||||
|
||||
// The link range currently being previewed
|
||||
private var currentPreviewedLinkRange: NSRange?
|
||||
// The preview created in the previewForHighlighting method, so that we can use the same one in previewForDismissing.
|
||||
|
@ -51,45 +56,11 @@ class ContentTextView: LinkTextView {
|
|||
|
||||
// MARK: - Emojis
|
||||
func setEmojis(_ emojis: [Emoji]) {
|
||||
guard !emojis.isEmpty else {
|
||||
hasEmojis = false
|
||||
replaceEmojis(in: attributedText!, emojis: emojis, identifier: emojiIdentifier) { attributedString, didReplaceEmojis in
|
||||
guard didReplaceEmojis else {
|
||||
return
|
||||
}
|
||||
hasEmojis = true
|
||||
|
||||
let emojiImages = MultiThreadDictionary<String, UIImage>(name: "ContentTextView Emoji Images")
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
for emoji in emojis {
|
||||
group.enter()
|
||||
_ = ImageCache.emojis.get(emoji.url) { (_, image) in
|
||||
defer { group.leave() }
|
||||
guard let image = image,
|
||||
let transformedImage = ImageGrayscalifier.convertIfNecessary(url: emoji.url, image: image) else {
|
||||
return
|
||||
}
|
||||
emojiImages[emoji.shortcode] = transformedImage
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: .main) {
|
||||
let mutAttrString = NSMutableAttributedString(attributedString: self.attributedText!)
|
||||
let string = mutAttrString.string
|
||||
let matches = emojiRegex.matches(in: string, options: [], range: mutAttrString.fullRange)
|
||||
// replaces the emojis started from the end of the string as to not alter the indexes of the other emojis
|
||||
for match in matches.reversed() {
|
||||
let shortcode = (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 ?? .label)
|
||||
let attachmentStr = NSAttributedString(attachment: attachment)
|
||||
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
||||
}
|
||||
|
||||
self.attributedText = mutAttrString
|
||||
self.attributedText = attributedString
|
||||
self.setNeedsLayout()
|
||||
self.setNeedsDisplay()
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class EmojiLabel: UILabel, BaseEmojiLabel {
|
|||
emojiRequests = []
|
||||
hasEmojis = true
|
||||
|
||||
replaceEmojis(in: attributedText.string, emojis: emojis, identifier: identifier) { [weak self] (newAttributedText) in
|
||||
replaceEmojis(in: attributedText.string, emojis: emojis, identifier: identifier) { [weak self] (newAttributedText, _) in
|
||||
guard let self = self, self.emojiIdentifier == identifier else { return }
|
||||
self.attributedText = newAttributedText
|
||||
self.setNeedsLayout()
|
||||
|
|
|
@ -37,7 +37,7 @@ class MultiSourceEmojiLabel: UILabel, BaseEmojiLabel {
|
|||
recombine()
|
||||
|
||||
for (index, (string, emojis)) in pairs.enumerated() {
|
||||
self.replaceEmojis(in: string, emojis: emojis, identifier: identifier) { (attributedString) in
|
||||
self.replaceEmojis(in: string, emojis: emojis, identifier: identifier) { (attributedString, _) in
|
||||
attributedStrings[index] = attributedString
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self, self.emojiIdentifier == identifier else { return }
|
||||
|
|
|
@ -15,6 +15,7 @@ class StatusContentTextView: ContentTextView {
|
|||
|
||||
func setTextFrom(status: StatusMO) {
|
||||
statusID = status.id
|
||||
emojiIdentifier = status.id
|
||||
setTextFromHtml(status.content)
|
||||
setEmojis(status.emojis)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue