// // AccountDisplayNameLabel.swift // Tusker // // Created by Shadowfacts on 9/7/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import SwiftUI import Pachyderm private let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: []) struct AccountDisplayNameLabel: View { let account: Account let fontSize: Int @State var text: Text @State var emojiRequests = [ImageCache.Request]() init(account: Account, fontSize: Int) { self.account = account self.fontSize = fontSize self._text = State(initialValue: Text(verbatim: account.displayName)) } var body: some View { if #available(iOS 14.0, *) { text .font(.system(size: CGFloat(fontSize), weight: .semibold)) .onAppear(perform: self.loadEmojis) } else { text .font(.system(size: CGFloat(fontSize), weight: .semibold)) } } // embedding Image inside Text is only available on iOS 14 @available(iOS 14.0, *) private func loadEmojis() { let fullRange = NSRange(account.displayName.startIndex..., in: account.displayName) let matches = emojiRegex.matches(in: account.displayName, options: [], range: fullRange) guard !matches.isEmpty else { return } let emojiImages = CachedDictionary(name: "AcccountDisplayNameLabel Emoji Images") let group = DispatchGroup() for emoji in account.emojis { guard matches.contains(where: { (match) in let matchShortcode = (account.displayName 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 } let size = CGSize(width: fontSize, height: fontSize) let renderer = UIGraphicsImageRenderer(size: size) let resized = renderer.image { (ctx) in image.draw(in: CGRect(origin: .zero, size: size)) } emojiImages[emoji.shortcode] = Image(uiImage: resized) } if let request = request { emojiRequests.append(request) } } group.notify(queue: .main) { var text: Text? var endIndex = account.displayName.utf16.count // iterate backwards as to not alter the indices of earlier matches for match in matches.reversed() { let shortcode = (account.displayName as NSString).substring(with: match.range(at: 1)) guard let image = emojiImages[shortcode] else { continue } let afterCurrentMatch = (account.displayName as NSString).substring(with: NSRange(location: match.range.upperBound, length: endIndex - match.range.upperBound)) if let subsequent = text { text = Text(image) + Text(verbatim: afterCurrentMatch) + subsequent } else { text = Text(image) + Text(verbatim: afterCurrentMatch) } endIndex = match.range.lowerBound } let beforeLastMatch = (account.displayName as NSString).substring(to: endIndex) if let text = text { self.text = Text(verbatim: beforeLastMatch) + text } else { self.text = Text(verbatim: beforeLastMatch) } } } } //struct AccountDisplayNameLabel_Previews: PreviewProvider { // static var previews: some View { // AccountDisplayNameLabel() // } //}