Add custom emojis

Closes #6
This commit is contained in:
Shadowfacts 2019-02-09 21:12:31 -05:00
parent 71bfd1513a
commit 37f6a0b4c8
Signed by untrusted user: shadowfacts
GPG Key ID: 94A5AB95422746E5
4 changed files with 68 additions and 7 deletions

View File

@ -9,17 +9,16 @@
import Foundation
public class Emoji: Decodable {
let shortcode: String
let url: URL
let staticURL: URL
// TODO: missing in pleroma
// let visibleInPicker: Bool
public let shortcode: String
public let url: URL
public let staticURL: URL
public let visibleInPicker: Bool
private enum CodingKeys: String, CodingKey {
case shortcode
case url
case staticURL = "static_url"
// case visibleInPicker = "visible_in_picker"
case visibleInPicker = "visible_in_picker"
}
}

View File

@ -14,6 +14,7 @@ class ImageCache {
static let avatars = ImageCache(name: "Avatars", memoryExpiry: .seconds(60 * 60), diskExpiry: .seconds(60 * 60 * 24))
static let headers = ImageCache(name: "Headers", memoryExpiry: .seconds(60 * 60), diskExpiry: .seconds(60 * 60 * 24))
static let attachments = ImageCache(name: "Attachments", memoryExpiry: .seconds(60 * 2))
static let emojis = ImageCache(name: "Emojis", memoryExpiry: .seconds(60 * 5), diskExpiry: .seconds(60 * 60))
let cache: Cache<Data>

View File

@ -8,14 +8,74 @@
import UIKit
import SafariServices
import TTTAttributedLabel
import Pachyderm
import SwiftSoup
class ContentLabel: LinkLabel {
private static let emojiRegex = try! NSRegularExpression(pattern: ":(\\w+):", options: [])
var navigationDelegate: TuskerNavigationDelegate?
// MARK: - Emojis
func setEmojis(_ emojis: [Emoji]) {
guard !emojis.isEmpty else { return }
let group = DispatchGroup()
let mutAttrString = NSMutableAttributedString(attributedString: self.attributedText!)
let string = mutAttrString.string
let matches = ContentLabel.emojiRegex.matches(in: string, options: [], range: NSRange(location: 0, length: mutAttrString.length))
for match in matches.reversed() {
let shortcode = (string as NSString).substring(with: match.range(at: 1))
guard let emoji = emojis.first(where: { $0.shortcode == shortcode }) else {
continue
}
group.enter()
ImageCache.emojis.get(emoji.url) { (data) in
guard let data = data, let image = UIImage(data: data) else {
group.leave()
return
}
DispatchQueue.main.async {
let attachment = self.createEmojiTextAttachment(image: image, index: match.range.location)
mutAttrString.replaceCharacters(in: match.range, with: NSAttributedString(attachment: attachment))
group.leave()
}
}
}
group.notify(queue: .main) {
self.attributedText = mutAttrString
self.setNeedsLayout()
self.setNeedsDisplay()
}
}
// Based on https://github.com/ReticentJohn/Amaroq/blob/7c5b7088eb9fd1611dcb0f47d43bf8df093e142c/DireFloof/InlineImageHelpers.m
func createEmojiTextAttachment(image: UIImage, index: Int) -> NSTextAttachment {
let font = self.font!
let adjustedCapHeight = font.capHeight - 1
var imageSizeMatchingFontSize = CGSize(width: image.size.width * (adjustedCapHeight / image.size.height), height: adjustedCapHeight)
let defaultScale: CGFloat = 1.4
imageSizeMatchingFontSize = CGSize(width: imageSizeMatchingFontSize.width * defaultScale, height: imageSizeMatchingFontSize.height * defaultScale)
let textColor = self.textColor!
UIGraphicsBeginImageContextWithOptions(imageSizeMatchingFontSize, false, 0.0)
textColor.set()
image.draw(in: CGRect(origin: .zero, size: imageSizeMatchingFontSize))
let attachmentImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let attachment = NSTextAttachment()
attachment.image = attachmentImage
return attachment
}
// MARK: - HTML Parsing
func setTextFromHtml(_ html: String) {
let doc = try! SwiftSoup.parse(html)

View File

@ -16,6 +16,7 @@ class StatusContentLabel: ContentLabel {
guard let statusID = statusID else { return }
guard let status = MastodonCache.status(for: statusID) else { fatalError("Can't set StatusContentLabel text without cached status \(statusID)") }
setTextFromHtml(status.content)
setEmojis(status.emojis)
}
}