added iOS source code
[wl-app.git] / iOS / Pods / Kingfisher / Sources / Indicator.swift
1 //
2 //  Indicator.swift
3 //  Kingfisher
4 //
5 //  Created by João D. Moreira on 30/08/16.
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 #if os(macOS)
34     public typealias IndicatorView = NSView
35 #else
36     public typealias IndicatorView = UIView
37 #endif
38
39 public enum IndicatorType {
40     /// No indicator.
41     case none
42     /// Use system activity indicator.
43     case activity
44     /// Use an image as indicator. GIF is supported.
45     case image(imageData: Data)
46     /// Use a custom indicator, which conforms to the `Indicator` protocol.
47     case custom(indicator: Indicator)
48 }
49
50 // MARK: - Indicator Protocol
51 public protocol Indicator {
52     func startAnimatingView()
53     func stopAnimatingView()
54
55     var viewCenter: CGPoint { get set }
56     var view: IndicatorView { get }
57 }
58
59 extension Indicator {
60     #if os(macOS)
61     public var viewCenter: CGPoint {
62         get {
63             let frame = view.frame
64             return CGPoint(x: frame.origin.x + frame.size.width / 2.0, y: frame.origin.y + frame.size.height / 2.0 )
65         }
66         set {
67             let frame = view.frame
68             let newFrame = CGRect(x: newValue.x - frame.size.width / 2.0,
69                                   y: newValue.y - frame.size.height / 2.0,
70                                   width: frame.size.width,
71                                   height: frame.size.height)
72             view.frame = newFrame
73         }
74     }
75     #else
76     public var viewCenter: CGPoint {
77         get {
78             return view.center
79         }
80         set {
81             view.center = newValue
82         }
83     }
84     #endif
85 }
86
87 // MARK: - ActivityIndicator
88 // Displays a NSProgressIndicator / UIActivityIndicatorView
89 final class ActivityIndicator: Indicator {
90
91     #if os(macOS)
92     private let activityIndicatorView: NSProgressIndicator
93     #else
94     private let activityIndicatorView: UIActivityIndicatorView
95     #endif
96     private var animatingCount = 0
97
98     var view: IndicatorView {
99         return activityIndicatorView
100     }
101
102     func startAnimatingView() {
103         animatingCount += 1
104         // Alrady animating
105         if animatingCount == 1 {
106             #if os(macOS)
107                 activityIndicatorView.startAnimation(nil)
108             #else
109                 activityIndicatorView.startAnimating()
110             #endif
111             activityIndicatorView.isHidden = false
112         }
113     }
114
115     func stopAnimatingView() {
116         animatingCount = max(animatingCount - 1, 0)
117         if animatingCount == 0 {
118             #if os(macOS)
119                 activityIndicatorView.stopAnimation(nil)
120             #else
121                 activityIndicatorView.stopAnimating()
122             #endif
123             activityIndicatorView.isHidden = true
124         }
125     }
126
127     init() {
128         #if os(macOS)
129             activityIndicatorView = NSProgressIndicator(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
130             activityIndicatorView.controlSize = .small
131             activityIndicatorView.style = .spinning
132         #else
133             #if os(tvOS)
134                 let indicatorStyle = UIActivityIndicatorViewStyle.white
135             #else
136                 let indicatorStyle = UIActivityIndicatorViewStyle.gray
137             #endif
138             activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle:indicatorStyle)
139             activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin, .flexibleTopMargin]
140         #endif
141     }
142 }
143
144 // MARK: - ImageIndicator
145 // Displays an ImageView. Supports gif
146 final class ImageIndicator: Indicator {
147     private let animatedImageIndicatorView: ImageView
148
149     var view: IndicatorView {
150         return animatedImageIndicatorView
151     }
152
153     init?(imageData data: Data, processor: ImageProcessor = DefaultImageProcessor.default, options: KingfisherOptionsInfo = KingfisherEmptyOptionsInfo) {
154
155         var options = options
156         // Use normal image view to show animations, so we need to preload all animation data.
157         if !options.preloadAllAnimationData {
158             options.append(.preloadAllAnimationData)
159         }
160         
161         guard let image = processor.process(item: .data(data), options: options) else {
162             return nil
163         }
164
165         animatedImageIndicatorView = ImageView()
166         animatedImageIndicatorView.image = image
167         animatedImageIndicatorView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
168         
169         #if os(macOS)
170             // Need for gif to animate on macOS
171             self.animatedImageIndicatorView.imageScaling = .scaleNone
172             self.animatedImageIndicatorView.canDrawSubviewsIntoLayer = true
173         #else
174             animatedImageIndicatorView.contentMode = .center
175             animatedImageIndicatorView.autoresizingMask = [.flexibleLeftMargin,
176                                                            .flexibleRightMargin,
177                                                            .flexibleBottomMargin,
178                                                            .flexibleTopMargin]
179         #endif
180     }
181
182     func startAnimatingView() {
183         #if os(macOS)
184             animatedImageIndicatorView.animates = true
185         #else
186             animatedImageIndicatorView.startAnimating()
187         #endif
188         animatedImageIndicatorView.isHidden = false
189     }
190
191     func stopAnimatingView() {
192         #if os(macOS)
193             animatedImageIndicatorView.animates = false
194         #else
195             animatedImageIndicatorView.stopAnimating()
196         #endif
197         animatedImageIndicatorView.isHidden = true
198     }
199 }