added iOS source code
[wl-app.git] / iOS / Pods / Kingfisher / Sources / KingfisherOptionsInfo.swift
1 //
2 //  KingfisherOptionsInfo.swift
3 //  Kingfisher
4 //
5 //  Created by Wei Wang on 15/4/23.
6 //
7 //  Copyright (c) 2018 Wei Wang <onevcat@gmail.com>
8 //
9 //  Permission is hereby granted, free of charge, to any person obtaining a copy
10 //  of this software and associated documentation files (the "Software"), to deal
11 //  in the Software without restriction, including without limitation the rights
12 //  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 //  copies of the Software, and to permit persons to whom the Software is
14 //  furnished to do so, subject to the following conditions:
15 //
16 //  The above copyright notice and this permission notice shall be included in
17 //  all copies or substantial portions of the Software.
18 //
19 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 //  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 //  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 //  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 //  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 //  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 //  THE SOFTWARE.
26
27 #if os(macOS)
28 import AppKit
29 #else
30 import UIKit
31 #endif
32     
33
34 /**
35 *       KingfisherOptionsInfo is a typealias for [KingfisherOptionsInfoItem]. You can use the enum of option item with value to control some behaviors of Kingfisher.
36 */
37 public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
38 let KingfisherEmptyOptionsInfo = [KingfisherOptionsInfoItem]()
39
40 /**
41 Items could be added into KingfisherOptionsInfo.
42 */
43 public enum KingfisherOptionsInfoItem {
44     /// The associated value of this member should be an ImageCache object. Kingfisher will use the specified
45     /// cache object when handling related operations, including trying to retrieve the cached images and store
46     /// the downloaded image to it.
47     case targetCache(ImageCache)
48     
49     /// Cache for storing and retrieving original image.
50     /// Preferred prior to targetCache for storing and retrieving original images if specified.
51     /// Only used if a non-default image processor is involved.
52     case originalCache(ImageCache)
53     
54     /// The associated value of this member should be an ImageDownloader object. Kingfisher will use this
55     /// downloader to download the images.
56     case downloader(ImageDownloader)
57     
58     /// Member for animation transition when using UIImageView. Kingfisher will use the `ImageTransition` of
59     /// this enum to animate the image in if it is downloaded from web. The transition will not happen when the
60     /// image is retrieved from either memory or disk cache by default. If you need to do the transition even when
61     /// the image being retrieved from cache, set `ForceTransition` as well.
62     case transition(ImageTransition)
63     
64     /// Associated `Float` value will be set as the priority of image download task. The value for it should be
65     /// between 0.0~1.0. If this option not set, the default value (`NSURLSessionTaskPriorityDefault`) will be used.
66     case downloadPriority(Float)
67     
68     /// If set, `Kingfisher` will ignore the cache and try to fire a download task for the resource.
69     case forceRefresh
70
71     /// If set, `Kingfisher` will try to retrieve the image from memory cache first. If the image is not in memory
72     /// cache, then it will ignore the disk cache but download the image again from network. This is useful when
73     /// you want to display a changeable image behind the same url, while avoiding download it again and again.
74     case fromMemoryCacheOrRefresh
75     
76     /// If set, setting the image to an image view will happen with transition even when retrieved from cache.
77     /// See `Transition` option for more.
78     case forceTransition
79     
80     ///  If set, `Kingfisher` will only cache the value in memory but not in disk.
81     case cacheMemoryOnly
82     
83     /// If set, `Kingfisher` will only try to retrieve the image from cache not from network.
84     case onlyFromCache
85     
86     /// Decode the image in background thread before using.
87     case backgroundDecode
88     
89     /// The associated value of this member will be used as the target queue of dispatch callbacks when
90     /// retrieving images from cache. If not set, `Kingfisher` will use main quese for callbacks.
91     case callbackDispatchQueue(DispatchQueue?)
92     
93     /// The associated value of this member will be used as the scale factor when converting retrieved data to an image.
94     /// It is the image scale, instead of your screen scale. You may need to specify the correct scale when you dealing 
95     /// with 2x or 3x retina images.
96     case scaleFactor(CGFloat)
97
98     /// Whether all the animated image data should be preloaded. Default it false, which means following frames will be
99     /// loaded on need. If true, all the animated image data will be loaded and decoded into memory. This option is mainly
100     /// used for back compatibility internally. You should not set it directly. `AnimatedImageView` will not preload
101     /// all data, while a normal image view (`UIImageView` or `NSImageView`) will load all data. Choose to use
102     /// corresponding image view type instead of setting this option.
103     case preloadAllAnimationData
104     
105     /// The `ImageDownloadRequestModifier` contained will be used to change the request before it being sent.
106     /// This is the last chance you can modify the request. You can modify the request for some customizing purpose,
107     /// such as adding auth token to the header, do basic HTTP auth or something like url mapping. The original request
108     /// will be sent without any modification by default.
109     case requestModifier(ImageDownloadRequestModifier)
110     
111     /// Processor for processing when the downloading finishes, a processor will convert the downloaded data to an image
112     /// and/or apply some filter on it. If a cache is connected to the downloader (it happens when you are using
113     /// KingfisherManager or the image extension methods), the converted image will also be sent to cache as well as the
114     /// image view. `DefaultImageProcessor.default` will be used by default.
115     case processor(ImageProcessor)
116     
117     /// Supply an `CacheSerializer` to convert some data to an image object for
118     /// retrieving from disk cache or vice versa for storing to disk cache.
119     /// `DefaultCacheSerializer.default` will be used by default.
120     case cacheSerializer(CacheSerializer)
121
122     /// Modifier for modifying an image right before it is used.
123     /// If the image was fetched directly from the downloader, the modifier will
124     /// run directly after the processor.
125     /// If the image is being fetched from a cache, the modifier will run after
126     /// the cacheSerializer.
127     /// Use `ImageModifier` when you need to set properties on a concrete type
128     /// of `Image`, such as a `UIImage`, that do not persist when caching the image.
129     case imageModifier(ImageModifier)
130     
131     /// Keep the existing image while setting another image to an image view.
132     /// By setting this option, the placeholder image parameter of imageview extension method
133     /// will be ignored and the current image will be kept while loading or downloading the new image.
134     case keepCurrentImageWhileLoading
135     
136     /// If set, Kingfisher will only load the first frame from a animated image data file as a single image.
137     /// Loading a lot of animated images may take too much memory. It will be useful when you want to display a
138     /// static preview of the first frame from a animated image.
139     /// This option will be ignored if the target image is not animated image data.
140     case onlyLoadFirstFrame
141     
142     /// If set and an `ImageProcessor` is used, Kingfisher will try to cache both 
143     /// the final result and original image. Kingfisher will have a chance to use 
144     /// the original image when another processor is applied to the same resouce, 
145     /// instead of downloading it again.
146     case cacheOriginalImage
147 }
148
149 precedencegroup ItemComparisonPrecedence {
150     associativity: none
151     higherThan: LogicalConjunctionPrecedence
152 }
153
154 infix operator <== : ItemComparisonPrecedence
155
156 // This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
157 func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
158     switch (lhs, rhs) {
159     case (.targetCache(_), .targetCache(_)): return true
160     case (.originalCache(_), .originalCache(_)): return true
161     case (.downloader(_), .downloader(_)): return true
162     case (.transition(_), .transition(_)): return true
163     case (.downloadPriority(_), .downloadPriority(_)): return true
164     case (.forceRefresh, .forceRefresh): return true
165     case (.fromMemoryCacheOrRefresh, .fromMemoryCacheOrRefresh): return true
166     case (.forceTransition, .forceTransition): return true
167     case (.cacheMemoryOnly, .cacheMemoryOnly): return true
168     case (.onlyFromCache, .onlyFromCache): return true
169     case (.backgroundDecode, .backgroundDecode): return true
170     case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
171     case (.scaleFactor(_), .scaleFactor(_)): return true
172     case (.preloadAllAnimationData, .preloadAllAnimationData): return true
173     case (.requestModifier(_), .requestModifier(_)): return true
174     case (.processor(_), .processor(_)): return true
175     case (.cacheSerializer(_), .cacheSerializer(_)): return true
176     case (.imageModifier(_), .imageModifier(_)): return true
177     case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
178     case (.onlyLoadFirstFrame, .onlyLoadFirstFrame): return true
179     case (.cacheOriginalImage, .cacheOriginalImage): return true
180     default: return false
181     }
182 }
183
184
185 extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
186     func lastMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
187         return reversed().first { $0 <== target }
188     }
189     
190     func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
191         return filter { !($0 <== target) }
192     }
193 }
194
195 public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
196     /// The target `ImageCache` which is used.
197     public var targetCache: ImageCache {
198         if let item = lastMatchIgnoringAssociatedValue(.targetCache(.default)),
199             case .targetCache(let cache) = item
200         {
201             return cache
202         }
203         return ImageCache.default
204     }
205     
206     /// The original `ImageCache` which is used.
207     public var originalCache: ImageCache {
208         if let item = lastMatchIgnoringAssociatedValue(.originalCache(.default)),
209             case .originalCache(let cache) = item
210         {
211             return cache
212         }
213         return targetCache
214     }
215     
216     /// The `ImageDownloader` which is specified.
217     public var downloader: ImageDownloader {
218         if let item = lastMatchIgnoringAssociatedValue(.downloader(.default)),
219             case .downloader(let downloader) = item
220         {
221             return downloader
222         }
223         return ImageDownloader.default
224     }
225     
226     /// Member for animation transition when using UIImageView.
227     public var transition: ImageTransition {
228         if let item = lastMatchIgnoringAssociatedValue(.transition(.none)),
229             case .transition(let transition) = item
230         {
231             return transition
232         }
233         return ImageTransition.none
234     }
235     
236     /// A `Float` value set as the priority of image download task. The value for it should be
237     /// between 0.0~1.0.
238     public var downloadPriority: Float {
239         if let item = lastMatchIgnoringAssociatedValue(.downloadPriority(0)),
240             case .downloadPriority(let priority) = item
241         {
242             return priority
243         }
244         return URLSessionTask.defaultPriority
245     }
246     
247     /// Whether an image will be always downloaded again or not.
248     public var forceRefresh: Bool {
249         return contains{ $0 <== .forceRefresh }
250     }
251
252     /// Whether an image should be got only from memory cache or download.
253     public var fromMemoryCacheOrRefresh: Bool {
254         return contains{ $0 <== .fromMemoryCacheOrRefresh }
255     }
256     
257     /// Whether the transition should always happen or not.
258     public var forceTransition: Bool {
259         return contains{ $0 <== .forceTransition }
260     }
261     
262     /// Whether cache the image only in memory or not.
263     public var cacheMemoryOnly: Bool {
264         return contains{ $0 <== .cacheMemoryOnly }
265     }
266     
267     /// Whether only load the images from cache or not.
268     public var onlyFromCache: Bool {
269         return contains{ $0 <== .onlyFromCache }
270     }
271     
272     /// Whether the image should be decoded in background or not.
273     public var backgroundDecode: Bool {
274         return contains{ $0 <== .backgroundDecode }
275     }
276
277     /// Whether the image data should be all loaded at once if it is an animated image.
278     public var preloadAllAnimationData: Bool {
279         return contains { $0 <== .preloadAllAnimationData }
280     }
281     
282     /// The queue of callbacks should happen from Kingfisher.
283     public var callbackDispatchQueue: DispatchQueue {
284         if let item = lastMatchIgnoringAssociatedValue(.callbackDispatchQueue(nil)),
285             case .callbackDispatchQueue(let queue) = item
286         {
287             return queue ?? DispatchQueue.main
288         }
289         return DispatchQueue.main
290     }
291     
292     /// The scale factor which should be used for the image.
293     public var scaleFactor: CGFloat {
294         if let item = lastMatchIgnoringAssociatedValue(.scaleFactor(0)),
295             case .scaleFactor(let scale) = item
296         {
297             return scale
298         }
299         return 1.0
300     }
301     
302     /// The `ImageDownloadRequestModifier` will be used before sending a download request.
303     public var modifier: ImageDownloadRequestModifier {
304         if let item = lastMatchIgnoringAssociatedValue(.requestModifier(NoModifier.default)),
305             case .requestModifier(let modifier) = item
306         {
307             return modifier
308         }
309         return NoModifier.default
310     }
311     
312     /// `ImageProcessor` for processing when the downloading finishes.
313     public var processor: ImageProcessor {
314         if let item = lastMatchIgnoringAssociatedValue(.processor(DefaultImageProcessor.default)),
315             case .processor(let processor) = item
316         {
317             return processor
318         }
319         return DefaultImageProcessor.default
320     }
321
322     /// `ImageModifier` for modifying right before the image is displayed.
323     public var imageModifier: ImageModifier {
324         if let item = lastMatchIgnoringAssociatedValue(.imageModifier(DefaultImageModifier.default)),
325             case .imageModifier(let imageModifier) = item
326         {
327             return imageModifier
328         }
329         return DefaultImageModifier.default
330     }
331     
332     /// `CacheSerializer` to convert image to data for storing in cache.
333     public var cacheSerializer: CacheSerializer {
334         if let item = lastMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
335             case .cacheSerializer(let cacheSerializer) = item
336         {
337             return cacheSerializer
338         }
339         return DefaultCacheSerializer.default
340     }
341     
342     /// Keep the existing image while setting another image to an image view. 
343     /// Or the placeholder will be used while downloading.
344     public var keepCurrentImageWhileLoading: Bool {
345         return contains { $0 <== .keepCurrentImageWhileLoading }
346     }
347     
348     public var onlyLoadFirstFrame: Bool {
349         return contains { $0 <== .onlyLoadFirstFrame }
350     }
351     
352     public var cacheOriginalImage: Bool {
353         return contains { $0 <== .cacheOriginalImage }
354     }
355 }