You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
16 KiB
364 lines
16 KiB
// |
|
// KingfisherOptionsInfo.swift |
|
// Kingfisher |
|
// |
|
// Created by Wei Wang on 15/4/23. |
|
// |
|
// Copyright (c) 2018 Wei Wang <onevcat@gmail.com> |
|
// |
|
// 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 |
|
|
|
|
|
/** |
|
* KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher. |
|
*/ |
|
public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem] |
|
let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]() |
|
|
|
/** |
|
Items could be added into KingfisherOptionsInfo. |
|
*/ |
|
public enum KingfisherOptionsInfoItem { |
|
/// The associated value of this member should be an ImageCache object. Kingfisher will use the specified |
|
/// cache object when handling related operations, including trying to retrieve the cached images and store |
|
/// the downloaded image to it. |
|
case targetCache(ImageCache) |
|
|
|
/// Cache for storing and retrieving original image. |
|
/// Preferred prior to targetCache for storing and retrieving original images if specified. |
|
/// Only used if a non-default image processor is involved. |
|
case originalCache(ImageCache) |
|
|
|
/// The associated value of this member should be an ImageDownloader object. Kingfisher will use this |
|
/// downloader to download the images. |
|
case downloader(ImageDownloader) |
|
|
|
/// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of |
|
/// this enum to animate the image in if it is downloaded from web. The transition will not happen when the |
|
/// image is retrieved from either memory or disk cache by default. If you need to do the transition even when |
|
/// the image being retrieved from cache, set `ForceTransition` as well. |
|
case transition(ImageTransition) |
|
|
|
/// Associated `Float` value will be set as the priority of image download task. The value for it should be |
|
/// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used. |
|
case downloadPriority(Float) |
|
|
|
/// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource. |
|
case forceRefresh |
|
|
|
/// If set, `Kingfisher` will try to retrieve the image from memory cache first. If the image is not in memory |
|
/// cache, then it will ignore the disk cache but download the image again from network. This is useful when |
|
/// you want to display a changeable image behind the same url, while avoiding download it again and again. |
|
case fromMemoryCacheOrRefresh |
|
|
|
/// If set, setting the image to an image view will happen with transition even when retrieved from cache. |
|
/// See `Transition` option for more. |
|
case forceTransition |
|
|
|
/// If set, `Kingfisher` will only cache the value in memory but not in disk. |
|
case cacheMemoryOnly |
|
|
|
/// If set, `Kingfisher` will wait for caching operation to be completed before calling the completion block. |
|
case waitForCache |
|
|
|
/// If set, `Kingfisher` will only try to retrieve the image from cache not from network. |
|
case onlyFromCache |
|
|
|
/// Decode the image in background thread before using. |
|
case backgroundDecode |
|
|
|
/// The associated value of this member will be used as the target queue of dispatch callbacks when |
|
/// retrieving images from cache. If not set, `Kingfisher` will use main queue for callbacks. |
|
case callbackDispatchQueue(DispatchQueue?) |
|
|
|
/// The associated value of this member will be used as the scale factor when converting retrieved data to an image. |
|
/// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing |
|
/// with 2x or 3x retina images. |
|
case scaleFactor(CGFloat) |
|
|
|
/// Whether all the animated image data should be preloaded. Default it false, which means following frames will be |
|
/// loaded on need. If true, all the animated image data will be loaded and decoded into memory. This option is mainly |
|
/// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload |
|
/// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use |
|
/// corresponding image view type instead of setting this option. |
|
case preloadAllAnimationData |
|
|
|
/// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent. |
|
/// This is the last chance you can modify the request. You can modify the request for some customizing purpose, |
|
/// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request |
|
/// will be sent without any modification by default. |
|
case requestModifier(ImageDownloadRequestModifier) |
|
|
|
/// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image |
|
/// and/or apply some filter on it. If a cache is connected to the downloader (it happens when you are using |
|
/// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the |
|
/// image view. `DefaultImageProcessor.default` will be used by default. |
|
case processor(ImageProcessor) |
|
|
|
/// Supply an `CacheSerializer` to convert some data to an image object for |
|
/// retrieving from disk cache or vice versa for storing to disk cache. |
|
/// `DefaultCacheSerializer.default` will be used by default. |
|
case cacheSerializer(CacheSerializer) |
|
|
|
/// Modifier for modifying an image right before it is used. |
|
/// If the image was fetched directly from the downloader, the modifier will |
|
/// run directly after the processor. |
|
/// If the image is being fetched from a cache, the modifier will run after |
|
/// the cacheSerializer. |
|
/// Use `ImageModifier` when you need to set properties on a concrete type |
|
/// of `Image`, such as a `UIImage`, that do not persist when caching the image. |
|
case imageModifier(ImageModifier) |
|
|
|
/// Keep the existing image while setting another image to an image view. |
|
/// By setting this option, the placeholder image parameter of imageview extension method |
|
/// will be ignored and the current image will be kept while loading or downloading the new image. |
|
case keepCurrentImageWhileLoading |
|
|
|
/// If set, Kingfisher will only load the first frame from a animated image data file as a single image. |
|
/// Loading a lot of animated images may take too much memory. It will be useful when you want to display a |
|
/// static preview of the first frame from a animated image. |
|
/// This option will be ignored if the target image is not animated image data. |
|
case onlyLoadFirstFrame |
|
|
|
/// If set and an `ImageProcessor` is used, Kingfisher will try to cache both |
|
/// the final result and original image. Kingfisher will have a chance to use |
|
/// the original image when another processor is applied to the same resource, |
|
/// instead of downloading it again. |
|
case cacheOriginalImage |
|
} |
|
|
|
precedencegroup ItemComparisonPrecedence { |
|
associativity: none |
|
higherThan: LogicalConjunctionPrecedence |
|
} |
|
|
|
infix operator <== : ItemComparisonPrecedence |
|
|
|
// This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values. |
|
func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool { |
|
switch (lhs, rhs) { |
|
case (.targetCache(_), .targetCache(_)): return true |
|
case (.originalCache(_), .originalCache(_)): return true |
|
case (.downloader(_), .downloader(_)): return true |
|
case (.transition(_), .transition(_)): return true |
|
case (.downloadPriority(_), .downloadPriority(_)): return true |
|
case (.forceRefresh, .forceRefresh): return true |
|
case (.fromMemoryCacheOrRefresh, .fromMemoryCacheOrRefresh): return true |
|
case (.forceTransition, .forceTransition): return true |
|
case (.cacheMemoryOnly, .cacheMemoryOnly): return true |
|
case (.waitForCache, .waitForCache): return true |
|
case (.onlyFromCache, .onlyFromCache): return true |
|
case (.backgroundDecode, .backgroundDecode): return true |
|
case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true |
|
case (.scaleFactor(_), .scaleFactor(_)): return true |
|
case (.preloadAllAnimationData, .preloadAllAnimationData): return true |
|
case (.requestModifier(_), .requestModifier(_)): return true |
|
case (.processor(_), .processor(_)): return true |
|
case (.cacheSerializer(_), .cacheSerializer(_)): return true |
|
case (.imageModifier(_), .imageModifier(_)): return true |
|
case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true |
|
case (.onlyLoadFirstFrame, .onlyLoadFirstFrame): return true |
|
case (.cacheOriginalImage, .cacheOriginalImage): return true |
|
default: return false |
|
} |
|
} |
|
|
|
|
|
extension Collection where Iterator.Element == KingfisherOptionsInfoItem { |
|
func lastMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? { |
|
return reversed().first { $0 <== target } |
|
} |
|
|
|
func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] { |
|
return filter { !($0 <== target) } |
|
} |
|
} |
|
|
|
public extension Collection where Iterator.Element == KingfisherOptionsInfoItem { |
|
/// The target `ImageCache` which is used. |
|
public var targetCache: ImageCache? { |
|
if let item = lastMatchIgnoringAssociatedValue(.targetCache(.default)), |
|
case .targetCache(let cache) = item |
|
{ |
|
return cache |
|
} |
|
return nil |
|
} |
|
|
|
/// The original `ImageCache` which is used. |
|
public var originalCache: ImageCache? { |
|
if let item = lastMatchIgnoringAssociatedValue(.originalCache(.default)), |
|
case .originalCache(let cache) = item |
|
{ |
|
return cache |
|
} |
|
return targetCache |
|
} |
|
|
|
/// The `ImageDownloader` which is specified. |
|
public var downloader: ImageDownloader? { |
|
if let item = lastMatchIgnoringAssociatedValue(.downloader(.default)), |
|
case .downloader(let downloader) = item |
|
{ |
|
return downloader |
|
} |
|
return nil |
|
} |
|
|
|
/// Member for animation transition when using UIImageView. |
|
public var transition: ImageTransition { |
|
if let item = lastMatchIgnoringAssociatedValue(.transition(.none)), |
|
case .transition(let transition) = item |
|
{ |
|
return transition |
|
} |
|
return ImageTransition.none |
|
} |
|
|
|
/// A `Float` value set as the priority of image download task. The value for it should be |
|
/// between 0.0~1.0. |
|
public var downloadPriority: Float { |
|
if let item = lastMatchIgnoringAssociatedValue(.downloadPriority(0)), |
|
case .downloadPriority(let priority) = item |
|
{ |
|
return priority |
|
} |
|
return URLSessionTask.defaultPriority |
|
} |
|
|
|
/// Whether an image will be always downloaded again or not. |
|
public var forceRefresh: Bool { |
|
return contains{ $0 <== .forceRefresh } |
|
} |
|
|
|
/// Whether an image should be got only from memory cache or download. |
|
public var fromMemoryCacheOrRefresh: Bool { |
|
return contains{ $0 <== .fromMemoryCacheOrRefresh } |
|
} |
|
|
|
/// Whether the transition should always happen or not. |
|
public var forceTransition: Bool { |
|
return contains{ $0 <== .forceTransition } |
|
} |
|
|
|
/// Whether cache the image only in memory or not. |
|
public var cacheMemoryOnly: Bool { |
|
return contains{ $0 <== .cacheMemoryOnly } |
|
} |
|
|
|
/// Whether the caching operation will be waited or not. |
|
public var waitForCache: Bool { |
|
return contains{ $0 <== .waitForCache } |
|
} |
|
|
|
/// Whether only load the images from cache or not. |
|
public var onlyFromCache: Bool { |
|
return contains{ $0 <== .onlyFromCache } |
|
} |
|
|
|
/// Whether the image should be decoded in background or not. |
|
public var backgroundDecode: Bool { |
|
return contains{ $0 <== .backgroundDecode } |
|
} |
|
|
|
/// Whether the image data should be all loaded at once if it is an animated image. |
|
public var preloadAllAnimationData: Bool { |
|
return contains { $0 <== .preloadAllAnimationData } |
|
} |
|
|
|
/// The queue of callbacks should happen from Kingfisher. |
|
public var callbackDispatchQueue: DispatchQueue { |
|
if let item = lastMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)), |
|
case .callbackDispatchQueue(let queue) = item |
|
{ |
|
return queue ?? DispatchQueue.main |
|
} |
|
return DispatchQueue.main |
|
} |
|
|
|
/// The scale factor which should be used for the image. |
|
public var scaleFactor: CGFloat { |
|
if let item = lastMatchIgnoringAssociatedValue(.scaleFactor(0)), |
|
case .scaleFactor(let scale) = item |
|
{ |
|
return scale |
|
} |
|
return 1.0 |
|
} |
|
|
|
/// The `ImageDownloadRequestModifier` will be used before sending a download request. |
|
public var modifier: ImageDownloadRequestModifier { |
|
if let item = lastMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)), |
|
case .requestModifier(let modifier) = item |
|
{ |
|
return modifier |
|
} |
|
return NoModifier.default |
|
} |
|
|
|
/// `ImageProcessor` for processing when the downloading finishes. |
|
public var processor: ImageProcessor { |
|
if let item = lastMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)), |
|
case .processor(let processor) = item |
|
{ |
|
return processor |
|
} |
|
return DefaultImageProcessor.default |
|
} |
|
|
|
/// `ImageModifier` for modifying right before the image is displayed. |
|
public var imageModifier: ImageModifier { |
|
if let item = lastMatchIgnoringAssociatedValue(.imageModifier(DefaultImageModifier.default)), |
|
case .imageModifier(let imageModifier) = item |
|
{ |
|
return imageModifier |
|
} |
|
return DefaultImageModifier.default |
|
} |
|
|
|
/// `CacheSerializer` to convert image to data for storing in cache. |
|
public var cacheSerializer: CacheSerializer { |
|
if let item = lastMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)), |
|
case .cacheSerializer(let cacheSerializer) = item |
|
{ |
|
return cacheSerializer |
|
} |
|
return DefaultCacheSerializer.default |
|
} |
|
|
|
/// Keep the existing image while setting another image to an image view. |
|
/// Or the placeholder will be used while downloading. |
|
public var keepCurrentImageWhileLoading: Bool { |
|
return contains { $0 <== .keepCurrentImageWhileLoading } |
|
} |
|
|
|
public var onlyLoadFirstFrame: Bool { |
|
return contains { $0 <== .onlyLoadFirstFrame } |
|
} |
|
|
|
public var cacheOriginalImage: Bool { |
|
return contains { $0 <== .cacheOriginalImage } |
|
} |
|
}
|
|
|