85 lines
3.2 KiB
Swift
85 lines
3.2 KiB
Swift
//
|
|
// BaseEmojiLabel.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 10/18/20.
|
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
import Pachyderm
|
|
|
|
private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
|
|
|
|
protocol BaseEmojiLabel: AnyObject {
|
|
var emojiIdentifier: String? { get set }
|
|
var emojiRequests: [ImageCache.Request] { get set }
|
|
var emojiFont: UIFont { get }
|
|
var emojiTextColor: UIColor { get }
|
|
}
|
|
|
|
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))
|
|
guard !matches.isEmpty else {
|
|
completion(NSAttributedString(string: string))
|
|
return
|
|
}
|
|
|
|
let emojiImages = MultiThreadDictionary<String, UIImage>(name: "BaseEmojiLabel Emoji Images")
|
|
var foundEmojis = false
|
|
|
|
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 = (string as NSString).substring(with: match.range(at: 1))
|
|
return emoji.shortcode == matchShortcode
|
|
}) else {
|
|
continue
|
|
}
|
|
|
|
foundEmojis = true
|
|
|
|
group.enter()
|
|
let request = 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
|
|
}
|
|
if let request = request {
|
|
emojiRequests.append(request)
|
|
}
|
|
}
|
|
|
|
guard foundEmojis else {
|
|
completion(NSAttributedString(string: string))
|
|
return
|
|
}
|
|
|
|
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(string: string)
|
|
// 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))
|
|
guard let emojiImage = emojiImages[shortcode] else {
|
|
continue
|
|
}
|
|
|
|
let attachment = NSTextAttachment(emojiImage: emojiImage, in: self.emojiFont, with: self.emojiTextColor)
|
|
let attachmentStr = NSAttributedString(attachment: attachment)
|
|
mutAttrString.replaceCharacters(in: match.range, with: attachmentStr)
|
|
}
|
|
|
|
completion(mutAttrString)
|
|
}
|
|
}
|
|
}
|