diff --git a/Emojione/Emojione/Client.swift b/Emojione/Emojione/Client.swift index 1454970..2068042 100644 --- a/Emojione/Emojione/Client.swift +++ b/Emojione/Emojione/Client.swift @@ -52,20 +52,20 @@ public class Client: ClientInterface { return unicodeToImage(string: result, font: font) } - + /// First pass changes unicode characters into emoji markup. /// Second pass changes any shortnames into emoji markup. /// Callback when emoji images are downloaded. - + /** First pass changes unicode characters into emoji markup. Second pass changes any shortnames into emoji markup. Callback when emoji images are downloaded. */ - + public func toImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) { let result = shortnameToUnicode(string: string) - + unicodeToImageAsync(string: result, font: font, callback: callback) } @@ -137,13 +137,13 @@ public class Client: ClientInterface { let unicodeString = shortnameToUnicode(string: string) return unicodeToImage(string: unicodeString, font: font) } - + /// This will output image markup from shortname input with asynchronous callback. - + /** This will output image markup from shortname input with asynchronous callback. */ - + public func shortnameToImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) { let unicodeString = shortnameToUnicode(string: string) unicodeToImageAsync(string: unicodeString, font: font, callback: callback) @@ -187,21 +187,21 @@ public class Client: ClientInterface { return getEmojiImage(filename: filename) } } - + /// This will output image markup from unicode input with asynchronous callback. - + /** This will output image markup from unicode input with asynchronous callback. */ - + public func unicodeToImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) { var result = string - + if ascii { result = asciiToShortname(string: result) result = shortnameToUnicode(string: result) } - + regexImageReplaceAsync(regexString: unicodeRegEx, string: result, font: font, callback: callback) } @@ -320,7 +320,7 @@ public class Client: ClientInterface { /// font - Used to determine line height to properly size the image /// callback(NSAttributedString) -> Void - A callback function /// that passes back the attributed string when replacements are complete. - + /** Replaces matched regular expression with an UIImage asynchronously. regexString - Regular expression @@ -329,63 +329,63 @@ public class Client: ClientInterface { callback(NSAttributedString) -> Void - A callback function that passes back the attributed string when replacements are complete. */ - + private func regexImageReplaceAsync(regexString: String, string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) { let mutableString = NSMutableAttributedString(string: string) var offset = 0 - + let matches = regexMatches(regexString: regexString, string: string) - + let matchesWithFilenames = matches.map { ($0, $1, getFilename(emoji: $0)) } - + let filenames = matchesWithFilenames.map { $0.2 }.filter { $0 != nil }.map { $0! } - + downloadImagesAsync(filenames: filenames) { [weak self] images in guard let strongSelf = self else { return } - + for (_, match, filename) in matchesWithFilenames { var resultRange = match.range resultRange.location += offset - + guard let filename = filename, let image = images[filename] else { continue } - + let attrStringWithImage = strongSelf.buildAttributedStringWithTextAttachment(image: image, font: font) - + mutableString.replaceCharacters(in: resultRange, with: attrStringWithImage) - + offset += attrStringWithImage.length - resultRange.length } - + callback(mutableString as NSAttributedString) } } - + /// Gets associated Emojione filename from unicode emoji. - + /** Gets associated Emojione filename from unicode emoji. */ - + private func getFilename(emoji: String) -> String? { let hexString = convertToHexString(string: emoji) - + guard let shortcode = ruleset.getUnicodeReplace()[hexString] ?? (greedyMatch ? ruleset.getUnicodeReplaceGreedy()[hexString] : nil) else { return nil } - + guard let filename = ruleset.getShortcodeReplace()[shortcode]?.1 else { return nil } - + return filename } - + /// Downloads a list of filenames from Emojione servers asynchronously. - + /** Downloads a list of filenames from Emojione servers asynchronously. */ - + private func downloadImagesAsync(filenames: [String], callback: @escaping ([String: UIImage]) -> Void) { var result: [String: UIImage] = [:] let group = DispatchGroup() - + for filename in filenames { group.enter() getEmojiImageAsync(filename: filename) { (image) in @@ -394,12 +394,12 @@ public class Client: ClientInterface { group.leave() } } - + group.notify(queue: .main) { callback(result) } } - + /// Builds an image attachment for a NSAttributedString. /** @@ -414,16 +414,16 @@ public class Client: ClientInterface { } /// Builds URL object from Emojione filename. - + /** Builds URL object from Emojione filename. */ - + private func getEmojiOneUrl(filename: String) -> URL? { let urlString = "\(imagePathPNG)/\(emojiVersion)/png/\(emojiSize.rawValue)/\(filename).png" return URL(string: urlString) } - + /// Gets emoji image from Emojione's CDN. /// Returns nil if unable to download image. @@ -442,16 +442,16 @@ public class Client: ClientInterface { /// Gets emoji image from Emojione's CDN asynchronously. /// Returns nil if unable to download image. - + /** Gets emoji image from Emojione's CDN asynchronously. Returns nil if unable to download image. */ - + private func getEmojiImageAsync(filename: String, callback: @escaping (UIImage?) -> Void) { guard let url = getEmojiOneUrl(filename: filename) else { callback(nil); return } - - URLSession.shared.dataTask(with: url) { (data, response, error) -> Void in + + URLSession.shared.dataTask(with: url) { (data, _, _) -> Void in if let imageData = data, let image = UIImage(data: imageData) { callback(image) } else { diff --git a/Emojione/Emojione/ClientInterface.swift b/Emojione/Emojione/ClientInterface.swift index fa3f124..2670d27 100644 --- a/Emojione/Emojione/ClientInterface.swift +++ b/Emojione/Emojione/ClientInterface.swift @@ -19,17 +19,17 @@ public protocol ClientInterface { */ func toImage(string: String, font: UIFont) -> NSAttributedString - + /// First pass changes unicode characters into emoji markup. /// Second pass changes any shortnames into emoji markup. /// Callback when emoji images are downloaded. - + /** First pass changes unicode characters into emoji markup. Second pass changes any shortnames into emoji markup. Callback when emoji images are downloaded. */ - + func toImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) /// Uses toShort to transform all unicode into a standard shortname @@ -77,13 +77,13 @@ public protocol ClientInterface { func shortnameToImage(string: String, font: UIFont) -> NSAttributedString /// This will output image markup from shortname input with asynchronous callback. - + /** This will output image markup from shortname input with asynchronous callback. */ - + func shortnameToImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) - + /// This will return the shortname from unicode input. /** @@ -99,12 +99,12 @@ public protocol ClientInterface { */ func unicodeToImage(string: String, font: UIFont) -> NSAttributedString - + /// This will output image markup from unicode input with asynchronous callback. - + /** This will output image markup from unicode input with asynchronous callback. */ - + func unicodeToImageAsync(string: String, font: UIFont, callback: @escaping (NSAttributedString) -> Void) } diff --git a/Emojione/EmojioneTests/ClientTests.swift b/Emojione/EmojioneTests/ClientTests.swift index c786047..88936dc 100644 --- a/Emojione/EmojioneTests/ClientTests.swift +++ b/Emojione/EmojioneTests/ClientTests.swift @@ -24,7 +24,7 @@ class ClientTests: XCTestCase { super.tearDown() } - + private func enableAscii() { let asciiEnabledClient = Client() asciiEnabledClient.ascii = true @@ -46,12 +46,12 @@ class ClientTests: XCTestCase { XCTAssertEqual("🐢Hello :thisisnotavalidshortname:πŸ˜‚", result) } - + func testShortnameToUnicode_WhenAsciiIsDisabled_ShouldIgnoreAsciiSmileys() { let shortNameString = ":dog: Hello :) =) :\")" - + let result = client.shortnameToUnicode(string: shortNameString) - + XCTAssertEqual("🐢 Hello :) =) :\")", result) } @@ -85,53 +85,53 @@ class ClientTests: XCTestCase { let emojiString = "Hello 🐢 πŸš‹ πŸ˜‚ ✍🏻" let result = client.unicodeToImage(string: emojiString, font: UIFont.systemFont(ofSize: 14)) - + XCTAssertEqual(13, result.length) XCTAssertTrue(result.containsAttachments(in: NSRange(location: 0, length: result.length))) } - + func testUnicodeToImage_WhenAsciiIsNotEnabled_ShouldIgnoreSmileys() { let emojiString = "Hello :)" - + let result = client.unicodeToImage(string: emojiString, font: UIFont.systemFont(ofSize: 14)) - + XCTAssertEqual(8, result.length) XCTAssertFalse(result.containsAttachments(in: NSRange(location: 0, length: result.length))) } - + func testUnicodeToImage_WhenAsciiIsEnabled_ShouldReplaceSmileysWithImages() { enableAscii() - + let emojiString = "Hello :)" - + let result = client.unicodeToImage(string: emojiString, font: UIFont.systemFont(ofSize: 14)) - + XCTAssertEqual(7, result.length) XCTAssertTrue(result.containsAttachments(in: NSRange(location: 0, length: result.length))) } - + func testToImage_WhenAsciiIsEnabled_ShouldReplaceAsciiAndEmojisWithImages() { enableAscii() - + let emojiString = "Hello 🐢 πŸš‹ πŸ˜‚ ✍🏻 :) =)" - + let result = client.unicodeToImage(string: emojiString, font: UIFont.systemFont(ofSize: 14)) - + XCTAssertEqual(17, result.length) XCTAssertTrue(result.containsAttachments(in: NSRange(location: 0, length: result.length))) } - + func testToImageAsync_ShouldReplaceEmojiWithImages() { let expectation = XCTestExpectation(description: "testToImageAsync_ShouldReplaceEmojiWithImages") - + let emojiString = "Hello 🐢 πŸš‹ πŸ˜‚ ✍🏻" - + client.unicodeToImageAsync(string: emojiString, font: UIFont.systemFont(ofSize: 14)) { result in XCTAssertEqual(13, result.length) XCTAssertTrue(result.containsAttachments(in: NSRange(location: 0, length: result.length))) expectation.fulfill() } - + self.wait(for: [expectation], timeout: 5.0) } } diff --git a/EmojioneExamples/EmojioneExamples/View Controllers/ShortnameToImageViewController.swift b/EmojioneExamples/EmojioneExamples/View Controllers/ShortnameToImageViewController.swift index 08aa9fd..7c487d8 100644 --- a/EmojioneExamples/EmojioneExamples/View Controllers/ShortnameToImageViewController.swift +++ b/EmojioneExamples/EmojioneExamples/View Controllers/ShortnameToImageViewController.swift @@ -13,7 +13,7 @@ class ShortnameToImageViewController: UIViewController { @IBOutlet weak var textField: UITextField! @IBOutlet weak var label: UILabel! - + var asynchronous: Bool = true let client: ClientInterface = Client() diff --git a/EmojioneExamples/EmojioneExamples/View Controllers/ToImageViewController.swift b/EmojioneExamples/EmojioneExamples/View Controllers/ToImageViewController.swift index d363ad6..e173631 100644 --- a/EmojioneExamples/EmojioneExamples/View Controllers/ToImageViewController.swift +++ b/EmojioneExamples/EmojioneExamples/View Controllers/ToImageViewController.swift @@ -15,7 +15,7 @@ class ToImageViewController: UIViewController { @IBOutlet weak var label: UILabel! var asynchronous: Bool = true - + let client: ClientInterface = Client() override func viewDidLoad() { diff --git a/EmojioneExamples/EmojioneExamples/View Controllers/UnicodeToImageViewController.swift b/EmojioneExamples/EmojioneExamples/View Controllers/UnicodeToImageViewController.swift index 09ae11b..206d45b 100644 --- a/EmojioneExamples/EmojioneExamples/View Controllers/UnicodeToImageViewController.swift +++ b/EmojioneExamples/EmojioneExamples/View Controllers/UnicodeToImageViewController.swift @@ -15,7 +15,7 @@ class UnicodeToImageViewController: UIViewController { @IBOutlet weak var label: UILabel! var asynchronous: Bool = true - + let client: ClientInterface = Client() override func viewDidLoad() {