X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Kingfisher/Sources/KingfisherManager.swift diff --git a/iOS/Pods/Kingfisher/Sources/KingfisherManager.swift b/iOS/Pods/Kingfisher/Sources/KingfisherManager.swift new file mode 100755 index 0000000..1f8a8f4 --- /dev/null +++ b/iOS/Pods/Kingfisher/Sources/KingfisherManager.swift @@ -0,0 +1,265 @@ +// +// KingfisherManager.swift +// Kingfisher +// +// Created by Wei Wang on 15/4/6. +// +// Copyright (c) 2018 Wei Wang +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(macOS) +import AppKit +#else +import UIKit +#endif + +public typealias DownloadProgressBlock = ((_ receivedSize: Int64, _ totalSize: Int64) -> Void) +public typealias CompletionHandler = ((_ image: Image?, _ error: NSError?, _ cacheType: CacheType, _ imageURL: URL?) -> Void) + +/// RetrieveImageTask represents a task of image retrieving process. +/// It contains an async task of getting image from disk and from network. +public final class RetrieveImageTask { + + public static let empty = RetrieveImageTask() + + // If task is canceled before the download task started (which means the `downloadTask` is nil), + // the download task should not begin. + var cancelledBeforeDownloadStarting: Bool = false + + /// The network retrieve task in this image task. + public var downloadTask: RetrieveImageDownloadTask? + + /** + Cancel current task. If this task is already done, do nothing. + */ + public func cancel() { + if let downloadTask = downloadTask { + downloadTask.cancel() + } else { + cancelledBeforeDownloadStarting = true + } + } +} + +/// Error domain of Kingfisher +public let KingfisherErrorDomain = "com.onevcat.Kingfisher.Error" + +/// Main manager class of Kingfisher. It connects Kingfisher downloader and cache. +/// You can use this class to retrieve an image via a specified URL from web or cache. +public class KingfisherManager { + + /// Shared manager used by the extensions across Kingfisher. + public static let shared = KingfisherManager() + + /// Cache used by this manager + public var cache: ImageCache + + /// Downloader used by this manager + public var downloader: ImageDownloader + + /// Default options used by the manager. This option will be used in + /// Kingfisher manager related methods, including all image view and + /// button extension methods. You can also passing the options per image by + /// sending an `options` parameter to Kingfisher's APIs, the per image option + /// will overwrite the default ones if exist. + /// + /// - Note: This option will not be applied to independent using of `ImageDownloader` or `ImageCache`. + public var defaultOptions = KingfisherEmptyOptionsInfo + + var currentDefaultOptions: KingfisherOptionsInfo { + return [.downloader(downloader), .targetCache(cache)] + defaultOptions + } + + convenience init() { + self.init(downloader: .default, cache: .default) + } + + init(downloader: ImageDownloader, cache: ImageCache) { + self.downloader = downloader + self.cache = cache + } + + /** + Get an image with resource. + If KingfisherOptions.None is used as `options`, Kingfisher will seek the image in memory and disk first. + If not found, it will download the image at `resource.downloadURL` and cache it with `resource.cacheKey`. + These default behaviors could be adjusted by passing different options. See `KingfisherOptions` for more. + + - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`. + - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more. + - parameter progressBlock: Called every time downloaded data changed. This could be used as a progress UI. + - parameter completionHandler: Called when the whole retrieving process finished. + + - returns: A `RetrieveImageTask` task object. You can use this object to cancel the task. + */ + @discardableResult + public func retrieveImage(with resource: Resource, + options: KingfisherOptionsInfo?, + progressBlock: DownloadProgressBlock?, + completionHandler: CompletionHandler?) -> RetrieveImageTask + { + let task = RetrieveImageTask() + let options = currentDefaultOptions + (options ?? KingfisherEmptyOptionsInfo) + if options.forceRefresh { + _ = downloadAndCacheImage( + with: resource.downloadURL, + forKey: resource.cacheKey, + retrieveImageTask: task, + progressBlock: progressBlock, + completionHandler: completionHandler, + options: options) + } else { + tryToRetrieveImageFromCache( + forKey: resource.cacheKey, + with: resource.downloadURL, + retrieveImageTask: task, + progressBlock: progressBlock, + completionHandler: completionHandler, + options: options) + } + + return task + } + + @discardableResult + func downloadAndCacheImage(with url: URL, + forKey key: String, + retrieveImageTask: RetrieveImageTask, + progressBlock: DownloadProgressBlock?, + completionHandler: CompletionHandler?, + options: KingfisherOptionsInfo) -> RetrieveImageDownloadTask? + { + let downloader = options.downloader + return downloader.downloadImage(with: url, retrieveImageTask: retrieveImageTask, options: options, + progressBlock: { receivedSize, totalSize in + progressBlock?(receivedSize, totalSize) + }, + completionHandler: { image, error, imageURL, originalData in + + let targetCache = options.targetCache + if let error = error, error.code == KingfisherError.notModified.rawValue { + // Not modified. Try to find the image from cache. + // (The image should be in cache. It should be guaranteed by the framework users.) + targetCache.retrieveImage(forKey: key, options: options, completionHandler: { (cacheImage, cacheType) -> Void in + completionHandler?(cacheImage, nil, cacheType, url) + }) + return + } + + if let image = image, let originalData = originalData { + targetCache.store(image, + original: originalData, + forKey: key, + processorIdentifier:options.processor.identifier, + cacheSerializer: options.cacheSerializer, + toDisk: !options.cacheMemoryOnly, + completionHandler: nil) + if options.cacheOriginalImage && options.processor != DefaultImageProcessor.default { + let originalCache = options.originalCache + let defaultProcessor = DefaultImageProcessor.default + if let originalImage = defaultProcessor.process(item: .data(originalData), options: options) { + originalCache.store(originalImage, + original: originalData, + forKey: key, + processorIdentifier: defaultProcessor.identifier, + cacheSerializer: options.cacheSerializer, + toDisk: !options.cacheMemoryOnly, + completionHandler: nil) + } + } + } + + completionHandler?(image, error, .none, url) + + }) + } + + func tryToRetrieveImageFromCache(forKey key: String, + with url: URL, + retrieveImageTask: RetrieveImageTask, + progressBlock: DownloadProgressBlock?, + completionHandler: CompletionHandler?, + options: KingfisherOptionsInfo) + { + + let diskTaskCompletionHandler: CompletionHandler = { (image, error, cacheType, imageURL) -> Void in + completionHandler?(image, error, cacheType, imageURL) + } + + func handleNoCache() { + if options.onlyFromCache { + let error = NSError(domain: KingfisherErrorDomain, code: KingfisherError.notCached.rawValue, userInfo: nil) + diskTaskCompletionHandler(nil, error, .none, url) + return + } + self.downloadAndCacheImage( + with: url, + forKey: key, + retrieveImageTask: retrieveImageTask, + progressBlock: progressBlock, + completionHandler: diskTaskCompletionHandler, + options: options) + + } + + let targetCache = options.targetCache + // First, try to get the exactly image from cache + targetCache.retrieveImage(forKey: key, options: options) { image, cacheType in + // If found, we could finish now. + if image != nil { + diskTaskCompletionHandler(image, nil, cacheType, url) + return + } + + // If not found, and we are using a default processor, download it! + let processor = options.processor + guard processor != DefaultImageProcessor.default else { + handleNoCache() + return + } + + // If processor is not the default one, we have a chance to check whether + // the original image is already in cache. + let originalCache = options.originalCache + let optionsWithoutProcessor = options.removeAllMatchesIgnoringAssociatedValue(.processor(processor)) + originalCache.retrieveImage(forKey: key, options: optionsWithoutProcessor) { image, cacheType in + // If we found the original image, there is no need to download it again. + // We could just apply processor to it now. + guard let image = image else { + handleNoCache() + return + } + + guard let processedImage = processor.process(item: .image(image), options: options) else { + diskTaskCompletionHandler(nil, nil, .none, url) + return + } + targetCache.store(processedImage, + original: nil, + forKey: key, + processorIdentifier:options.processor.identifier, + cacheSerializer: options.cacheSerializer, + toDisk: !options.cacheMemoryOnly, + completionHandler: nil) + diskTaskCompletionHandler(processedImage, nil, .none, url) + } + } + } +}