diff --git a/Library/GiphyImageSet.swift b/Library/GiphyImageSet.swift index 925652a..1f9c3fb 100644 --- a/Library/GiphyImageSet.swift +++ b/Library/GiphyImageSet.swift @@ -17,45 +17,15 @@ public struct GiphyImageSet: Mappable { public fileprivate(set) var height: Int = 0 - public fileprivate(set) var size: UInt64 = 0 + public fileprivate(set) var size: Int = 0 public fileprivate(set) var mp4URL: URL? - public fileprivate(set) var mp4Size: UInt64 = 0 + public fileprivate(set) var mp4Size: Int = 0 public fileprivate(set) var webpURL: URL? - public fileprivate(set) var webpSize: UInt64 = 0 - - fileprivate var widthString: String = "" { - didSet { - width = Int(widthString) ?? 0 - } - } - - fileprivate var heightString: String = "" { - didSet { - height = Int(heightString) ?? 0 - } - } - - fileprivate var sizeString: String = "" { - didSet { - size = UInt64(sizeString) ?? 0 - } - } - - fileprivate var mp4SizeString: String = "" { - didSet { - mp4Size = UInt64(mp4SizeString) ?? 0 - } - } - - fileprivate var webpSizeString: String = "" { - didSet { - webpSize = UInt64(webpSizeString) ?? 0 - } - } + public fileprivate(set) var webpSize: Int = 0 public init?(map: Map) { @@ -65,12 +35,12 @@ public struct GiphyImageSet: Mappable { mutating public func mapping(map: Map) { url <- (map["url"], URLTransform()) - widthString <- map["width"] - heightString <- map["height"] - sizeString <- map["size"] + width <- (map["width"], stringToIntTransform) + height <- (map["height"], stringToIntTransform) + size <- (map["size"], stringToIntTransform) mp4URL <- (map["mp4"], URLTransform()) - mp4SizeString <- map["mp4_size"] + mp4Size <- (map["mp4_size"], stringToIntTransform) webpURL <- (map["webp"], URLTransform()) - webpSizeString <- map["webp_size"] + webpSize <- (map["webp_size"], stringToIntTransform) } } diff --git a/Library/GiphyMultipleGIFResponse.swift b/Library/GiphyMultipleGIFResponse.swift index 36260c4..d2eb761 100644 --- a/Library/GiphyMultipleGIFResponse.swift +++ b/Library/GiphyMultipleGIFResponse.swift @@ -29,7 +29,7 @@ public struct GiphyMultipleGIFResponse: Mappable { meta <- map["meta"] } - func gifsSmallerThan(sizeInBytes: UInt64, forWidth: CGFloat) -> [GiphyItem] + func gifsSmallerThan(sizeInBytes: Int, forWidth: CGFloat) -> [GiphyItem] { return gifs.filter({ let size = $0.imageSetClosestTo(width: forWidth, animated: true)?.size ?? 0 diff --git a/Library/GiphySimpleItem.swift b/Library/GiphySimpleItem.swift new file mode 100644 index 0000000..0eb8917 --- /dev/null +++ b/Library/GiphySimpleItem.swift @@ -0,0 +1,89 @@ +// +// GiphySimpleItem.swift +// Pods +// +// Created by Brendan Lee on 3/15/17. +// +// + +import Foundation +import ObjectMapper + +public struct GiphySimpleItem: Mappable { + + public fileprivate(set) var type: String = "gif" + + public fileprivate(set) var identifier: String = "" + + public fileprivate(set) var url: URL? + + // Any of these could be nil + public fileprivate(set) var imageOriginalURL: URL? + public fileprivate(set) var imageURL: URL? + public fileprivate(set) var imagemp4URL: URL? + public fileprivate(set) var imageFrameCount: Int = 0 + public fileprivate(set) var imageWidth: Int = 0 + public fileprivate(set) var imageHeight: Int = 0 + + public fileprivate(set) var fixedHeightDownsampledURL: URL? + public fileprivate(set) var fixedHeightDownsampledWidth: Int = 0 + public fileprivate(set) var fixedHeightDownsampledHeight: Int = 0 + + public fileprivate(set) var fixedWidthDownsampledURL: URL? + public fileprivate(set) var fixedWidthDownsampledWidth: Int = 0 + public fileprivate(set) var fixedWidthDownsampledHeight: Int = 0 + + public fileprivate(set) var fixedHeightSmallURL: URL? + public fileprivate(set) var fixedHeightSmallStillURL: URL? + public fileprivate(set) var fixedHeightSmallWidth: Int = 0 + public fileprivate(set) var fixedHeightSmallHeight: Int = 0 + + public fileprivate(set) var fixedWidthSmallURL: URL? + public fileprivate(set) var fixedWidthSmallStillURL: URL? + public fileprivate(set) var fixedWidthSmallWidth: Int = 0 + public fileprivate(set) var fixedWidthSmallHeight: Int = 0 + + public init?(map: Map) + { + + } + + public mutating func mapping(map: Map) { + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" + dateFormatter.timeZone = TimeZone(abbreviation: "UTC") + + let dateTransformer = DateFormatterTransform(dateFormatter: dateFormatter) + + type <- map["type"] + identifier <- map["id"] + url <- (map["url"], URLTransform()) + + imageOriginalURL <- (map["image_original_url"], URLTransform()) + imageURL <- (map["image_url"], URLTransform()) + imagemp4URL <- (map["image_mp4_url"], URLTransform()) + imageFrameCount <- (map["image_frames"], stringToIntTransform) + imageWidth <- (map["image_width"], stringToIntTransform) + imageHeight <- (map["image_height"], stringToIntTransform) + + fixedHeightDownsampledURL <- (map["fixed_height_downsampled_url"], URLTransform()) + fixedHeightDownsampledWidth <- (map["fixed_height_downsampled_width"], stringToIntTransform) + fixedHeightDownsampledHeight <- (map["fixed_height_downsampled_height"], stringToIntTransform) + + fixedWidthDownsampledURL <- (map["fixed_width_downsampled_url"], URLTransform()) + fixedWidthDownsampledHeight <- (map["fixed_width_downsampled_height"], stringToIntTransform) + fixedWidthDownsampledWidth <- (map["fixed_width_downsampled_width"], stringToIntTransform) + + fixedHeightSmallURL <- (map["fixed_height_small_url"], URLTransform()) + fixedHeightSmallStillURL <- (map["fixed_height_small_still_url"], URLTransform()) + fixedHeightSmallWidth <- (map["fixed_height_small_width"], stringToIntTransform) + fixedHeightSmallHeight <- (map["fixed_height_small_height"], stringToIntTransform) + + fixedWidthSmallURL <- (map["fixed_width_small_url"], URLTransform()) + fixedWidthSmallStillURL <- (map["fixed_width_small_still_url"], URLTransform()) + fixedWidthSmallWidth <- (map["fixed_width_small_width"], stringToIntTransform) + fixedWidthSmallHeight <- (map["fixed_width_small_height"], stringToIntTransform) + } + +} diff --git a/Library/GiphySimpleSingleGIFResponse.swift b/Library/GiphySimpleSingleGIFResponse.swift new file mode 100644 index 0000000..3e9cde4 --- /dev/null +++ b/Library/GiphySimpleSingleGIFResponse.swift @@ -0,0 +1,28 @@ +// +// GiphySimpleSingleGIFResponse.swift +// Pods +// +// Created by Brendan Lee on 3/15/17. +// +// + +import Foundation +import ObjectMapper + +public struct GiphySimpleSingleGIFResponse: Mappable { + + public fileprivate(set) var gif: GiphySimpleItem? + + public fileprivate(set) var meta: GiphyMeta? + + public init?(map: Map) + { + + } + + mutating public func mapping(map: Map) { + + gif <- map["data"] + meta <- map["meta"] + } +} diff --git a/Library/GiphySingleGIFResponse.swift b/Library/GiphySingleGIFResponse.swift new file mode 100644 index 0000000..3b0b8aa --- /dev/null +++ b/Library/GiphySingleGIFResponse.swift @@ -0,0 +1,28 @@ +// +// GiphySingleGIFResponse.swift +// Pods +// +// Created by Brendan Lee on 3/15/17. +// +// + +import Foundation +import ObjectMapper + +public struct GiphySingleGIFResponse: Mappable { + + public fileprivate(set) var gif: GiphyItem? + + public fileprivate(set) var meta: GiphyMeta? + + public init?(map: Map) + { + + } + + mutating public func mapping(map: Map) { + + gif <- map["data"] + meta <- map["meta"] + } +} diff --git a/Library/GiphyUser.swift b/Library/GiphyUser.swift new file mode 100644 index 0000000..ae0c249 --- /dev/null +++ b/Library/GiphyUser.swift @@ -0,0 +1,35 @@ +// +// GiphyUser.swift +// Pods +// +// Created by Brendan Lee on 3/15/17. +// +// + +import Foundation +import ObjectMapper + +public struct GiphyUser: Mappable { + + public fileprivate(set) var avatarURL: URL? + public fileprivate(set) var bannerURL: URL? + public fileprivate(set) var profileURL: URL? + public fileprivate(set) var username: String = "" + public fileprivate(set) var displayName: String = "" + public fileprivate(set) var twitterHandle: String? + + public init?(map: Map) + { + + } + + mutating public func mapping(map: Map) { + + avatarURL <- (map["avatar_url"], URLTransform()) + bannerURL <- (map["banner_url"], URLTransform()) + profileURL <- (map["profile_url"], URLTransform()) + username <- map["username"] + displayName <- map["display_name"] + twitterHandle <- map["twitter"] + } +} diff --git a/Library/ParsingTransforms.swift b/Library/ParsingTransforms.swift new file mode 100644 index 0000000..345b973 --- /dev/null +++ b/Library/ParsingTransforms.swift @@ -0,0 +1,21 @@ +// +// ParsingTransforms.swift +// Pods +// +// Created by Brendan Lee on 3/15/17. +// +// + +import Foundation +import ObjectMapper + +let stringToIntTransform = TransformOf(fromJSON: { (value: String?) -> Int in + + return Int(value ?? "0") ?? 0 +}, toJSON: { (value: Int?) -> String? in + // transform value from Int? to String? + if let value = value { + return String(value) + } + return nil +}) diff --git a/Library/SwiftyGiphyAPI.swift b/Library/SwiftyGiphyAPI.swift index c323065..c6801a8 100644 --- a/Library/SwiftyGiphyAPI.swift +++ b/Library/SwiftyGiphyAPI.swift @@ -12,12 +12,16 @@ import ObjectMapper public let kGiphyNetworkingErrorDomain = "kGiphyNetworkingErrorDomain" public typealias GiphyMultipleGIFResponseBlock = (_ error: NSError?, _ response: GiphyMultipleGIFResponse?) -> Void +public typealias GiphySingleGIFResponseBlock = (_ error: NSError?, _ response: GiphySingleGIFResponse?) -> Void +public typealias GiphySimpleSingleGIFResponseBlock = (_ error: NSError?, _ response: GiphySimpleSingleGIFResponse?) -> Void + fileprivate typealias GiphyAPIResponseBlock = (_ error: NSError?, _ response: [String : AnyObject]?) -> Void fileprivate let kGiphyUnknownResponseError = NSLocalizedString("The server returned an unknown response.", comment: "The error message shown when the server produces something unintelligible.") fileprivate let kGiphyDefaultAPIBase = URL(string: "https://api.giphy.com/v1/gifs/")! +fileprivate let kGiphyDefaultStickerAPIBase = URL(string: "https://api.giphy.com/v1/stickers/")! public enum SwiftyGiphyAPIContentRating: String { @@ -57,132 +61,25 @@ public class SwiftyGiphyAPI { /// - Changing this URL will disable the requirement for an API key to be set on SwiftyGiphyAPI. You can still set one if you want, but we allow it to be nil in case you want the API key to live on your server. public var giphyAPIBase: URL = kGiphyDefaultAPIBase + /// This can be overriden to use a custom API base url, in the scenario that you want requests to pass through your own server. + /// - Note: + /// - Changing this URL will disable the requirement for an API key to be set on SwiftyGiphyAPI. You can still set one if you want, but we allow it to be nil in case you want the API key to live on your server. + public var giphyStickerAPIBase: URL = kGiphyDefaultStickerAPIBase + fileprivate var isUsingDefaultAPIBase: Bool { get { return giphyAPIBase == kGiphyDefaultAPIBase } } - /// This is private, you should use the shared singleton instead of creating your own instance. - fileprivate init() { - - } - - /// Get the currently trending gifs from Giphy - /// - /// - Parameters: - /// - limit: The limit of results to fetch - /// - rating: The max rating for the gifs - /// - offset: The paging offset - /// - completion: The completion block to call when done - public func getTrending(limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) - { - guard apiKey != nil || !isUsingDefaultAPIBase else { - print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") - - completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) - return - } - - var params = [String : Any]() - - if let validAPIKey = apiKey - { - params["api_key"] = validAPIKey - } - - params["limit"] = limit - params["rating"] = rating.rawValue - - if let currentOffset = offset - { - params["offset"] = currentOffset - } - - let request = createRequest(relativePath: "trending", method: "GET", params: params) - - send(request: request) { [unowned self] (error, response) in - - guard error == nil, response != nil else { - DispatchQueue.main.async { - - completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) - } - - return - } - - // We have gifs! - guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { - - completion?(self.networkError(description: kGiphyUnknownResponseError), nil) - return - } - - DispatchQueue.main.async { - completion?(nil, gifs) - } + fileprivate var isUsingDefaultStickerAPIBase: Bool { + get { + return giphyStickerAPIBase == kGiphyDefaultStickerAPIBase } } - /// Get the results for a search from Giphy - /// - /// - Parameters: - /// - searchTerm: The phrase to use to search Giphy - /// - limit: The limit of results to fetch - /// - rating: The max rating for the gifs - /// - offset: The paging offset - /// - completion: The completion block to call when done - public func getSearch(searchTerm: String, limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) - { - guard apiKey != nil || !isUsingDefaultAPIBase else { - print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") - - completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) - return - } - - var params = [String : Any]() - - if let validAPIKey = apiKey - { - params["api_key"] = validAPIKey - } - - params["q"] = searchTerm - params["limit"] = limit - params["rating"] = rating.rawValue - - if let currentOffset = offset - { - params["offset"] = currentOffset - } - - let request = createRequest(relativePath: "search", method: "GET", params: params) - - send(request: request) { [unowned self] (error, response) in - - guard error == nil, response != nil else { - DispatchQueue.main.async { - - completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) - } - - return - } - - // We have gifs! - guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { - - completion?(self.networkError(description: kGiphyUnknownResponseError), nil) - return - } - - DispatchQueue.main.async { - completion?(nil, gifs) - } - } - } + /// This is private, you should use the shared singleton instead of creating your own instance. + fileprivate init() { } // MARK: Networking Utilities @@ -280,9 +177,9 @@ public class SwiftyGiphyAPI { - returns: The generated request, or nil if a JSON error occurred. */ - fileprivate func createRequest(relativePath:String, method:String, params: [String : Any]?) -> URLRequest + fileprivate func createRequest(baseURL: URL, relativePath:String, method:String, params: [String : Any]?) -> URLRequest { - var request = URLRequest(url: URL(string: relativePath, relativeTo: giphyAPIBase)!) + var request = URLRequest(url: URL(string: relativePath, relativeTo: baseURL)!) request.httpMethod = method @@ -345,3 +242,507 @@ public class SwiftyGiphyAPI { } } } + +// MARK: - GIF Support +public extension SwiftyGiphyAPI { + + /// Get the currently trending gifs from Giphy + /// + /// - Parameters: + /// - limit: The limit of results to fetch + /// - rating: The max rating for the gifs + /// - offset: The paging offset + /// - completion: The completion block to call when done + public func getTrending(limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["limit"] = limit + params["rating"] = rating.rawValue + + if let currentOffset = offset + { + params["offset"] = currentOffset + } + + let request = createRequest(baseURL: giphyAPIBase, relativePath: "trending", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gifs! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Get the results for a search from Giphy + /// + /// - Parameters: + /// - searchTerm: The phrase to use to search Giphy + /// - limit: The limit of results to fetch + /// - rating: The max rating for the gifs + /// - offset: The paging offset + /// - completion: The completion block to call when done + public func getSearch(searchTerm: String, limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["q"] = searchTerm + params["limit"] = limit + params["rating"] = rating.rawValue + + if let currentOffset = offset + { + params["offset"] = currentOffset + } + + let request = createRequest(baseURL: giphyAPIBase, relativePath: "search", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gifs! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Translate a search term into an image. + /// + /// - Parameters: + /// - searchTerm: The search term to translate + /// - rating: The max rating for the image (optional, defaults to pg13) + /// - languageCode: The language code (optional) + /// - completion: The completion block to call when done + public func getTranslation(searchTerm: String, rating: SwiftyGiphyAPIContentRating = .pg13, languageCode: String? = nil, completion: GiphySingleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["s"] = searchTerm + params["rating"] = rating.rawValue + + if let language = languageCode + { + params["lang"] = language + } + + let request = createRequest(baseURL: giphyAPIBase, relativePath: "translate", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gif! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Get a random gif + /// + /// - Parameters: + /// - tag: The tag to limit the randomness with + /// - rating: The max rating to limit the image to + /// - completion: The completion block to call when done + public func getRandom(tag: String, rating: SwiftyGiphyAPIContentRating = .pg13, completion: GiphySimpleSingleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["tag"] = tag + params["rating"] = rating.rawValue + + let request = createRequest(baseURL: giphyAPIBase, relativePath: "random", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gif! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Get a gif with a specific Giphy ID + /// + /// - Parameters: + /// - identifier: The identifier of the gif + /// - completion: The completion block to call when done. + public func getGIFById(identifier: String, completion: GiphySingleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params: [String : Any]? + + if let validAPIKey = apiKey + { + params = [String : Any]() + params?["api_key"] = validAPIKey + } + + let request = createRequest(baseURL: giphyAPIBase, relativePath: identifier, method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gif! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } +} + +// MARK: - Sticker support +public extension SwiftyGiphyAPI { + + /// Get the currently trending stickers from Giphy + /// + /// - Parameters: + /// - limit: The limit of results to fetch + /// - rating: The max rating for the stickers + /// - offset: The paging offset + /// - completion: The completion block to call when done + public func getTrendingStickers(limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultStickerAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["limit"] = limit + params["rating"] = rating.rawValue + + if let currentOffset = offset + { + params["offset"] = currentOffset + } + + let request = createRequest(baseURL: giphyStickerAPIBase, relativePath: "trending", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gifs! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Get the results for a search from Giphy for stickers + /// + /// - Parameters: + /// - searchTerm: The phrase to use to search Giphy + /// - limit: The limit of results to fetch + /// - rating: The max rating for the stickers + /// - offset: The paging offset + /// - completion: The completion block to call when done + public func getSearchStickers(searchTerm: String, limit: Int = 25, rating: SwiftyGiphyAPIContentRating = .pg13, offset: Int? = nil, completion: GiphyMultipleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultStickerAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["q"] = searchTerm + params["limit"] = limit + params["rating"] = rating.rawValue + + if let currentOffset = offset + { + params["offset"] = currentOffset + } + + let request = createRequest(baseURL: giphyStickerAPIBase, relativePath: "search", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gifs! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Translate a search term into an image. + /// + /// - Parameters: + /// - searchTerm: The search term to translate + /// - rating: The max rating for the image (optional, defaults to pg13) + /// - languageCode: The language code (optional) + /// - completion: The completion block to call when done + public func getTranslationStickers(searchTerm: String, rating: SwiftyGiphyAPIContentRating = .pg13, languageCode: String? = nil, completion: GiphySingleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultStickerAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["s"] = searchTerm + params["rating"] = rating.rawValue + + if let language = languageCode + { + params["lang"] = language + } + + let request = createRequest(baseURL: giphyStickerAPIBase, relativePath: "translate", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gif! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } + + /// Get a random sticker + /// + /// - Parameters: + /// - tag: The tag to limit the randomness with + /// - rating: The max rating to limit the image to + /// - completion: The completion block to call when done + public func getRandomSticker(tag: String, rating: SwiftyGiphyAPIContentRating = .pg13, completion: GiphySimpleSingleGIFResponseBlock?) + { + guard apiKey != nil || !isUsingDefaultStickerAPIBase else { + print("ATTENTION: You need to set your Giphy API key before using SwiftyGiphy.") + + completion?(networkError(description: NSLocalizedString("You need to set your Giphy API key before using SwiftyGiphy.", comment: "You need to set your Giphy API key before using SwiftyGiphy.")), nil) + return + } + + var params = [String : Any]() + + if let validAPIKey = apiKey + { + params["api_key"] = validAPIKey + } + + params["tag"] = tag + params["rating"] = rating.rawValue + + let request = createRequest(baseURL: giphyStickerAPIBase, relativePath: "random", method: "GET", params: params) + + send(request: request) { [unowned self] (error, response) in + + guard error == nil, response != nil else { + DispatchQueue.main.async { + + completion?(error ?? self.networkError(description: kGiphyUnknownResponseError), nil) + } + + return + } + + // We have gif! + guard let validResponse = response, let gifs = Mapper().map(JSONObject: validResponse) else { + + completion?(self.networkError(description: kGiphyUnknownResponseError), nil) + return + } + + DispatchQueue.main.async { + completion?(nil, gifs) + } + } + } +} diff --git a/Library/SwiftyGiphyViewController.swift b/Library/SwiftyGiphyViewController.swift index 361cda1..f762d63 100644 --- a/Library/SwiftyGiphyViewController.swift +++ b/Library/SwiftyGiphyViewController.swift @@ -11,7 +11,7 @@ import AVFoundation import NSTimer_Blocks public protocol SwiftyGiphyViewControllerDelegate: class { - + func giphyControllerDidSelectGif(controller: SwiftyGiphyViewController, item: GiphyItem) func giphyControllerDidCancel(controller: SwiftyGiphyViewController) } @@ -19,22 +19,22 @@ public protocol SwiftyGiphyViewControllerDelegate: class { fileprivate let kSwiftyGiphyCollectionViewCell = "SwiftyGiphyCollectionViewCell" public class SwiftyGiphyViewController: UIViewController { - + fileprivate let searchController: UISearchController = UISearchController(searchResultsController: nil) fileprivate let searchContainerView: UIView = UIView(frame: CGRect.zero) - + fileprivate let collectionView: UICollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: SwiftyGiphyGridLayout()) - + fileprivate let loadingIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) - + fileprivate let errorLabel: UILabel = UILabel() - + fileprivate var latestTrendingResponse: GiphyMultipleGIFResponse? fileprivate var latestSearchResponse: GiphyMultipleGIFResponse? - + fileprivate var combinedTrendingGifs: [GiphyItem] = [GiphyItem]() fileprivate var combinedSearchGifs: [GiphyItem] = [GiphyItem]() - + fileprivate var currentGifs: [GiphyItem]? { didSet { collectionView.reloadData() @@ -43,14 +43,14 @@ public class SwiftyGiphyViewController: UIViewController { fileprivate var currentTrendingPageOffset: Int = 0 fileprivate var currentSearchPageOffset: Int = 0 - + fileprivate var searchCounter: Int = 0 - + fileprivate var isTrendingPageLoadInProgress: Bool = false fileprivate var isSearchPageLoadInProgress: Bool = false - + fileprivate var keyboardAdjustConstraint: NSLayoutConstraint! - + fileprivate var searchCoalesceTimer: Timer? { willSet { if searchCoalesceTimer?.isValid == true @@ -59,32 +59,32 @@ public class SwiftyGiphyViewController: UIViewController { } } } - + /// The maximum content rating allowed for the shown gifs public var contentRating: SwiftyGiphyAPIContentRating = .pg13 - + /// The maximum allowed size for gifs shown in the feed - public var maxSizeInBytes: UInt64 = 2048000 // 2MB size cap by default. We're on mobile, after all. - + public var maxSizeInBytes: Int = 2048000 // 2MB size cap by default. We're on mobile, after all. + /// Allow paging the API results. Enabled by default, but you can disable it if you use a custom base URL that doesn't support it. public var allowResultPaging: Bool = true - + /// The collection view layout that governs the waterfall layout of the gifs. There are a few parameters you can modify, but we recommend the defaults. public var collectionViewLayout: SwiftyGiphyGridLayout? { get { return collectionView.collectionViewLayout as? SwiftyGiphyGridLayout } } - + /// The object to receive callbacks for when the user cancels or selects a gif. It is the delegate's responsibility to dismiss the SwiftyGiphyViewController. public weak var delegate: SwiftyGiphyViewControllerDelegate? - + public override func loadView() { super.loadView() - + self.title = NSLocalizedString("Giphy", comment: "Giphy") self.navigationItem.titleView = UIImageView(image: UIImage(named: "GiphyLogoEmblem", in: Bundle(for: SwiftyGiphyViewController.self), compatibleWith: nil)) - + searchController.searchBar.placeholder = NSLocalizedString("Search GIFs", comment: "The placeholder string for the Giphy search field") searchController.searchResultsUpdater = self searchController.dimsBackgroundDuringPresentation = false @@ -95,18 +95,18 @@ public class SwiftyGiphyViewController: UIViewController { searchContainerView.backgroundColor = UIColor.clear searchContainerView.translatesAutoresizingMaskIntoConstraints = false searchContainerView.addSubview(searchController.searchBar) - + collectionView.backgroundColor = UIColor.clear collectionView.delegate = self collectionView.dataSource = self collectionView.keyboardDismissMode = .interactive - + collectionView.translatesAutoresizingMaskIntoConstraints = false - + loadingIndicator.color = UIColor.lightGray loadingIndicator.hidesWhenStopped = true loadingIndicator.translatesAutoresizingMaskIntoConstraints = false - + errorLabel.textAlignment = .center errorLabel.textColor = UIColor.lightGray errorLabel.font = UIFont.systemFont(ofSize: 20.0, weight: UIFontWeightMedium) @@ -118,9 +118,9 @@ public class SwiftyGiphyViewController: UIViewController { self.view.addSubview(loadingIndicator) self.view.addSubview(errorLabel) self.view.addSubview(searchContainerView) - + keyboardAdjustConstraint = collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor) - + NSLayoutConstraint.activate([ searchContainerView.leftAnchor.constraint(equalTo: self.view.leftAnchor), searchContainerView.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor), @@ -131,23 +131,23 @@ public class SwiftyGiphyViewController: UIViewController { collectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor), keyboardAdjustConstraint ]) - + NSLayoutConstraint.activate([ loadingIndicator.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor, constant: 0.0), loadingIndicator.centerYAnchor.constraint(equalTo: collectionView.centerYAnchor, constant: 32.0) ]) - + NSLayoutConstraint.activate([ errorLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 30.0), errorLabel.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -30.0), errorLabel.centerYAnchor.constraint(equalTo: collectionView.centerYAnchor, constant: 32.0) ]) - + collectionView.register(SwiftyGiphyCollectionViewCell.self, forCellWithReuseIdentifier: kSwiftyGiphyCollectionViewCell) - + self.view.backgroundColor = UIColor.groupTableViewBackground } - + public override func viewDidLoad() { super.viewDidLoad() @@ -156,15 +156,15 @@ public class SwiftyGiphyViewController: UIViewController { { collectionViewLayout.delegate = self } - + NotificationCenter.default.addObserver(self, selector: #selector(updateBottomLayoutConstraintWithNotification(notification:)), name: .UIKeyboardWillChangeFrame, object: nil) - + fetchNextTrendingDataPage() } - + public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + if self.navigationController?.viewControllers.count == 1 && self.navigationController?.presentingViewController != nil { self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissPicker)) @@ -174,17 +174,17 @@ public class SwiftyGiphyViewController: UIViewController { self.navigationItem.rightBarButtonItem = nil } } - + public override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() - + collectionView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length + 44.0, 0.0, 10.0, 0.0) collectionView.scrollIndicatorInsets = UIEdgeInsetsMake(self.topLayoutGuide.length + 44.0, 0.0, 10.0, 0.0) } - + public override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - + searchController.searchBar.frame = searchContainerView.bounds } @@ -192,124 +192,124 @@ public class SwiftyGiphyViewController: UIViewController { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - + deinit { NotificationCenter.default.removeObserver(self) } - + @objc fileprivate func dismissPicker() { searchController.isActive = false delegate?.giphyControllerDidCancel(controller: self) } - + fileprivate func fetchNextTrendingDataPage() { guard !isTrendingPageLoadInProgress else { return } - + if currentGifs?.count ?? 0 == 0 { loadingIndicator.startAnimating() errorLabel.isHidden = true } - + isTrendingPageLoadInProgress = true - + let maxBytes = maxSizeInBytes let width = max((collectionView.collectionViewLayout as? SwiftyGiphyGridLayout)?.columnWidth ?? 0.0, 0.0) - + SwiftyGiphyAPI.shared.getTrending(limit: 100, rating: contentRating, offset: currentTrendingPageOffset) { [weak self] (error, response) in - + self?.isTrendingPageLoadInProgress = false self?.loadingIndicator.stopAnimating() self?.errorLabel.isHidden = true - + guard error == nil else { - + if self?.currentGifs?.count ?? 0 == 0 { self?.errorLabel.text = error?.localizedDescription self?.errorLabel.isHidden = false } - + print("Giphy error: \(error?.localizedDescription)") return } - + self?.latestTrendingResponse = response self?.combinedTrendingGifs.append(contentsOf: response!.gifsSmallerThan(sizeInBytes: maxBytes, forWidth: width)) self?.currentTrendingPageOffset = (response!.pagination?.offset ?? (self?.currentTrendingPageOffset ?? 0)) + (response!.pagination?.count ?? 0) - + self?.currentGifs = self?.combinedTrendingGifs - + self?.collectionView.reloadData() } } - + fileprivate func fetchNextSearchPage() { guard !isSearchPageLoadInProgress else { return } - + guard let searchText = searchController.searchBar.text, searchText.characters.count > 0 else { - + self.searchCounter += 1 self.currentGifs = combinedTrendingGifs return } - + searchCoalesceTimer = Timer.scheduledTimer(withTimeInterval: 0.5, block: { [unowned self] () -> Void in - + self.isSearchPageLoadInProgress = true - + if self.currentGifs?.count ?? 0 == 0 { self.loadingIndicator.startAnimating() self.errorLabel.isHidden = true } - + self.searchCounter += 1 - + let currentCounter = self.searchCounter - + let maxBytes = self.maxSizeInBytes let width = max((self.collectionView.collectionViewLayout as? SwiftyGiphyGridLayout)?.columnWidth ?? 0.0, 0.0) - + SwiftyGiphyAPI.shared.getSearch(searchTerm: searchText, limit: 100, rating: self.contentRating, offset: self.currentSearchPageOffset) { [weak self] (error, response) in - + self?.isSearchPageLoadInProgress = false - + guard currentCounter == self?.searchCounter else { - + return } - + self?.loadingIndicator.stopAnimating() self?.errorLabel.isHidden = true - + guard error == nil else { - + if self?.currentGifs?.count ?? 0 == 0 { self?.errorLabel.text = error?.localizedDescription self?.errorLabel.isHidden = false } - + print("Giphy error: \(error?.localizedDescription)") return } - + self?.latestSearchResponse = response self?.combinedSearchGifs.append(contentsOf: response!.gifsSmallerThan(sizeInBytes: maxBytes, forWidth: width)) self?.currentSearchPageOffset = (response!.pagination?.offset ?? (self?.currentSearchPageOffset ?? 0)) + (response!.pagination?.count ?? 0) - + self?.currentGifs = self?.combinedSearchGifs - + self?.collectionView.reloadData() - + if self?.currentGifs?.count ?? 0 == 0 { self?.errorLabel.text = NSLocalizedString("No GIFs match this search.", comment: "No GIFs match this search.") @@ -322,50 +322,50 @@ public class SwiftyGiphyViewController: UIViewController { // MARK: - SwiftyGiphyGridLayoutDelegate extension SwiftyGiphyViewController: SwiftyGiphyGridLayoutDelegate { - + public func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath, withWidth: CGFloat) -> CGFloat { guard let imageSet = currentGifs?[indexPath.row].imageSetClosestTo(width: withWidth, animated: true) else { return 0.0 } - + return AVMakeRect(aspectRatio: CGSize(width: imageSet.width, height: imageSet.height), insideRect: CGRect(x: 0.0, y: 0.0, width: withWidth, height: CGFloat.greatestFiniteMagnitude)).height } } // MARK: - UICollectionViewDataSource extension SwiftyGiphyViewController: UICollectionViewDataSource { - + public func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - + return currentGifs?.count ?? 0 } - + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kSwiftyGiphyCollectionViewCell, for: indexPath) as! SwiftyGiphyCollectionViewCell - + if let collectionViewLayout = collectionView.collectionViewLayout as? SwiftyGiphyGridLayout, let imageSet = currentGifs?[indexPath.row].imageSetClosestTo(width: collectionViewLayout.columnWidth, animated: true) { cell.configureFor(imageSet: imageSet) } - + return cell } } // MARK: - UICollectionViewDelegate extension SwiftyGiphyViewController: UICollectionViewDelegate { - + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { collectionView.deselectItem(at: indexPath, animated: false) - + let selectedGif = currentGifs![indexPath.row] - + searchController.isActive = false delegate?.giphyControllerDidSelectGif(controller: self, item: selectedGif) } @@ -373,31 +373,31 @@ extension SwiftyGiphyViewController: UICollectionViewDelegate { // MARK: - UISearchControllerDelegate extension SwiftyGiphyViewController: UISearchControllerDelegate { - + public func willPresentSearchController(_ searchController: UISearchController) { - + searchCounter += 1 latestSearchResponse = nil currentSearchPageOffset = 0 combinedSearchGifs = [GiphyItem]() currentGifs = [GiphyItem]() - + errorLabel.isHidden = true loadingIndicator.stopAnimating() } - + public func willDismissSearchController(_ searchController: UISearchController) { - + searchController.searchBar.text = nil - + searchCounter += 1 latestSearchResponse = nil currentSearchPageOffset = 0 combinedSearchGifs = [GiphyItem]() - + currentGifs = combinedTrendingGifs collectionView.setContentOffset(CGPoint(x: 0.0, y: -collectionView.contentInset.top), animated: false) - + errorLabel.isHidden = true loadingIndicator.stopAnimating() } @@ -405,9 +405,9 @@ extension SwiftyGiphyViewController: UISearchControllerDelegate { // MARK: - UISearchResultsUpdating extension SwiftyGiphyViewController: UISearchResultsUpdating { - + public func updateSearchResults(for searchController: UISearchController) { - + // Destroy current results searchCounter += 1 latestSearchResponse = nil @@ -420,13 +420,13 @@ extension SwiftyGiphyViewController: UISearchResultsUpdating { // MARK: - UIScrollViewDelegate extension SwiftyGiphyViewController: UIScrollViewDelegate { - + public func scrollViewDidScroll(_ scrollView: UIScrollView) { - + guard allowResultPaging else { return } - + if scrollView.contentOffset.y + scrollView.bounds.height + 100 >= scrollView.contentSize.height { if searchController.isActive @@ -451,36 +451,36 @@ extension SwiftyGiphyViewController: UIScrollViewDelegate { // MARK: - Keyboard extension SwiftyGiphyViewController { - + @objc fileprivate func updateBottomLayoutConstraintWithNotification(notification: NSNotification?) { - + let constantAdjustment: CGFloat = 0.0 - + guard let bottomLayoutConstraint: NSLayoutConstraint = keyboardAdjustConstraint else { return } - + guard let userInfo = notification?.userInfo else { - + bottomLayoutConstraint.constant = constantAdjustment return } - + let animationDuration = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue let keyboardEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let convertedKeyboardEndFrame = view.convert(keyboardEndFrame, from: view.window) let rawAnimationCurve = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).uint32Value << 16 let animationCurve = UIViewAnimationOptions(rawValue: UInt(rawAnimationCurve)) - + let newConstantValue: CGFloat = max(self.view.bounds.maxY - convertedKeyboardEndFrame.minY + constantAdjustment, 0.0) - + if fabs(bottomLayoutConstraint.constant - newConstantValue) >= 1.0 { UIView.animate(withDuration: animationDuration, delay: 0.0, options: animationCurve, animations: { - + bottomLayoutConstraint.constant = -newConstantValue self.view.layoutIfNeeded() - + }, completion: nil) } else diff --git a/README.md b/README.md index 15a00bc..f153dc4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ #SwiftyGiphy SwiftyGiphy is a library to allow you to easily integrate Giphy image search into your app. -The library includes a view controller you can present that shows trending Giphy images, and allows search. The controller also supports paging so your users can contiously scroll and see results. +###The library consists of 2 primary components -The SwiftyGiphy view controller provides a delegate hook so you can be notified of what gif a user has selected. +1. **SwiftyGiphyViewController**, which provides a simple UI for search, and callbacks for selected images so you can quickly integrate Giphy in to your app. The controller also supports paging so your users can contiously scroll and see results. + +2. **SwiftyGiphyAPI**, which provides an API layer to access Giphy. This does not require you to use SwiftyGiphyViewController for your UI, and can be used standalone.
@@ -43,14 +45,14 @@ Recommended usage is to present SwiftyGiphyViewController modally in a UINavigat You should dismiss SwiftyGiphyViewController in the delegate methods, when you need to. -**IMPORTANT:** SwiftyGiphyViewController will not dismiss itself. Similar UIImagePickerController, you'll need to dismiss it from a delegate callback when you want it to go away. +**IMPORTANT:** SwiftyGiphyViewController will not dismiss itself. Similar to UIImagePickerController, you'll need to dismiss it from a delegate callback when you want it to go away. ##Components SwiftyGiphy provides a few useful things for your Giphy integration: * **SwiftyGiphyViewController** (outlined above) gives you an easy to use UI for interacting with Giphy image search. * **SwiftyGiphyViewControllerDelegate** is called by SwiftyGiphyViewController to notify you when the user selects GIFs, or is ready to close the screen. -* **SwiftyGiphyAPI** provides easy access to the Giphy API. Currently the search and trending endpoints are implemented. Hint: I'd welcome pull requests with this component more fleshed out. +* **SwiftyGiphyAPI** provides easy access to the Giphy API. Currently this supports all of the Giphy API [documented here](https://github.com/Giphy/GiphyAPI), with the exception of image uploads. * **SwiftyGiphy Data Models** are provided by the API layer so you can interact with real objects instead of dictionaries and arrays. ##Questions diff --git a/SwiftyGiphy.podspec b/SwiftyGiphy.podspec index d9dacf7..c571faf 100644 --- a/SwiftyGiphy.podspec +++ b/SwiftyGiphy.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'SwiftyGiphy' - s.version = '1.0.5' + s.version = '1.0.6' s.summary = 'Provides a UI and API layer for Giphy discovery and integration.' # This description is used to generate tags and improve search results. diff --git a/SwiftyGiphy/AppDelegate.swift b/SwiftyGiphy/AppDelegate.swift index a8de044..4a6f32c 100644 --- a/SwiftyGiphy/AppDelegate.swift +++ b/SwiftyGiphy/AppDelegate.swift @@ -18,7 +18,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { SwiftyGiphyAPI.shared.apiKey = SwiftyGiphyAPI.publicBetaKey - // Override point for customization after application launch. return true }