├── .gitignore
├── .travis.yml
├── Core
├── ActivityIndicator.swift
├── FullScreenSlideshowViewController.swift
├── ImageSlideshowItem.swift
├── InputSource.swift
├── KFImageViewer.swift
├── PageIndicator.swift
├── PageIndicatorPosition.swift
├── Resources
│ ├── ic_cross_white@2x.png
│ └── ic_cross_white@3x.png
├── UIImage+AspectFit.swift
├── UIImageView+Tools.swift
└── ZoomAnimatedTransitioning.swift
├── Example
├── KFImageViewer.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── KFImageViewer-Example.xcscheme
├── KFImageViewer.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── KFImageViewer
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── KFImageViewer.gif
│ ├── KFImageViewer_02.gif
│ └── ViewController.swift
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Kingfisher
│ │ ├── LICENSE
│ │ ├── README.md
│ │ └── Sources
│ │ │ ├── AnimatedImageView.swift
│ │ │ ├── Box.swift
│ │ │ ├── CacheSerializer.swift
│ │ │ ├── Filter.swift
│ │ │ ├── FormatIndicatedCacheSerializer.swift
│ │ │ ├── Image.swift
│ │ │ ├── ImageCache.swift
│ │ │ ├── ImageDownloader.swift
│ │ │ ├── ImageModifier.swift
│ │ │ ├── ImagePrefetcher.swift
│ │ │ ├── ImageProcessor.swift
│ │ │ ├── ImageTransition.swift
│ │ │ ├── ImageView+Kingfisher.swift
│ │ │ ├── Indicator.swift
│ │ │ ├── Kingfisher.h
│ │ │ ├── Kingfisher.swift
│ │ │ ├── KingfisherManager.swift
│ │ │ ├── KingfisherOptionsInfo.swift
│ │ │ ├── Placeholder.swift
│ │ │ ├── RequestModifier.swift
│ │ │ ├── Resource.swift
│ │ │ ├── String+MD5.swift
│ │ │ ├── ThreadHelper.swift
│ │ │ └── UIButton+Kingfisher.swift
│ ├── Local Podspecs
│ │ └── KFImageViewer.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── Target Support Files
│ │ ├── KFImageViewer
│ │ ├── Info.plist
│ │ ├── KFImageViewer-dummy.m
│ │ ├── KFImageViewer-prefix.pch
│ │ ├── KFImageViewer-umbrella.h
│ │ ├── KFImageViewer.modulemap
│ │ └── KFImageViewer.xcconfig
│ │ ├── Kingfisher
│ │ ├── Info.plist
│ │ ├── Kingfisher-dummy.m
│ │ ├── Kingfisher-prefix.pch
│ │ ├── Kingfisher-umbrella.h
│ │ ├── Kingfisher.modulemap
│ │ └── Kingfisher.xcconfig
│ │ ├── Pods-KFImageViewer_Example
│ │ ├── Info.plist
│ │ ├── Pods-KFImageViewer_Example-acknowledgements.markdown
│ │ ├── Pods-KFImageViewer_Example-acknowledgements.plist
│ │ ├── Pods-KFImageViewer_Example-dummy.m
│ │ ├── Pods-KFImageViewer_Example-frameworks.sh
│ │ ├── Pods-KFImageViewer_Example-resources.sh
│ │ ├── Pods-KFImageViewer_Example-umbrella.h
│ │ ├── Pods-KFImageViewer_Example.debug.xcconfig
│ │ ├── Pods-KFImageViewer_Example.modulemap
│ │ └── Pods-KFImageViewer_Example.release.xcconfig
│ │ └── Pods-KFImageViewer_Tests
│ │ ├── Info.plist
│ │ ├── Pods-KFImageViewer_Tests-acknowledgements.markdown
│ │ ├── Pods-KFImageViewer_Tests-acknowledgements.plist
│ │ ├── Pods-KFImageViewer_Tests-dummy.m
│ │ ├── Pods-KFImageViewer_Tests-frameworks.sh
│ │ ├── Pods-KFImageViewer_Tests-resources.sh
│ │ ├── Pods-KFImageViewer_Tests-umbrella.h
│ │ ├── Pods-KFImageViewer_Tests.debug.xcconfig
│ │ ├── Pods-KFImageViewer_Tests.modulemap
│ │ └── Pods-KFImageViewer_Tests.release.xcconfig
└── Tests
│ ├── Info.plist
│ └── Tests.swift
├── KFImageViewer.podspec
├── Kingfisher
└── KingfisherSource.swift
├── LICENSE
├── Podfile
├── README.md
└── _Pods.xcodeproj
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # Bundler
23 | .bundle
24 |
25 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
26 | # Carthage/Checkouts
27 |
28 | Carthage/Build
29 |
30 | # We recommend against adding the Pods directory to your .gitignore. However
31 | # you should judge for yourself, the pros and cons are mentioned at:
32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
33 | #
34 | # Note: if you ignore the Pods directory, make sure to uncomment
35 | # `pod install` in .travis.yml
36 | #
37 | # Pods/
38 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/
3 | # * https://github.com/supermarin/xcpretty#usage
4 |
5 | osx_image: xcode7.3
6 | language: objective-c
7 | # cache: cocoapods
8 | # podfile: Example/Podfile
9 | # before_install:
10 | # - gem install cocoapods # Since Travis is not always on latest version
11 | # - pod install --project-directory=Example
12 | script:
13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/KFImageViewer.xcworkspace -scheme KFImageViewer-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty
14 | - pod lib lint
15 |
--------------------------------------------------------------------------------
/Core/ActivityIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActivityIndicator.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 01.05.17.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Cusotm Activity Indicator can be used by implementing this protocol
11 | public protocol ActivityIndicatorView {
12 | /// View of the activity indicator
13 | var view: UIView { get }
14 |
15 | /// Show activity indicator
16 | func show()
17 |
18 | /// Hide activity indicator
19 | func hide()
20 | }
21 |
22 | /// Factory protocol to create new ActivityIndicatorViews. Meant to be implemented when creating custom activity indicator.
23 | public protocol ActivityIndicatorFactory {
24 | func create() -> ActivityIndicatorView
25 | }
26 |
27 | /// Default ActivityIndicatorView implementation for UIActivityIndicatorView
28 | extension UIActivityIndicatorView: ActivityIndicatorView {
29 | public var view: UIView {
30 | return self
31 | }
32 |
33 | public func show() {
34 | startAnimating()
35 | }
36 |
37 | public func hide() {
38 | stopAnimating()
39 | }
40 | }
41 |
42 | /// Default activity indicator factory creating UIActivityIndicatorView instances
43 | @objcMembers
44 | open class DefaultActivityIndicator: ActivityIndicatorFactory {
45 | /// activity indicator style
46 | open var style: UIActivityIndicatorView.Style
47 | /// activity indicator color
48 | open var color: UIColor?
49 |
50 | /// Create a new ActivityIndicator for UIActivityIndicatorView
51 | ///
52 | /// - style: activity indicator style
53 | /// - color: activity indicator color
54 | public init(style: UIActivityIndicatorView.Style = .gray, color: UIColor? = nil) {
55 | self.style = style
56 | self.color = color
57 | }
58 |
59 | /// create ActivityIndicatorView instance
60 | open func create() -> ActivityIndicatorView {
61 | let activityIndicator = UIActivityIndicatorView(style: style)
62 | activityIndicator.color = color
63 | activityIndicator.hidesWhenStopped = true
64 |
65 | return activityIndicator
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Core/FullScreenSlideshowViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FullScreenSlideshowViewController.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 31.08.15.
6 | //
7 |
8 | import UIKit
9 |
10 | @objcMembers
11 | open class FullScreenSlideshowViewController: UIViewController {
12 |
13 | open var slideshow: KFImageViewer = {
14 | let slideshow = KFImageViewer()
15 | slideshow.zoomEnabled = true
16 | slideshow.contentScaleMode = UIView.ContentMode.scaleAspectFit
17 | slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .center, vertical: .bottom)
18 | // turns off the timer
19 | slideshow.slideshowInterval = 0
20 | slideshow.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
21 |
22 | return slideshow
23 | }()
24 |
25 | /// Close button
26 | open var closeButton = UIButton()
27 |
28 | /// Close button frame
29 | open var closeButtonFrame: CGRect?
30 |
31 | /// Closure called on page selection
32 | open var pageSelected: ((_ page: Int) -> Void)?
33 |
34 | /// Index of initial image
35 | open var initialPage: Int = 0
36 |
37 | /// Input sources to
38 | open var inputs: [InputSource]?
39 |
40 | /// Background color
41 | open var backgroundColor = UIColor.black
42 |
43 | /// Enables/disable zoom
44 | open var zoomEnabled = true {
45 | didSet {
46 | slideshow.zoomEnabled = zoomEnabled
47 | }
48 | }
49 |
50 | fileprivate var isInit = true
51 |
52 | override open func viewDidLoad() {
53 | super.viewDidLoad()
54 |
55 | view.backgroundColor = backgroundColor
56 | slideshow.backgroundColor = backgroundColor
57 |
58 | if let inputs = inputs {
59 | slideshow.setImageInputs(inputs)
60 | }
61 |
62 | view.addSubview(slideshow)
63 |
64 | // close button configuration
65 | closeButton.setImage(UIImage(named: "ic_cross_white", in: Bundle(for: type(of: self)), compatibleWith: nil), for: UIControl.State())
66 | closeButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.close), for: UIControl.Event.touchUpInside)
67 | view.addSubview(closeButton)
68 | }
69 |
70 | override open var prefersStatusBarHidden: Bool {
71 | return true
72 | }
73 |
74 | override open func viewWillAppear(_ animated: Bool) {
75 | super.viewWillAppear(animated)
76 |
77 | if isInit {
78 | isInit = false
79 | slideshow.setCurrentPage(initialPage, animated: false)
80 | }
81 | }
82 |
83 | override open func viewWillDisappear(_ animated: Bool) {
84 | super.viewWillDisappear(animated)
85 |
86 | slideshow.slideshowItems.forEach { $0.cancelPendingLoad() }
87 | }
88 |
89 | open override func viewDidLayoutSubviews() {
90 | if !isBeingDismissed {
91 | let safeAreaInsets: UIEdgeInsets
92 | if #available(iOS 11.0, *) {
93 | safeAreaInsets = view.safeAreaInsets
94 | } else {
95 | safeAreaInsets = UIEdgeInsets.zero
96 | }
97 |
98 | closeButton.frame = closeButtonFrame ?? CGRect(x: max(10, safeAreaInsets.left), y: max(10, safeAreaInsets.top), width: 40, height: 40)
99 | }
100 |
101 | slideshow.frame = view.frame
102 | }
103 |
104 | @objc func close() {
105 | // if pageSelected closure set, send call it with current page
106 | if let pageSelected = pageSelected {
107 | pageSelected(slideshow.currentPage)
108 | }
109 |
110 | dismiss(animated: true, completion: nil)
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Core/ImageSlideshowItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZoomablePhotoView.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 30.07.15.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Used to wrap a single slideshow item and allow zooming on it
11 | @objcMembers
12 | open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
13 |
14 | /// Image view to hold the image
15 | public let imageView = UIImageView()
16 |
17 | /// Activity indicator shown during image loading, when nil there won't be shown any
18 | public let activityIndicator: ActivityIndicatorView?
19 |
20 | open var progressView = UIProgressView()
21 |
22 | /// Input Source for the item
23 | public let image: InputSource
24 |
25 | /// Guesture recognizer to detect double tap to zoom
26 | open var gestureRecognizer: UITapGestureRecognizer?
27 |
28 | /// Holds if the zoom feature is enabled
29 | public let zoomEnabled: Bool
30 |
31 | /// If set to true image is initially zoomed in
32 | open var zoomInInitially = false
33 |
34 | /// Maximum zoom scale
35 | open var maximumScale: CGFloat = 2.0
36 |
37 | fileprivate var lastFrame = CGRect.zero
38 | fileprivate var imageReleased = false
39 | fileprivate var isLoading = false
40 | fileprivate var singleTapGestureRecognizer: UITapGestureRecognizer?
41 | fileprivate var loadFailed = false {
42 | didSet {
43 | singleTapGestureRecognizer?.isEnabled = loadFailed
44 | gestureRecognizer?.isEnabled = !loadFailed
45 | }
46 | }
47 |
48 | // MARK: - Life cycle
49 |
50 | /**
51 | Initializes a new ImageSlideshowItem
52 | - parameter image: Input Source to load the image
53 | - parameter zoomEnabled: holds if it should be possible to zoom-in the image
54 | */
55 | init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil, maximumScale: CGFloat = 2.0) {
56 | self.zoomEnabled = zoomEnabled
57 | self.image = image
58 | self.activityIndicator = activityIndicator
59 | self.maximumScale = maximumScale
60 |
61 | super.init(frame: CGRect.null)
62 |
63 | imageView.clipsToBounds = true
64 | imageView.isUserInteractionEnabled = true
65 |
66 | setPictoCenter()
67 |
68 | // scroll view configuration
69 | delegate = self
70 | showsVerticalScrollIndicator = false
71 | showsHorizontalScrollIndicator = false
72 | addSubview(imageView)
73 | minimumZoomScale = 1.0
74 | maximumZoomScale = calculateMaximumScale()
75 |
76 | if let activityIndicator = activityIndicator {
77 | addSubview(activityIndicator.view)
78 | }
79 |
80 | progressView = UIProgressView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 30))
81 | progressView.trackTintColor = UIColor.clear
82 | addSubview(progressView)
83 |
84 | // tap gesture recognizer
85 | let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ImageSlideshowItem.tapZoom))
86 | tapRecognizer.numberOfTapsRequired = 2
87 | imageView.addGestureRecognizer(tapRecognizer)
88 | gestureRecognizer = tapRecognizer
89 |
90 | singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(retryLoadImage))
91 | singleTapGestureRecognizer!.numberOfTapsRequired = 1
92 | singleTapGestureRecognizer!.isEnabled = false
93 | imageView.addGestureRecognizer(singleTapGestureRecognizer!)
94 | }
95 |
96 | required public init?(coder aDecoder: NSCoder) {
97 | fatalError("init(coder:) has not been implemented")
98 | }
99 |
100 | override open func layoutSubviews() {
101 | super.layoutSubviews()
102 |
103 | if !zoomEnabled {
104 | imageView.frame.size = frame.size
105 | } else if !isZoomed() {
106 | imageView.frame.size = calculatePictureSize()
107 | }
108 |
109 | if isFullScreen() {
110 | clearContentInsets()
111 | } else {
112 | setPictoCenter()
113 | }
114 |
115 | self.activityIndicator?.view.center = imageView.center
116 |
117 | // if self.frame was changed and zoomInInitially enabled, zoom in
118 | if lastFrame != frame && zoomInInitially {
119 | setZoomScale(maximumZoomScale, animated: false)
120 | }
121 |
122 | lastFrame = self.frame
123 |
124 | contentSize = imageView.frame.size
125 | maximumZoomScale = calculateMaximumScale()
126 | }
127 |
128 | /// Request to load Image Source to Image View
129 | public func loadImage() {
130 | if self.imageView.image == nil && !isLoading {
131 | isLoading = true
132 | imageReleased = false
133 | activityIndicator?.show()
134 | image.load(to: self.imageView) {[weak self] image in
135 | // set image to nil if there was a release request during the image load
136 | if let imageRelease = self?.imageReleased, imageRelease {
137 | self?.imageView.image = nil
138 | }else{
139 | self?.imageView.image = image
140 | }
141 | self?.activityIndicator?.hide()
142 | self?.loadFailed = image == nil
143 | self?.isLoading = false
144 | }
145 | }
146 | }
147 |
148 | public func loadImageWithProgress()
149 | {
150 | if self.imageView.image == nil && !isLoading {
151 | isLoading = true
152 | imageReleased = false
153 | activityIndicator?.show()
154 | self.progressView.isHidden = false
155 | image.loadWithProgress!(to: self.imageView, with: {[weak self] image in
156 | // set image to nil if there was a release request during the image load
157 | if let imageRelease = self?.imageReleased, imageRelease {
158 | self?.imageView.image = nil
159 | }else{
160 | self?.imageView.image = image
161 | }
162 | self?.progressView.isHidden = true
163 | self?.activityIndicator?.hide()
164 | self?.loadFailed = image == nil
165 | self?.isLoading = false
166 | }) { (progress) in
167 | self.progressView.progress = Float(progress)
168 | }
169 | }
170 | }
171 |
172 | func releaseImage() {
173 | imageReleased = true
174 | cancelPendingLoad()
175 | self.imageView.image = nil
176 | }
177 |
178 | public func cancelPendingLoad() {
179 | image.cancelLoad?(on: imageView)
180 | }
181 |
182 | @objc func retryLoadImage() {
183 | //self.loadImage()
184 | self.loadImageWithProgress()
185 | }
186 |
187 | // MARK: - Image zoom & size
188 |
189 | func isZoomed() -> Bool {
190 | return self.zoomScale != self.minimumZoomScale
191 | }
192 |
193 | func zoomOut() {
194 | self.setZoomScale(minimumZoomScale, animated: false)
195 | }
196 |
197 | @objc func tapZoom() {
198 | if isZoomed() {
199 | self.setZoomScale(minimumZoomScale, animated: true)
200 | } else {
201 | self.setZoomScale(maximumZoomScale, animated: true)
202 | }
203 | }
204 |
205 | fileprivate func screenSize() -> CGSize {
206 | return CGSize(width: frame.width, height: frame.height)
207 | }
208 |
209 | fileprivate func calculatePictureFrame() {
210 | let boundsSize: CGSize = bounds.size
211 | var frameToCenter: CGRect = imageView.frame
212 |
213 | if frameToCenter.size.width < boundsSize.width {
214 | frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2
215 | } else {
216 | frameToCenter.origin.x = 0
217 | }
218 |
219 | if frameToCenter.size.height < boundsSize.height {
220 | frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2
221 | } else {
222 | frameToCenter.origin.y = 0
223 | }
224 |
225 | imageView.frame = frameToCenter
226 | }
227 |
228 | fileprivate func calculatePictureSize() -> CGSize {
229 | if let image = imageView.image, imageView.contentMode == .scaleAspectFit {
230 | let picSize = image.size
231 | let picRatio = picSize.width / picSize.height
232 | let screenRatio = screenSize().width / screenSize().height
233 |
234 | if picRatio > screenRatio {
235 | return CGSize(width: screenSize().width, height: screenSize().width / picSize.width * picSize.height)
236 | } else {
237 | return CGSize(width: screenSize().height / picSize.height * picSize.width, height: screenSize().height)
238 | }
239 | } else {
240 | return CGSize(width: screenSize().width, height: screenSize().height)
241 | }
242 | }
243 |
244 | fileprivate func calculateMaximumScale() -> CGFloat {
245 | return maximumScale
246 | }
247 |
248 | fileprivate func setPictoCenter() {
249 | var intendHorizon = (screenSize().width - imageView.frame.width ) / 2
250 | var intendVertical = (screenSize().height - imageView.frame.height ) / 2
251 | intendHorizon = intendHorizon > 0 ? intendHorizon : 0
252 | intendVertical = intendVertical > 0 ? intendVertical : 0
253 | contentInset = UIEdgeInsets(top: intendVertical, left: intendHorizon, bottom: intendVertical, right: intendHorizon)
254 | }
255 |
256 | private func isFullScreen() -> Bool {
257 | return imageView.frame.width >= screenSize().width && imageView.frame.height >= screenSize().height
258 | }
259 |
260 | func clearContentInsets() {
261 | contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
262 | }
263 |
264 | // MARK: UIScrollViewDelegate
265 |
266 | open func scrollViewDidZoom(_ scrollView: UIScrollView) {
267 | setPictoCenter()
268 | }
269 |
270 | open func viewForZooming(in scrollView: UIScrollView) -> UIView? {
271 | return zoomEnabled ? imageView : nil
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/Core/InputSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InputSource.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 14.01.16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | /// A protocol that can be adapted by different Input Source providers
12 | @objc public protocol InputSource {
13 | /**
14 | Load image from the source to image view.
15 | - parameter imageView: Image view to load the image into.
16 | - parameter callback: Callback called after image was set to the image view.
17 | - parameter image: Image that was set to the image view.
18 | */
19 | func load(to imageView: UIImageView, with callback: @escaping (_ image: UIImage?) -> Void)
20 |
21 | @objc optional func loadWithProgress(to imageView: UIImageView, with callback: @escaping (_ image: UIImage?) -> Void, progress: @escaping(_ progress: CGFloat) ->Void)
22 | /**
23 | Cancel image load on the image view
24 | - parameter imageView: Image view that is loading the image
25 | */
26 | @objc optional func cancelLoad(on imageView: UIImageView)
27 | }
28 |
29 | /// Input Source to load plain UIImage
30 | @objcMembers
31 | open class ImageSource: NSObject, InputSource {
32 | var image: UIImage!
33 |
34 | /// Initializes a new Image Source with UIImage
35 | /// - parameter image: Image to be loaded
36 | public init(image: UIImage) {
37 | self.image = image
38 | }
39 |
40 | /// Initializes a new Image Source with an image name from the main bundle
41 | /// - parameter imageString: name of the file in the application's main bundle
42 | public init?(imageString: String) {
43 | if let image = UIImage(named: imageString) {
44 | self.image = image
45 | super.init()
46 | } else {
47 | return nil
48 | }
49 | }
50 |
51 | public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) {
52 | imageView.image = image
53 | callback(image)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Core/PageIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageIndicator.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 27.05.18.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Cusotm Page Indicator can be used by implementing this protocol
11 | public protocol PageIndicatorView: class {
12 | /// View of the page indicator
13 | var view: UIView { get }
14 |
15 | /// Current page of the page indicator
16 | var page: Int { get set }
17 |
18 | /// Total number of pages of the page indicator
19 | var numberOfPages: Int { get set}
20 | }
21 |
22 | extension UIPageControl: PageIndicatorView {
23 | public var view: UIView {
24 | return self
25 | }
26 |
27 | public var page: Int {
28 | get {
29 | return currentPage
30 | }
31 | set {
32 | currentPage = newValue
33 | }
34 | }
35 |
36 | open override func sizeToFit() {
37 | var frame = self.frame
38 | frame.size = size(forNumberOfPages: numberOfPages)
39 | frame.size.height = 30
40 | self.frame = frame
41 | }
42 | }
43 |
44 | /// Page indicator that shows page in numeric style, eg. "5/21"
45 | public class LabelPageIndicator: UILabel, PageIndicatorView {
46 | public var view: UIView {
47 | return self
48 | }
49 |
50 | public var numberOfPages: Int = 0 {
51 | didSet {
52 | updateLabel()
53 | }
54 | }
55 |
56 | public var page: Int = 0 {
57 | didSet {
58 | updateLabel()
59 | }
60 | }
61 |
62 | public override init(frame: CGRect) {
63 | super.init(frame: frame)
64 | initialize()
65 | }
66 |
67 | required public init?(coder aDecoder: NSCoder) {
68 | super.init(coder: aDecoder)
69 | initialize()
70 | }
71 |
72 | private func initialize() {
73 | self.textAlignment = .center
74 | }
75 |
76 | private func updateLabel() {
77 | text = "\(page+1)/\(numberOfPages)"
78 | }
79 |
80 | public override func sizeToFit() {
81 | let maximumString = String(repeating: "8", count: numberOfPages) as NSString
82 | self.frame.size = maximumString.size(withAttributes: [.font: font])
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Core/PageIndicatorPosition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageIndicator.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 04.02.18.
6 | //
7 |
8 | import UIKit
9 |
10 | /// Describes the configuration of the page indicator position
11 | public struct PageIndicatorPosition {
12 | public enum Horizontal {
13 | case left(padding: CGFloat), center, right(padding: CGFloat)
14 | }
15 |
16 | public enum Vertical {
17 | case top, bottom, under, customTop(padding: CGFloat), customBottom(padding: CGFloat), customUnder(padding: CGFloat)
18 | }
19 |
20 | /// Horizontal position of the page indicator
21 | var horizontal: Horizontal
22 |
23 | /// Vertical position of the page indicator
24 | var vertical: Vertical
25 |
26 | /// Creates a new PageIndicatorPosition struct
27 | ///
28 | /// - Parameters:
29 | /// - horizontal: horizontal position of the page indicator
30 | /// - vertical: vertical position of the page indicator
31 | public init(horizontal: Horizontal = .center, vertical: Vertical = .bottom) {
32 | self.horizontal = horizontal
33 | self.vertical = vertical
34 | }
35 |
36 | /// Computes the additional padding needed for the page indicator under the KFImageViewer
37 | ///
38 | /// - Parameter indicatorSize: size of the page indicator
39 | /// - Returns: padding needed under the KFImageViewer
40 | func underPadding(for indicatorSize: CGSize) -> CGFloat {
41 | switch vertical {
42 | case .under:
43 | return indicatorSize.height
44 | case .customUnder(let padding):
45 | return indicatorSize.height + padding
46 | default:
47 | return 0
48 | }
49 | }
50 |
51 | /// Computes the page indicator frame
52 | ///
53 | /// - Parameters:
54 | /// - parentFrame: frame of the parent view – KFImageViewer
55 | /// - indicatorSize: size of the page indicator
56 | /// - edgeInsets: edge insets of the parent view – KFImageViewer (used for SafeAreaInsets adjustment)
57 | /// - Returns: frame of the indicator by computing the origin and using `indicatorSize` as size
58 | func indicatorFrame(for parentFrame: CGRect, indicatorSize: CGSize, edgeInsets: UIEdgeInsets) -> CGRect {
59 | var xSize: CGFloat = 0
60 | var ySize: CGFloat = 0
61 |
62 | switch horizontal {
63 | case .center:
64 | xSize = parentFrame.size.width / 2 - indicatorSize.width / 2
65 | case .left(let padding):
66 | xSize = padding + edgeInsets.left
67 | case .right(let padding):
68 | xSize = parentFrame.size.width - indicatorSize.width - padding - edgeInsets.right
69 | }
70 |
71 | switch vertical {
72 | case .bottom, .under, .customUnder:
73 | ySize = parentFrame.size.height - indicatorSize.height - edgeInsets.bottom
74 | case .customBottom(let padding):
75 | ySize = parentFrame.size.height - indicatorSize.height - padding - edgeInsets.bottom
76 | case .top:
77 | ySize = edgeInsets.top
78 | case .customTop(let padding):
79 | ySize = padding + edgeInsets.top
80 | }
81 |
82 | return CGRect(x: xSize, y: ySize, width: indicatorSize.width, height: indicatorSize.height)
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Core/Resources/ic_cross_white@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalazeez/KFImageViewer/1564b20f5b21933e3f47b093a614d5480211a49d/Core/Resources/ic_cross_white@2x.png
--------------------------------------------------------------------------------
/Core/Resources/ic_cross_white@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalazeez/KFImageViewer/1564b20f5b21933e3f47b093a614d5480211a49d/Core/Resources/ic_cross_white@3x.png
--------------------------------------------------------------------------------
/Core/UIImage+AspectFit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+AspectFit.swift
3 | // KFImageViewer
4 | //
5 | // Created by Petr Zvoníček on 31.08.15.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIImage {
12 |
13 | func tgr_aspectFitRectForSize(_ size: CGSize) -> CGRect {
14 | let targetAspect: CGFloat = size.width / size.height
15 | let sourceAspect: CGFloat = self.size.width / self.size.height
16 | var rect: CGRect = CGRect.zero
17 |
18 | if targetAspect > sourceAspect {
19 | rect.size.height = size.height
20 | rect.size.width = ceil(rect.size.height * sourceAspect)
21 | rect.origin.x = ceil((size.width - rect.size.width) * 0.5)
22 | } else {
23 | rect.size.width = size.width
24 | rect.size.height = ceil(rect.size.width / sourceAspect)
25 | rect.origin.y = ceil((size.height - rect.size.height) * 0.5)
26 | }
27 |
28 | return rect
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Core/UIImageView+Tools.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Tools.swift
3 | // Pods
4 | //
5 | // Created by Aleš Kocur on 20/04/16.
6 | //
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIImageView {
12 |
13 | func aspectToFitFrame() -> CGRect {
14 |
15 | guard let image = image else {
16 | assertionFailure("No image found!")
17 | return CGRect.zero
18 | }
19 |
20 | let imageRatio: CGFloat = image.size.width / image.size.height
21 | let viewRatio: CGFloat = frame.size.width / frame.size.height
22 |
23 | if imageRatio < viewRatio {
24 | let scale: CGFloat = frame.size.height / image.size.height
25 | let width: CGFloat = scale * image.size.width
26 | let topLeftX: CGFloat = (frame.size.width - width) * 0.5
27 | return CGRect(x: topLeftX, y: 0, width: width, height: frame.size.height)
28 | } else {
29 | let scale: CGFloat = frame.size.width / image.size.width
30 | let height: CGFloat = scale * image.size.height
31 | let topLeftY: CGFloat = (frame.size.height - height) * 0.5
32 | return CGRect(x: 0, y: topLeftY, width: frame.size.width, height: height)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/KFImageViewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/KFImageViewer.xcodeproj/xcshareddata/xcschemes/KFImageViewer-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
80 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
101 |
107 |
108 |
109 |
110 |
112 |
113 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Example/KFImageViewer.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/KFImageViewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // KFImageViewer
4 | //
5 | // Created by faisalazeez on 08/09/2018.
6 | // Copyright (c) 2018 faisalazeez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "size" : "1024x1024",
46 | "scale" : "1x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Example/KFImageViewer/KFImageViewer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalazeez/KFImageViewer/1564b20f5b21933e3f47b093a614d5480211a49d/Example/KFImageViewer/KFImageViewer.gif
--------------------------------------------------------------------------------
/Example/KFImageViewer/KFImageViewer_02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalazeez/KFImageViewer/1564b20f5b21933e3f47b093a614d5480211a49d/Example/KFImageViewer/KFImageViewer_02.gif
--------------------------------------------------------------------------------
/Example/KFImageViewer/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // KFImageViewer
4 | //
5 | // Created by faisalazeez on 08/09/2018.
6 | // Copyright (c) 2018 faisalazeez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import KFImageViewer
11 |
12 | class ViewController: UIViewController {
13 |
14 | /*
15 | * sample url as kingfisher Input source
16 | */
17 | let photo:[InputSource] = [KingfisherSource(urlString: "https://eoimages.gsfc.nasa.gov/images/imagerecords/84000/84214/bluemarble_2014090_xlrg.jpg")!,KingfisherSource(urlString: "https://picsum.photos/1024/1000")!]
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 | // Do any additional setup after loading the view, typically from a nib.
22 | }
23 |
24 | override func didReceiveMemoryWarning() {
25 | super.didReceiveMemoryWarning()
26 | // Dispose of any resources that can be recreated.
27 | }
28 |
29 | func callLIb()
30 | {
31 | let fullScreenController = FullScreenSlideshowViewController()
32 | fullScreenController.inputs = photo
33 | fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
34 |
35 | /*
36 | if let cell = tableView.cellForRow(at: indexPath), let imageView = cell.imageView {
37 | slideshowTransitioningDelegate = ZoomAnimatedTransitioningDelegate(imageView: imageView, slideshowController: fullScreenController)
38 | fullScreenController.transitioningDelegate = slideshowTransitioningDelegate
39 | }
40 |
41 | fullScreenController.slideshow.currentPageChanged = { [weak self] page in
42 | if let cell = tableView.cellForRow(at: IndexPath(row: page, section: 0)), let imageView = cell.imageView {
43 | self?.slideshowTransitioningDelegate?.referenceImageView = imageView
44 | }
45 | }
46 | */
47 | present(fullScreenController, animated: true, completion: nil)
48 | }
49 | @IBAction func action(_ sender: Any)
50 | {
51 | callLIb()
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'KFImageViewer_Example' do
4 | pod 'KFImageViewer', :path => '../'
5 | pod "KFImageViewer/Kingfisher", :path => "../"
6 |
7 | target 'KFImageViewer_Tests' do
8 | inherit! :search_paths
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - KFImageViewer (1.0.0):
3 | - KFImageViewer/Core (= 1.0.0)
4 | - KFImageViewer/Core (1.0.0)
5 | - KFImageViewer/Kingfisher (1.0.0):
6 | - KFImageViewer/Core
7 | - Kingfisher (> 4.0)
8 | - Kingfisher (4.8.0)
9 |
10 | DEPENDENCIES:
11 | - KFImageViewer (from `../`)
12 | - KFImageViewer/Kingfisher (from `../`)
13 |
14 | SPEC REPOS:
15 | https://github.com/cocoapods/specs.git:
16 | - Kingfisher
17 |
18 | EXTERNAL SOURCES:
19 | KFImageViewer:
20 | :path: "../"
21 |
22 | SPEC CHECKSUMS:
23 | KFImageViewer: 98e9bbf8eb8547cbe068501675b95d8e14c5658a
24 | Kingfisher: 976d828df2b24834c6a3f2fc4d82cdbd26552be1
25 |
26 | PODFILE CHECKSUM: ec48d017d47cd4da82807056131dfeea12515cee
27 |
28 | COCOAPODS: 1.5.3
29 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Wei Wang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Kingfisher is a lightweight, pure-Swift library for downloading and caching images from the web. This project is heavily inspired by the popular [SDWebImage](https://github.com/rs/SDWebImage). It provides you a chance to use a pure-Swift alternative in your next app.
19 |
20 | ## Features
21 |
22 | - [x] Asynchronous image downloading and caching.
23 | - [x] `URLSession`-based networking. Basic image processors and filters supplied.
24 | - [x] Multiple-layer cache for both memory and disk.
25 | - [x] Cancelable downloading and processing tasks to improve performance.
26 | - [x] Independent components. Use the downloader or caching system separately as you need.
27 | - [x] Prefetching images and showing them from cache later when necessary.
28 | - [x] Extensions for `UIImageView`, `NSImage` and `UIButton` to directly set an image from a URL.
29 | - [x] Built-in transition animation when setting images.
30 | - [x] Customizable placeholder while loading images.
31 | - [x] Extensible image processing and image format support.
32 |
33 | The simplest use-case is setting an image to an image view with the `UIImageView` extension:
34 |
35 | ```swift
36 | let url = URL(string: "url_of_your_image")
37 | imageView.kf.setImage(with: url)
38 | ```
39 |
40 | Kingfisher will download the image from `url`, send it to both the memory cache and the disk cache, and display it in `imageView`. When you use the same code later, the image will be retrieved from cache and shown immediately.
41 |
42 | For more examples of using Kingfisher, take a look at the [Cheat Sheet](https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet).
43 |
44 | ## Requirements
45 |
46 | - iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
47 | - Swift 4 (Kingfisher 4.x), Swift 3 (Kingfisher 3.x)
48 |
49 | Main development of Kingfisher is based on Swift 4. Only critical bug fixes will be applied to Kingfisher 3.x.
50 |
51 | - Kingfisher 4.0 Migration - Kingfisher 3.x should be source compatible to Kingfisher 4. The reason for a major update is that we need to specify the Swift version explicitly for Xcode. All deprecated methods in Kingfisher 3 has been removed, so please ensure you have no warning left before you migrate from Kingfisher 3 to Kingfisher 4. If you have any trouble in migrating, please open an issue to discuss.
52 | - [Kingfisher 3.0 Migration Guide](https://github.com/onevcat/Kingfisher/wiki/Kingfisher-3.0-Migration-Guide) - If you are upgrading to Kingfisher 3.x from an earlier version, please read this for more information.
53 |
54 | ## Next Steps
55 |
56 | We prepared a [wiki page](https://github.com/onevcat/Kingfisher/wiki). You can find tons of useful things there.
57 |
58 | * [Installation Guide](https://github.com/onevcat/Kingfisher/wiki/Installation-Guide) - Follow it to integrate Kingfisher into your project.
59 | * [Cheat Sheet](https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet)- Curious about what Kingfisher could do and how would it look like when used in your project? See this page for useful code snippets. If you are already familiar with Kingfisher, you could also learn new tricks to improve the way you use Kingfisher!
60 | * [API Reference](http://onevcat.github.io/Kingfisher/) - Lastly, please remember to read the full whenever you may need a more detailed reference.
61 |
62 | ## Other
63 |
64 | ### Future of Kingfisher
65 |
66 | I want to keep Kingfisher lightweight. This framework will focus on providing a simple solution for downloading and caching images. This doesn’t mean the framework can’t be improved. Kingfisher is far from perfect, so necessary and useful updates will be made to make it better.
67 |
68 | ### Developments and Tests
69 |
70 | Any contributing and pull requests are warmly welcome. However, before you plan to implement some features or try to fix an uncertain issue, it is recommended to open a discussion first.
71 |
72 | The test images are contained in another project to keep this project repo fast and slim. You could run `./setup.sh` in the root folder of Kingfisher to clone the test images when you need to run the tests target. It would be appreciated if your pull requests could build and with all tests green. :)
73 |
74 | ### About the logo
75 |
76 | The logo of Kingfisher is inspired by [Tangram (七巧板)](http://en.wikipedia.org/wiki/Tangram), a dissection puzzle consisting of seven flat shapes from China. I believe she's a kingfisher bird instead of a swift, but someone insists that she is a pigeon. I guess I should give her a name. Hi, guys, do you have any suggestions?
77 |
78 | ### Contact
79 |
80 | Follow and contact me on [Twitter](http://twitter.com/onevcat) or [Sina Weibo](http://weibo.com/onevcat). If you find an issue, just [open a ticket](https://github.com/onevcat/Kingfisher/issues/new). Pull requests are warmly welcome as well.
81 |
82 | ## Contributors
83 |
84 | This project exists thanks to all the people who contribute. [[Contribute]](https://github.com/onevcat/Kingfisher/blob/master/CONTRIBUTING.md).
85 |
86 |
87 |
88 | ## Backers
89 |
90 | Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/kingfisher#backer)]
91 |
92 |
93 |
94 |
95 | ## Sponsors
96 |
97 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/kingfisher#sponsor)]
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | ### License
113 |
114 | Kingfisher is released under the MIT license. See LICENSE for details.
115 |
116 |
117 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2018/3/17.
6 | // Copyright (c) 2018 Wei Wang
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 |
26 | import Foundation
27 |
28 | class Box {
29 | let value: T
30 |
31 | init(_ value: T) {
32 | self.value = value
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/CacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CacheSerializer.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/02.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 |
29 | /// An `CacheSerializer` would be used to convert some data to an image object for
30 | /// retrieving from disk cache and vice versa for storing to disk cache.
31 | public protocol CacheSerializer {
32 |
33 | /// Get the serialized data from a provided image
34 | /// and optional original data for caching to disk.
35 | ///
36 | ///
37 | /// - parameter image: The image needed to be serialized.
38 | /// - parameter original: The original data which is just downloaded.
39 | /// If the image is retrieved from cache instead of
40 | /// downloaded, it will be `nil`.
41 | ///
42 | /// - returns: A data which will be stored to cache, or `nil` when no valid
43 | /// data could be serialized.
44 | func data(with image: Image, original: Data?) -> Data?
45 |
46 | /// Get an image deserialized from provided data.
47 | ///
48 | /// - parameter data: The data from which an image should be deserialized.
49 | /// - parameter options: Options for deserialization.
50 | ///
51 | /// - returns: An image deserialized or `nil` when no valid image
52 | /// could be deserialized.
53 | func image(with data: Data, options: KingfisherOptionsInfo?) -> Image?
54 | }
55 |
56 |
57 | /// `DefaultCacheSerializer` is a basic `CacheSerializer` used in default cache of
58 | /// Kingfisher. It could serialize and deserialize PNG, JEPG and GIF images. For
59 | /// image other than these formats, a normalized `pngRepresentation` will be used.
60 | public struct DefaultCacheSerializer: CacheSerializer {
61 |
62 | public static let `default` = DefaultCacheSerializer()
63 | private init() {}
64 |
65 | public func data(with image: Image, original: Data?) -> Data? {
66 | let imageFormat = original?.kf.imageFormat ?? .unknown
67 |
68 | let data: Data?
69 | switch imageFormat {
70 | case .PNG: data = image.kf.pngRepresentation()
71 | case .JPEG: data = image.kf.jpegRepresentation(compressionQuality: 1.0)
72 | case .GIF: data = image.kf.gifRepresentation()
73 | case .unknown: data = original ?? image.kf.normalized.kf.pngRepresentation()
74 | }
75 |
76 | return data
77 | }
78 |
79 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
80 | let options = options ?? KingfisherEmptyOptionsInfo
81 | return Kingfisher.image(
82 | data: data,
83 | scale: options.scaleFactor,
84 | preloadAllAnimationData: options.preloadAllAnimationData,
85 | onlyFirstFrame: options.onlyLoadFirstFrame)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Filter.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/08/31.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 |
28 |
29 | import CoreImage
30 | import Accelerate
31 |
32 | // Reuse the same CI Context for all CI drawing.
33 | private let ciContext = CIContext(options: nil)
34 |
35 | /// Transformer method which will be used in to provide a `Filter`.
36 | public typealias Transformer = (CIImage) -> CIImage?
37 |
38 | /// Supply a filter to create an `ImageProcessor`.
39 | public protocol CIImageProcessor: ImageProcessor {
40 | var filter: Filter { get }
41 | }
42 |
43 | extension CIImageProcessor {
44 | public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
45 | switch item {
46 | case .image(let image):
47 | return image.kf.apply(filter)
48 | case .data(_):
49 | return (DefaultImageProcessor.default >> self).process(item: item, options: options)
50 | }
51 | }
52 | }
53 |
54 | /// Wrapper for a `Transformer` of CIImage filters.
55 | public struct Filter {
56 |
57 | let transform: Transformer
58 |
59 | public init(transform: @escaping Transformer) {
60 | self.transform = transform
61 | }
62 |
63 | /// Tint filter which will apply a tint color to images.
64 | public static var tint: (Color) -> Filter = {
65 | color in
66 | Filter(transform: { input in
67 | let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
68 | colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
69 |
70 | let colorImage = colorFilter.outputImage
71 | let filter = CIFilter(name: "CISourceOverCompositing")!
72 | filter.setValue(colorImage, forKey: kCIInputImageKey)
73 | filter.setValue(input, forKey: kCIInputBackgroundImageKey)
74 | #if swift(>=4.0)
75 | return filter.outputImage?.cropped(to: input.extent)
76 | #else
77 | return filter.outputImage?.cropping(to: input.extent)
78 | #endif
79 | })
80 | }
81 |
82 | public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
83 |
84 | /// Color control filter which will apply color control change to images.
85 | public static var colorControl: (ColorElement) -> Filter = { arg -> Filter in
86 | let (brightness, contrast, saturation, inputEV) = arg
87 | return Filter(transform: { input in
88 | let paramsColor = [kCIInputBrightnessKey: brightness,
89 | kCIInputContrastKey: contrast,
90 | kCIInputSaturationKey: saturation]
91 |
92 | let paramsExposure = [kCIInputEVKey: inputEV]
93 | #if swift(>=4.0)
94 | let blackAndWhite = input.applyingFilter("CIColorControls", parameters: paramsColor)
95 | return blackAndWhite.applyingFilter("CIExposureAdjust", parameters: paramsExposure)
96 | #else
97 | let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
98 | return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
99 | #endif
100 | })
101 | }
102 | }
103 |
104 | // MARK: - Deprecated
105 | extension Filter {
106 | @available(*, deprecated, message: "Use init(transform:) instead.", renamed: "init(transform:)")
107 | public init(tranform: @escaping Transformer) {
108 | self.transform = tranform
109 | }
110 | }
111 |
112 | extension Kingfisher where Base: Image {
113 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
114 | ///
115 | /// - parameter filter: The filter used to transform `self`.
116 | ///
117 | /// - returns: A transformed image by input `Filter`.
118 | ///
119 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
120 | public func apply(_ filter: Filter) -> Image {
121 |
122 | guard let cgImage = cgImage else {
123 | assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
124 | return base
125 | }
126 |
127 | let inputImage = CIImage(cgImage: cgImage)
128 | guard let outputImage = filter.transform(inputImage) else {
129 | return base
130 | }
131 |
132 | guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
133 | assertionFailure("[Kingfisher] Can not make an tint image within context.")
134 | return base
135 | }
136 |
137 | #if os(macOS)
138 | return fixedForRetinaPixel(cgImage: result, to: size)
139 | #else
140 | return Image(cgImage: result, scale: base.scale, orientation: base.imageOrientation)
141 | #endif
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/FormatIndicatedCacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Junyu Kuang on 5/28/17.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 |
29 | /// `FormatIndicatedCacheSerializer` let you indicate an image format for serialized caches.
30 | ///
31 | /// It could serialize and deserialize PNG, JEPG and GIF images. For
32 | /// image other than these formats, a normalized `pngRepresentation` will be used.
33 | ///
34 | /// Example:
35 | /// ````
36 | /// private let profileImageSize = CGSize(width: 44, height: 44)
37 | ///
38 | /// private let imageProcessor = RoundCornerImageProcessor(
39 | /// cornerRadius: profileImageSize.width / 2, targetSize: profileImageSize)
40 | ///
41 | /// private let optionsInfo: KingfisherOptionsInfo = [
42 | /// .cacheSerializer(FormatIndicatedCacheSerializer.png),
43 | /// .backgroundDecode, .processor(imageProcessor), .scaleFactor(UIScreen.main.scale)]
44 | ///
45 | /// extension UIImageView {
46 | /// func setProfileImage(with url: URL) {
47 | /// // Image will always cached as PNG format to preserve alpha channel for round rect.
48 | /// _ = kf.setImage(with: url, options: optionsInfo)
49 | /// }
50 | ///}
51 | /// ````
52 | public struct FormatIndicatedCacheSerializer: CacheSerializer {
53 |
54 | public static let png = FormatIndicatedCacheSerializer(imageFormat: .PNG)
55 | public static let jpeg = FormatIndicatedCacheSerializer(imageFormat: .JPEG)
56 | public static let gif = FormatIndicatedCacheSerializer(imageFormat: .GIF)
57 |
58 | /// The indicated image format.
59 | private let imageFormat: ImageFormat
60 |
61 | public func data(with image: Image, original: Data?) -> Data? {
62 |
63 | func imageData(withFormat imageFormat: ImageFormat) -> Data? {
64 | switch imageFormat {
65 | case .PNG: return image.kf.pngRepresentation()
66 | case .JPEG: return image.kf.jpegRepresentation(compressionQuality: 1.0)
67 | case .GIF: return image.kf.gifRepresentation()
68 | case .unknown: return nil
69 | }
70 | }
71 |
72 | // generate data with indicated image format
73 | if let data = imageData(withFormat: imageFormat) {
74 | return data
75 | }
76 |
77 | let originalFormat = original?.kf.imageFormat ?? .unknown
78 |
79 | // generate data with original image's format
80 | if originalFormat != imageFormat, let data = imageData(withFormat: originalFormat) {
81 | return data
82 | }
83 |
84 | return original ?? image.kf.normalized.kf.pngRepresentation()
85 | }
86 |
87 | /// Same implementation as `DefaultCacheSerializer`.
88 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
89 | let options = options ?? KingfisherEmptyOptionsInfo
90 | return Kingfisher.image(
91 | data: data,
92 | scale: options.scaleFactor,
93 | preloadAllAnimationData: options.preloadAllAnimationData,
94 | onlyFirstFrame: options.onlyLoadFirstFrame)
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/ImageModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Ethan Gill on 2017/11/28.
6 | //
7 | // Copyright (c) 2018 Ethan Gill
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 | import Foundation
28 |
29 | /// An `ImageModifier` can be used to change properties on an Image in between
30 | /// cache serialization and use of the image.
31 | public protocol ImageModifier {
32 | /// Modify an input `Image`.
33 | ///
34 | /// - parameter image: Image which will be modified by `self`
35 | ///
36 | /// - returns: The modified image.
37 | ///
38 | /// - Note: The return value will be unmodified if modifying is not possible on
39 | /// the current platform.
40 | /// - Note: Most modifiers support UIImage or NSImage, but not CGImage.
41 | func modify(_ image: Image) -> Image
42 | }
43 |
44 | extension ImageModifier {
45 | func modify(_ image: Image?) -> Image? {
46 | guard let image = image else {
47 | return nil
48 | }
49 | return modify(image)
50 | }
51 | }
52 |
53 | typealias ModifierImp = ((Image) -> Image)
54 |
55 | fileprivate struct GeneralModifier: ImageModifier {
56 | let identifier: String
57 | let m: ModifierImp
58 | func modify(_ image: Image) -> Image {
59 | return m(image)
60 | }
61 | }
62 |
63 | /// The default modifier.
64 | /// Does nothing and returns the image it was given
65 | public struct DefaultImageModifier: ImageModifier {
66 |
67 | /// A default `DefaultImageModifier` which can be used everywhere.
68 | public static let `default` = DefaultImageModifier()
69 |
70 | /// Initialize a `DefaultImageModifier`
71 | private init() {}
72 |
73 | /// Modify an input `Image`.
74 | ///
75 | /// - parameter image: Image which will be modified by `self`
76 | ///
77 | /// - returns: The modified image.
78 | ///
79 | /// - Note: See documentation of `ImageModifier` protocol for more.
80 | public func modify(_ image: Image) -> Image {
81 | return image
82 | }
83 | }
84 |
85 | /// A custom modifier.
86 | /// Can be initialized with a block to modify images in a custom way
87 | public struct AnyImageModifier: ImageModifier {
88 |
89 | /// A block which modifies images, or returns the original image
90 | /// if modification cannot be performed.
91 | let block: (Image) -> Image
92 |
93 | /// Initialize an `AnyImageModifier`
94 | public init(modify: @escaping (Image) -> Image) {
95 | block = modify
96 | }
97 |
98 | /// Modifies an input `Image` using this `AnyImageModifier`'s `block`.
99 | ///
100 | /// - parameter image: Image which will be modified by `self`
101 | ///
102 | /// - returns: The modified image.
103 | ///
104 | /// - Note: See documentation of `ImageModifier` protocol for more.
105 | public func modify(_ image: Image) -> Image {
106 | return block(image)
107 | }
108 | }
109 |
110 | #if os(iOS) || os(tvOS) || os(watchOS)
111 | import UIKit
112 |
113 | /// Modifier for setting the rendering mode of images.
114 | /// Only UI-based images are supported; if a non-UI image is passed in, the
115 | /// modifier will do nothing.
116 | public struct RenderingModeImageModifier: ImageModifier {
117 |
118 | /// The rendering mode to apply to the image.
119 | public let renderingMode: UIImage.RenderingMode
120 |
121 | /// Initialize a `RenderingModeImageModifier`
122 | ///
123 | /// - parameter renderingMode: The rendering mode to apply to the image.
124 | /// Default is .automatic
125 | public init(renderingMode: UIImage.RenderingMode = .automatic) {
126 | self.renderingMode = renderingMode
127 | }
128 |
129 | /// Modify an input `Image`.
130 | ///
131 | /// - parameter image: Image which will be modified by `self`
132 | ///
133 | /// - returns: The modified image.
134 | ///
135 | /// - Note: See documentation of `ImageModifier` protocol for more.
136 | public func modify(_ image: Image) -> Image {
137 | return image.withRenderingMode(renderingMode)
138 | }
139 | }
140 |
141 | /// Modifier for setting the `flipsForRightToLeftLayoutDirection` property of images.
142 | /// Only UI-based images are supported; if a non-UI image is passed in, the
143 | /// modifier will do nothing.
144 | public struct FlipsForRightToLeftLayoutDirectionImageModifier: ImageModifier {
145 | /// Initialize a `FlipsForRightToLeftLayoutDirectionImageModifier`
146 | ///
147 | /// - Note: On versions of iOS lower than 9.0, the image will be returned
148 | /// unmodified.
149 | public init() {}
150 |
151 | /// Modify an input `Image`.
152 | ///
153 | /// - parameter image: Image which will be modified by `self`
154 | ///
155 | /// - returns: The modified image.
156 | ///
157 | /// - Note: See documentation of `ImageModifier` protocol for more.
158 | public func modify(_ image: Image) -> Image {
159 | if #available(iOS 9.0, *) {
160 | return image.imageFlippedForRightToLeftLayoutDirection()
161 | } else {
162 | return image
163 | }
164 | }
165 | }
166 |
167 | /// Modifier for setting the `alignmentRectInsets` property of images.
168 | /// Only UI-based images are supported; if a non-UI image is passed in, the
169 | /// modifier will do nothing.
170 | public struct AlignmentRectInsetsImageModifier: ImageModifier {
171 |
172 | /// The alignment insets to apply to the image
173 | public let alignmentInsets: UIEdgeInsets
174 |
175 | /// Initialize a `AlignmentRectInsetsImageModifier`
176 | public init(alignmentInsets: UIEdgeInsets) {
177 | self.alignmentInsets = alignmentInsets
178 | }
179 |
180 | /// Modify an input `Image`.
181 | ///
182 | /// - parameter image: Image which will be modified by `self`
183 | ///
184 | /// - returns: The modified image.
185 | ///
186 | /// - Note: See documentation of `ImageModifier` protocol for more.
187 | public func modify(_ image: Image) -> Image {
188 | return image.withAlignmentRectInsets(alignmentInsets)
189 | }
190 | }
191 | #endif
192 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/ImageTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransition.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/9/18.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | // Not implemented for macOS and watchOS yet.
29 |
30 | import AppKit
31 |
32 | /// Image transition is not supported on macOS.
33 | public enum ImageTransition {
34 | case none
35 | var duration: TimeInterval {
36 | return 0
37 | }
38 | }
39 |
40 | #elseif os(watchOS)
41 | import UIKit
42 | /// Image transition is not supported on watchOS.
43 | public enum ImageTransition {
44 | case none
45 | var duration: TimeInterval {
46 | return 0
47 | }
48 | }
49 | #else
50 | import UIKit
51 |
52 | /**
53 | Transition effect which will be used when an image downloaded and set by `UIImageView` extension API in Kingfisher.
54 | You can assign an enum value with transition duration as an item in `KingfisherOptionsInfo`
55 | to enable the animation transition.
56 |
57 | Apple's UIViewAnimationOptions is used under the hood.
58 | For custom transition, you should specified your own transition options, animations and
59 | completion handler as well.
60 | */
61 | public enum ImageTransition {
62 | /// No animation transition.
63 | case none
64 |
65 | /// Fade in the loaded image.
66 | case fade(TimeInterval)
67 |
68 | /// Flip from left transition.
69 | case flipFromLeft(TimeInterval)
70 |
71 | /// Flip from right transition.
72 | case flipFromRight(TimeInterval)
73 |
74 | /// Flip from top transition.
75 | case flipFromTop(TimeInterval)
76 |
77 | /// Flip from bottom transition.
78 | case flipFromBottom(TimeInterval)
79 |
80 | /// Custom transition.
81 | case custom(duration: TimeInterval,
82 | options: UIView.AnimationOptions,
83 | animations: ((UIImageView, UIImage) -> Void)?,
84 | completion: ((Bool) -> Void)?)
85 |
86 | var duration: TimeInterval {
87 | switch self {
88 | case .none: return 0
89 | case .fade(let duration): return duration
90 |
91 | case .flipFromLeft(let duration): return duration
92 | case .flipFromRight(let duration): return duration
93 | case .flipFromTop(let duration): return duration
94 | case .flipFromBottom(let duration): return duration
95 |
96 | case .custom(let duration, _, _, _): return duration
97 | }
98 | }
99 |
100 | var animationOptions: UIView.AnimationOptions {
101 | switch self {
102 | case .none: return []
103 | case .fade(_): return .transitionCrossDissolve
104 |
105 | case .flipFromLeft(_): return .transitionFlipFromLeft
106 | case .flipFromRight(_): return .transitionFlipFromRight
107 | case .flipFromTop(_): return .transitionFlipFromTop
108 | case .flipFromBottom(_): return .transitionFlipFromBottom
109 |
110 | case .custom(_, let options, _, _): return options
111 | }
112 | }
113 |
114 | var animations: ((UIImageView, UIImage) -> Void)? {
115 | switch self {
116 | case .custom(_, _, let animations, _): return animations
117 | default: return { $0.image = $1 }
118 | }
119 | }
120 |
121 | var completion: ((Bool) -> Void)? {
122 | switch self {
123 | case .custom(_, _, _, let completion): return completion
124 | default: return nil
125 | }
126 | }
127 | }
128 | #endif
129 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/ImageView+Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageView+Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 |
28 | #if os(macOS)
29 | import AppKit
30 | #else
31 | import UIKit
32 | #endif
33 |
34 | // MARK: - Extension methods.
35 | /**
36 | * Set image to use from web.
37 | */
38 | extension Kingfisher where Base: ImageView {
39 | /**
40 | Set an image with a resource, a placeholder image, options, progress handler and completion handler.
41 |
42 | - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
43 | - parameter placeholder: A placeholder image when retrieving the image at URL.
44 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
45 | - parameter progressBlock: Called when the image downloading progress gets updated.
46 | - parameter completionHandler: Called when the image retrieved and set.
47 |
48 | - returns: A task represents the retrieving process.
49 |
50 | - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
51 | The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
52 |
53 | If `resource` is `nil`, the `placeholder` image will be set and
54 | `completionHandler` will be called with both `error` and `image` being `nil`.
55 | */
56 | @discardableResult
57 | public func setImage(with resource: Resource?,
58 | placeholder: Placeholder? = nil,
59 | options: KingfisherOptionsInfo? = nil,
60 | progressBlock: DownloadProgressBlock? = nil,
61 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
62 | {
63 | guard let resource = resource else {
64 | self.placeholder = placeholder
65 | setWebURL(nil)
66 | completionHandler?(nil, nil, .none, nil)
67 | return .empty
68 | }
69 |
70 | var options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
71 | let noImageOrPlaceholderSet = base.image == nil && self.placeholder == nil
72 |
73 | if !options.keepCurrentImageWhileLoading || noImageOrPlaceholderSet { // Always set placeholder while there is no image/placehoer yet.
74 | self.placeholder = placeholder
75 | }
76 |
77 | let maybeIndicator = indicator
78 | maybeIndicator?.startAnimatingView()
79 |
80 | setWebURL(resource.downloadURL)
81 |
82 | if base.shouldPreloadAllAnimation() {
83 | options.append(.preloadAllAnimationData)
84 | }
85 |
86 | let task = KingfisherManager.shared.retrieveImage(
87 | with: resource,
88 | options: options,
89 | progressBlock: { receivedSize, totalSize in
90 | guard resource.downloadURL == self.webURL else {
91 | return
92 | }
93 | if let progressBlock = progressBlock {
94 | progressBlock(receivedSize, totalSize)
95 | }
96 | },
97 | completionHandler: {[weak base] image, error, cacheType, imageURL in
98 | DispatchQueue.main.safeAsync {
99 | maybeIndicator?.stopAnimatingView()
100 | guard let strongBase = base, imageURL == self.webURL else {
101 | completionHandler?(image, error, cacheType, imageURL)
102 | return
103 | }
104 |
105 | self.setImageTask(nil)
106 | guard let image = image else {
107 | completionHandler?(nil, error, cacheType, imageURL)
108 | return
109 | }
110 |
111 | guard let transitionItem = options.lastMatchIgnoringAssociatedValue(.transition(.none)),
112 | case .transition(let transition) = transitionItem, ( options.forceTransition || cacheType == .none) else
113 | {
114 | self.placeholder = nil
115 | strongBase.image = image
116 | completionHandler?(image, error, cacheType, imageURL)
117 | return
118 | }
119 |
120 | #if !os(macOS)
121 | UIView.transition(with: strongBase, duration: 0.0, options: [],
122 | animations: { maybeIndicator?.stopAnimatingView() },
123 | completion: { _ in
124 |
125 | self.placeholder = nil
126 | UIView.transition(with: strongBase, duration: transition.duration,
127 | options: [transition.animationOptions, .allowUserInteraction],
128 | animations: {
129 | // Set image property in the animation.
130 | transition.animations?(strongBase, image)
131 | },
132 | completion: { finished in
133 | transition.completion?(finished)
134 | completionHandler?(image, error, cacheType, imageURL)
135 | })
136 | })
137 | #endif
138 | }
139 | })
140 |
141 | setImageTask(task)
142 |
143 | return task
144 | }
145 |
146 | /**
147 | Cancel the image download task bounded to the image view if it is running.
148 | Nothing will happen if the downloading has already finished.
149 | */
150 | public func cancelDownloadTask() {
151 | imageTask?.cancel()
152 | }
153 | }
154 |
155 | // MARK: - Associated Object
156 | private var lastURLKey: Void?
157 | private var indicatorKey: Void?
158 | private var indicatorTypeKey: Void?
159 | private var placeholderKey: Void?
160 | private var imageTaskKey: Void?
161 |
162 | extension Kingfisher where Base: ImageView {
163 | /// Get the image URL binded to this image view.
164 | public var webURL: URL? {
165 | return objc_getAssociatedObject(base, &lastURLKey) as? URL
166 | }
167 |
168 | fileprivate func setWebURL(_ url: URL?) {
169 | objc_setAssociatedObject(base, &lastURLKey, url, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
170 | }
171 |
172 | /// Holds which indicator type is going to be used.
173 | /// Default is .none, means no indicator will be shown.
174 | public var indicatorType: IndicatorType {
175 | get {
176 | let indicator = objc_getAssociatedObject(base, &indicatorTypeKey) as? IndicatorType
177 | return indicator ?? .none
178 | }
179 |
180 | set {
181 | switch newValue {
182 | case .none:
183 | indicator = nil
184 | case .activity:
185 | indicator = ActivityIndicator()
186 | case .image(let data):
187 | indicator = ImageIndicator(imageData: data)
188 | case .custom(let anIndicator):
189 | indicator = anIndicator
190 | }
191 |
192 | objc_setAssociatedObject(base, &indicatorTypeKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
193 | }
194 | }
195 |
196 | /// Holds any type that conforms to the protocol `Indicator`.
197 | /// The protocol `Indicator` has a `view` property that will be shown when loading an image.
198 | /// It will be `nil` if `indicatorType` is `.none`.
199 | public fileprivate(set) var indicator: Indicator? {
200 | get {
201 | guard let box = objc_getAssociatedObject(base, &indicatorKey) as? Box else {
202 | return nil
203 | }
204 | return box.value
205 | }
206 |
207 | set {
208 | // Remove previous
209 | if let previousIndicator = indicator {
210 | previousIndicator.view.removeFromSuperview()
211 | }
212 |
213 | // Add new
214 | if var newIndicator = newValue {
215 | // Set default indicator frame if the view's frame not set.
216 | if newIndicator.view.frame == .zero {
217 | newIndicator.view.frame = base.frame
218 | }
219 | newIndicator.viewCenter = CGPoint(x: base.bounds.midX, y: base.bounds.midY)
220 | newIndicator.view.isHidden = true
221 | base.addSubview(newIndicator.view)
222 | }
223 |
224 | // Save in associated object
225 | // Wrap newValue with Box to workaround an issue that Swift does not recognize
226 | // and casting protocol for associate object correctly. https://github.com/onevcat/Kingfisher/issues/872
227 | objc_setAssociatedObject(base, &indicatorKey, newValue.map(Box.init), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
228 | }
229 | }
230 |
231 | fileprivate var imageTask: RetrieveImageTask? {
232 | return objc_getAssociatedObject(base, &imageTaskKey) as? RetrieveImageTask
233 | }
234 |
235 | fileprivate func setImageTask(_ task: RetrieveImageTask?) {
236 | objc_setAssociatedObject(base, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
237 | }
238 |
239 | public fileprivate(set) var placeholder: Placeholder? {
240 | get {
241 | return objc_getAssociatedObject(base, &placeholderKey) as? Placeholder
242 | }
243 |
244 | set {
245 | if let previousPlaceholder = placeholder {
246 | previousPlaceholder.remove(from: base)
247 | }
248 |
249 | if let newPlaceholder = newValue {
250 | newPlaceholder.add(to: base)
251 | } else {
252 | base.image = nil
253 | }
254 |
255 | objc_setAssociatedObject(base, &placeholderKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
256 | }
257 | }
258 | }
259 |
260 |
261 | @objc extension ImageView {
262 | func shouldPreloadAllAnimation() -> Bool { return true }
263 | }
264 |
--------------------------------------------------------------------------------
/Example/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
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 | // Already 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 = UIActivityIndicatorView.Style.gray
137 | #endif
138 | activityIndicatorView = UIActivityIndicatorView(style: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 | }
200 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Kingfisher.h:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.h
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | #import
28 |
29 | //! Project version number for Kingfisher.
30 | FOUNDATION_EXPORT double KingfisherVersionNumber;
31 |
32 | //! Project version string for Kingfisher.
33 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
34 |
35 | // In this header, you should import all the public headers of your framework using statements like #import
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 16/9/14.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 | import ImageIO
29 |
30 | #if os(macOS)
31 | import AppKit
32 | public typealias Image = NSImage
33 | public typealias View = NSView
34 | public typealias Color = NSColor
35 | public typealias ImageView = NSImageView
36 | public typealias Button = NSButton
37 | #else
38 | import UIKit
39 | public typealias Image = UIImage
40 | public typealias Color = UIColor
41 | #if !os(watchOS)
42 | public typealias ImageView = UIImageView
43 | public typealias View = UIView
44 | public typealias Button = UIButton
45 | #else
46 | import WatchKit
47 | #endif
48 | #endif
49 |
50 | public final class Kingfisher {
51 | public let base: Base
52 | public init(_ base: Base) {
53 | self.base = base
54 | }
55 | }
56 |
57 | /**
58 | A type that has Kingfisher extensions.
59 | */
60 | public protocol KingfisherCompatible {
61 | associatedtype CompatibleType
62 | var kf: CompatibleType { get }
63 | }
64 |
65 | public extension KingfisherCompatible {
66 | public var kf: Kingfisher {
67 | return Kingfisher(self)
68 | }
69 | }
70 |
71 | extension Image: KingfisherCompatible { }
72 | #if !os(watchOS)
73 | extension ImageView: KingfisherCompatible { }
74 | extension Button: KingfisherCompatible { }
75 | #else
76 | extension WKInterfaceImage: KingfisherCompatible { }
77 | #endif
78 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Placeholder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Placeholder.swift
3 | // Kingfisher
4 | //
5 | // Created by Tieme van Veen on 28/08/2017.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | /// Represent a placeholder type which could be set while loading as well as
35 | /// loading finished without getting an image.
36 | public protocol Placeholder {
37 |
38 | /// How the placeholder should be added to a given image view.
39 | func add(to imageView: ImageView)
40 |
41 | /// How the placeholder should be removed from a given image view.
42 | func remove(from imageView: ImageView)
43 | }
44 |
45 | /// Default implementation of an image placeholder. The image will be set or
46 | /// reset directly for `image` property of the image view.
47 | extension Placeholder where Self: Image {
48 |
49 | /// How the placeholder should be added to a given image view.
50 | public func add(to imageView: ImageView) { imageView.image = self }
51 |
52 | /// How the placeholder should be removed from a given image view.
53 | public func remove(from imageView: ImageView) { imageView.image = nil }
54 | }
55 |
56 | extension Image: Placeholder {}
57 |
58 | /// Default implementation of an arbitrary view as placeholder. The view will be
59 | /// added as a subview when adding and be removed from its super view when removing.
60 | ///
61 | /// To use your customize View type as placeholder, simply let it conforming to
62 | /// `Placeholder` by `extension MyView: Placeholder {}`.
63 | extension Placeholder where Self: View {
64 |
65 | /// How the placeholder should be added to a given image view.
66 | public func add(to imageView: ImageView) {
67 | imageView.addSubview(self)
68 |
69 | self.translatesAutoresizingMaskIntoConstraints = false
70 | NSLayoutConstraint.activate([
71 | NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: imageView, attribute: .centerX, multiplier: 1, constant: 0),
72 | NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: imageView, attribute: .centerY, multiplier: 1, constant: 0),
73 | NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: imageView, attribute: .height, multiplier: 1, constant: 0),
74 | NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: imageView, attribute: .width, multiplier: 1, constant: 0)
75 | ])
76 | }
77 |
78 | /// How the placeholder should be removed from a given image view.
79 | public func remove(from imageView: ImageView) {
80 | self.removeFromSuperview()
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/RequestModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/05.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 |
29 | /// Request modifier of image downloader.
30 | public protocol ImageDownloadRequestModifier {
31 | func modified(for request: URLRequest) -> URLRequest?
32 | }
33 |
34 | struct NoModifier: ImageDownloadRequestModifier {
35 | static let `default` = NoModifier()
36 | private init() {}
37 | func modified(for request: URLRequest) -> URLRequest? {
38 | return request
39 | }
40 | }
41 |
42 | public struct AnyModifier: ImageDownloadRequestModifier {
43 |
44 | let block: (URLRequest) -> URLRequest?
45 |
46 | public func modified(for request: URLRequest) -> URLRequest? {
47 | return block(request)
48 | }
49 |
50 | public init(modify: @escaping (URLRequest) -> URLRequest? ) {
51 | block = modify
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/Resource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Resource.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 |
29 |
30 | /// `Resource` protocol defines how to download and cache a resource from network.
31 | public protocol Resource {
32 | /// The key used in cache.
33 | var cacheKey: String { get }
34 |
35 | /// The target image URL.
36 | var downloadURL: URL { get }
37 | }
38 |
39 | /**
40 | ImageResource is a simple combination of `downloadURL` and `cacheKey`.
41 |
42 | When passed to image view set methods, Kingfisher will try to download the target
43 | image from the `downloadURL`, and then store it with the `cacheKey` as the key in cache.
44 | */
45 | public struct ImageResource: Resource {
46 | /// The key used in cache.
47 | public let cacheKey: String
48 |
49 | /// The target image URL.
50 | public let downloadURL: URL
51 |
52 | /**
53 | Create a resource.
54 |
55 | - parameter downloadURL: The target image URL.
56 | - parameter cacheKey: The cache key. If `nil`, Kingfisher will use the `absoluteString` of `downloadURL` as the key.
57 |
58 | - returns: A resource.
59 | */
60 | public init(downloadURL: URL, cacheKey: String? = nil) {
61 | self.downloadURL = downloadURL
62 | self.cacheKey = cacheKey ?? downloadURL.absoluteString
63 | }
64 | }
65 |
66 | /**
67 | URL conforms to `Resource` in Kingfisher.
68 | The `absoluteString` of this URL is used as `cacheKey`. And the URL itself will be used as `downloadURL`.
69 | If you need customize the url and/or cache key, use `ImageResource` instead.
70 | */
71 | extension URL: Resource {
72 | public var cacheKey: String { return absoluteString }
73 | public var downloadURL: URL { return self }
74 | }
75 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/String+MD5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+MD5.swift
3 | // Kingfisher
4 | //
5 | // To date, adding CommonCrypto to a Swift framework is problematic. See:
6 | // http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework
7 | // We're using a subset and modified version of CryptoSwift as an alternative.
8 | // The following is an altered source version that only includes MD5. The original software can be found at:
9 | // https://github.com/krzyzanowskim/CryptoSwift
10 | // This is the original copyright notice:
11 |
12 | /*
13 | Copyright (C) 2014 Marcin Krzyżanowski
14 | This software is provided 'as-is', without any express or implied warranty.
15 | In no event will the authors be held liable for any damages arising from the use of this software.
16 | Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
17 | - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
18 | - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
19 | - This notice may not be removed or altered from any source or binary distribution.
20 | */
21 |
22 | import Foundation
23 |
24 | public struct StringProxy {
25 | fileprivate let base: String
26 | init(proxy: String) {
27 | base = proxy
28 | }
29 | }
30 |
31 | extension String: KingfisherCompatible {
32 | public typealias CompatibleType = StringProxy
33 | public var kf: CompatibleType {
34 | return StringProxy(proxy: self)
35 | }
36 | }
37 |
38 | extension StringProxy {
39 | var md5: String {
40 | if let data = base.data(using: .utf8, allowLossyConversion: true) {
41 |
42 | let message = data.withUnsafeBytes { bytes -> [UInt8] in
43 | return Array(UnsafeBufferPointer(start: bytes, count: data.count))
44 | }
45 |
46 | let MD5Calculator = MD5(message)
47 | let MD5Data = MD5Calculator.calculate()
48 |
49 | var MD5String = String()
50 | for c in MD5Data {
51 | MD5String += String(format: "%02x", c)
52 | }
53 | return MD5String
54 |
55 | } else {
56 | return base
57 | }
58 | }
59 | }
60 |
61 |
62 | /** array of bytes, little-endian representation */
63 | func arrayOfBytes(_ value: T, length: Int? = nil) -> [UInt8] {
64 | let totalBytes = length ?? (MemoryLayout.size * 8)
65 |
66 | let valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
67 | valuePointer.pointee = value
68 |
69 | let bytes = valuePointer.withMemoryRebound(to: UInt8.self, capacity: totalBytes) { (bytesPointer) -> [UInt8] in
70 | var bytes = [UInt8](repeating: 0, count: totalBytes)
71 | for j in 0...size, totalBytes) {
72 | bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
73 | }
74 | return bytes
75 | }
76 |
77 | #if swift(>=4.1)
78 | valuePointer.deinitialize(count: 1)
79 | valuePointer.deallocate()
80 | #else
81 | valuePointer.deinitialize()
82 | valuePointer.deallocate(capacity: 1)
83 | #endif
84 |
85 | return bytes
86 | }
87 |
88 | extension Int {
89 | /** Array of bytes with optional padding (little-endian) */
90 | func bytes(_ totalBytes: Int = MemoryLayout.size) -> [UInt8] {
91 | return arrayOfBytes(self, length: totalBytes)
92 | }
93 |
94 | }
95 |
96 | extension NSMutableData {
97 |
98 | /** Convenient way to append bytes */
99 | func appendBytes(_ arrayOfBytes: [UInt8]) {
100 | append(arrayOfBytes, length: arrayOfBytes.count)
101 | }
102 |
103 | }
104 |
105 | protocol HashProtocol {
106 | var message: Array { get }
107 |
108 | /** Common part for hash calculation. Prepare header data. */
109 | func prepare(_ len: Int) -> Array
110 | }
111 |
112 | extension HashProtocol {
113 |
114 | func prepare(_ len: Int) -> Array {
115 | var tmpMessage = message
116 |
117 | // Step 1. Append Padding Bits
118 | tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message
119 |
120 | // append "0" bit until message length in bits ≡ 448 (mod 512)
121 | var msgLength = tmpMessage.count
122 | var counter = 0
123 |
124 | while msgLength % len != (len - 8) {
125 | counter += 1
126 | msgLength += 1
127 | }
128 |
129 | tmpMessage += Array(repeating: 0, count: counter)
130 | return tmpMessage
131 | }
132 | }
133 |
134 | func toUInt32Array(_ slice: ArraySlice) -> Array {
135 | var result = Array()
136 | result.reserveCapacity(16)
137 |
138 | for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout.size) {
139 | let d0 = UInt32(slice[idx.advanced(by: 3)]) << 24
140 | let d1 = UInt32(slice[idx.advanced(by: 2)]) << 16
141 | let d2 = UInt32(slice[idx.advanced(by: 1)]) << 8
142 | let d3 = UInt32(slice[idx])
143 | let val: UInt32 = d0 | d1 | d2 | d3
144 |
145 | result.append(val)
146 | }
147 | return result
148 | }
149 |
150 | struct BytesIterator: IteratorProtocol {
151 |
152 | let chunkSize: Int
153 | let data: [UInt8]
154 |
155 | init(chunkSize: Int, data: [UInt8]) {
156 | self.chunkSize = chunkSize
157 | self.data = data
158 | }
159 |
160 | var offset = 0
161 |
162 | mutating func next() -> ArraySlice? {
163 | let end = min(chunkSize, data.count - offset)
164 | let result = data[offset.. 0 ? result : nil
167 | }
168 | }
169 |
170 | struct BytesSequence: Sequence {
171 | let chunkSize: Int
172 | let data: [UInt8]
173 |
174 | func makeIterator() -> BytesIterator {
175 | return BytesIterator(chunkSize: chunkSize, data: data)
176 | }
177 | }
178 |
179 | func rotateLeft(_ value: UInt32, bits: UInt32) -> UInt32 {
180 | return ((value << bits) & 0xFFFFFFFF) | (value >> (32 - bits))
181 | }
182 |
183 | class MD5: HashProtocol {
184 |
185 | static let size = 16 // 128 / 8
186 | let message: [UInt8]
187 |
188 | init (_ message: [UInt8]) {
189 | self.message = message
190 | }
191 |
192 | /** specifies the per-round shift amounts */
193 | private let shifts: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
194 | 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
195 | 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
196 | 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
197 |
198 | /** binary integer part of the sines of integers (Radians) */
199 | private let sines: [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
200 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
201 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
202 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
203 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
204 | 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
205 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
206 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
207 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
208 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
209 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
210 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
211 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
212 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
213 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
214 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391]
215 |
216 | private let hashes: [UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
217 |
218 | func calculate() -> [UInt8] {
219 | var tmpMessage = prepare(64)
220 | tmpMessage.reserveCapacity(tmpMessage.count + 4)
221 |
222 | // hash values
223 | var hh = hashes
224 |
225 | // Step 2. Append Length a 64-bit representation of lengthInBits
226 | let lengthInBits = (message.count * 8)
227 | let lengthBytes = lengthInBits.bytes(64 / 8)
228 | tmpMessage += lengthBytes.reversed()
229 |
230 | // Process the message in successive 512-bit chunks:
231 | let chunkSizeBytes = 512 / 8 // 64
232 |
233 | for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
234 | // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
235 | var M = toUInt32Array(chunk)
236 | assert(M.count == 16, "Invalid array")
237 |
238 | // Initialize hash value for this chunk:
239 | var A: UInt32 = hh[0]
240 | var B: UInt32 = hh[1]
241 | var C: UInt32 = hh[2]
242 | var D: UInt32 = hh[3]
243 |
244 | var dTemp: UInt32 = 0
245 |
246 | // Main loop
247 | for j in 0 ..< sines.count {
248 | var g = 0
249 | var F: UInt32 = 0
250 |
251 | switch j {
252 | case 0...15:
253 | F = (B & C) | ((~B) & D)
254 | g = j
255 | break
256 | case 16...31:
257 | F = (D & B) | (~D & C)
258 | g = (5 * j + 1) % 16
259 | break
260 | case 32...47:
261 | F = B ^ C ^ D
262 | g = (3 * j + 5) % 16
263 | break
264 | case 48...63:
265 | F = C ^ (B | (~D))
266 | g = (7 * j) % 16
267 | break
268 | default:
269 | break
270 | }
271 | dTemp = D
272 | D = C
273 | C = B
274 | B = B &+ rotateLeft((A &+ F &+ sines[j] &+ M[g]), bits: shifts[j])
275 | A = dTemp
276 | }
277 |
278 | hh[0] = hh[0] &+ A
279 | hh[1] = hh[1] &+ B
280 | hh[2] = hh[2] &+ C
281 | hh[3] = hh[3] &+ D
282 | }
283 |
284 | var result = [UInt8]()
285 | result.reserveCapacity(hh.count / 4)
286 |
287 | hh.forEach {
288 | let itemLE = $0.littleEndian
289 | let r1 = UInt8(itemLE & 0xff)
290 | let r2 = UInt8((itemLE >> 8) & 0xff)
291 | let r3 = UInt8((itemLE >> 16) & 0xff)
292 | let r4 = UInt8((itemLE >> 24) & 0xff)
293 | result += [r1, r2, r3, r4]
294 | }
295 | return result
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/ThreadHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreadHelper.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/10/9.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import Foundation
28 |
29 | extension DispatchQueue {
30 | // This method will dispatch the `block` to self.
31 | // If `self` is the main queue, and current thread is main thread, the block
32 | // will be invoked immediately instead of being dispatched.
33 | func safeAsync(_ block: @escaping ()->()) {
34 | if self === DispatchQueue.main && Thread.isMainThread {
35 | block()
36 | } else {
37 | async { block() }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Example/Pods/Kingfisher/Sources/UIButton+Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/13.
6 | //
7 | // Copyright (c) 2018 Wei Wang
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 | import UIKit
28 |
29 | // MARK: - Set Images
30 | /**
31 | * Set image to use in button from web for a specified state.
32 | */
33 | extension Kingfisher where Base: UIButton {
34 | /**
35 | Set an image to use for a specified state with a resource, a placeholder image, options, progress handler and
36 | completion handler.
37 |
38 | - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
39 | - parameter state: The state that uses the specified image.
40 | - parameter placeholder: A placeholder image when retrieving the image at URL.
41 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
42 | - parameter progressBlock: Called when the image downloading progress gets updated.
43 | - parameter completionHandler: Called when the image retrieved and set.
44 |
45 | - returns: A task represents the retrieving process.
46 |
47 | - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
48 | The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
49 |
50 | If `resource` is `nil`, the `placeholder` image will be set and
51 | `completionHandler` will be called with both `error` and `image` being `nil`.
52 | */
53 | @discardableResult
54 | public func setImage(with resource: Resource?,
55 | for state: UIControl.State,
56 | placeholder: UIImage? = nil,
57 | options: KingfisherOptionsInfo? = nil,
58 | progressBlock: DownloadProgressBlock? = nil,
59 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
60 | {
61 | guard let resource = resource else {
62 | base.setImage(placeholder, for: state)
63 | setWebURL(nil, for: state)
64 | completionHandler?(nil, nil, .none, nil)
65 | return .empty
66 | }
67 |
68 | let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
69 | if !options.keepCurrentImageWhileLoading {
70 | base.setImage(placeholder, for: state)
71 | }
72 |
73 | setWebURL(resource.downloadURL, for: state)
74 | let task = KingfisherManager.shared.retrieveImage(
75 | with: resource,
76 | options: options,
77 | progressBlock: { receivedSize, totalSize in
78 | guard resource.downloadURL == self.webURL(for: state) else {
79 | return
80 | }
81 | if let progressBlock = progressBlock {
82 | progressBlock(receivedSize, totalSize)
83 | }
84 | },
85 | completionHandler: {[weak base] image, error, cacheType, imageURL in
86 | DispatchQueue.main.safeAsync {
87 | guard let strongBase = base, imageURL == self.webURL(for: state) else {
88 | completionHandler?(image, error, cacheType, imageURL)
89 | return
90 | }
91 | self.setImageTask(nil)
92 | if image != nil {
93 | strongBase.setImage(image, for: state)
94 | }
95 |
96 | completionHandler?(image, error, cacheType, imageURL)
97 | }
98 | })
99 |
100 | setImageTask(task)
101 | return task
102 | }
103 |
104 | /**
105 | Cancel the image download task bounded to the image view if it is running.
106 | Nothing will happen if the downloading has already finished.
107 | */
108 | public func cancelImageDownloadTask() {
109 | imageTask?.cancel()
110 | }
111 |
112 | /**
113 | Set the background image to use for a specified state with a resource,
114 | a placeholder image, options progress handler and completion handler.
115 |
116 | - parameter resource: Resource object contains information such as `cacheKey` and `downloadURL`.
117 | - parameter state: The state that uses the specified image.
118 | - parameter placeholder: A placeholder image when retrieving the image at URL.
119 | - parameter options: A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
120 | - parameter progressBlock: Called when the image downloading progress gets updated.
121 | - parameter completionHandler: Called when the image retrieved and set.
122 |
123 | - returns: A task represents the retrieving process.
124 |
125 | - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
126 | The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
127 |
128 | If `resource` is `nil`, the `placeholder` image will be set and
129 | `completionHandler` will be called with both `error` and `image` being `nil`.
130 | */
131 | @discardableResult
132 | public func setBackgroundImage(with resource: Resource?,
133 | for state: UIControl.State,
134 | placeholder: UIImage? = nil,
135 | options: KingfisherOptionsInfo? = nil,
136 | progressBlock: DownloadProgressBlock? = nil,
137 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
138 | {
139 | guard let resource = resource else {
140 | base.setBackgroundImage(placeholder, for: state)
141 | setBackgroundWebURL(nil, for: state)
142 | completionHandler?(nil, nil, .none, nil)
143 | return .empty
144 | }
145 |
146 | let options = KingfisherManager.shared.defaultOptions + (options ?? KingfisherEmptyOptionsInfo)
147 | if !options.keepCurrentImageWhileLoading {
148 | base.setBackgroundImage(placeholder, for: state)
149 | }
150 |
151 | setBackgroundWebURL(resource.downloadURL, for: state)
152 | let task = KingfisherManager.shared.retrieveImage(
153 | with: resource,
154 | options: options,
155 | progressBlock: { receivedSize, totalSize in
156 | guard resource.downloadURL == self.backgroundWebURL(for: state) else {
157 | return
158 | }
159 | if let progressBlock = progressBlock {
160 | progressBlock(receivedSize, totalSize)
161 | }
162 | },
163 | completionHandler: { [weak base] image, error, cacheType, imageURL in
164 | DispatchQueue.main.safeAsync {
165 | guard let strongBase = base, imageURL == self.backgroundWebURL(for: state) else {
166 | completionHandler?(image, error, cacheType, imageURL)
167 | return
168 | }
169 | self.setBackgroundImageTask(nil)
170 | if image != nil {
171 | strongBase.setBackgroundImage(image, for: state)
172 | }
173 | completionHandler?(image, error, cacheType, imageURL)
174 | }
175 | })
176 |
177 | setBackgroundImageTask(task)
178 | return task
179 | }
180 |
181 | /**
182 | Cancel the background image download task bounded to the image view if it is running.
183 | Nothing will happen if the downloading has already finished.
184 | */
185 | public func cancelBackgroundImageDownloadTask() {
186 | backgroundImageTask?.cancel()
187 | }
188 |
189 | }
190 |
191 | // MARK: - Associated Object
192 | private var lastURLKey: Void?
193 | private var imageTaskKey: Void?
194 |
195 | extension Kingfisher where Base: UIButton {
196 | /**
197 | Get the image URL binded to this button for a specified state.
198 |
199 | - parameter state: The state that uses the specified image.
200 |
201 | - returns: Current URL for image.
202 | */
203 | public func webURL(for state: UIControl.State) -> URL? {
204 | return webURLs[NSNumber(value:state.rawValue)] as? URL
205 | }
206 |
207 | fileprivate func setWebURL(_ url: URL?, for state: UIControl.State) {
208 | webURLs[NSNumber(value:state.rawValue)] = url
209 | }
210 |
211 | fileprivate var webURLs: NSMutableDictionary {
212 | var dictionary = objc_getAssociatedObject(base, &lastURLKey) as? NSMutableDictionary
213 | if dictionary == nil {
214 | dictionary = NSMutableDictionary()
215 | setWebURLs(dictionary!)
216 | }
217 | return dictionary!
218 | }
219 |
220 | fileprivate func setWebURLs(_ URLs: NSMutableDictionary) {
221 | objc_setAssociatedObject(base, &lastURLKey, URLs, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
222 | }
223 |
224 | fileprivate var imageTask: RetrieveImageTask? {
225 | return objc_getAssociatedObject(base, &imageTaskKey) as? RetrieveImageTask
226 | }
227 |
228 | fileprivate func setImageTask(_ task: RetrieveImageTask?) {
229 | objc_setAssociatedObject(base, &imageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
230 | }
231 | }
232 |
233 |
234 | private var lastBackgroundURLKey: Void?
235 | private var backgroundImageTaskKey: Void?
236 |
237 |
238 | extension Kingfisher where Base: UIButton {
239 | /**
240 | Get the background image URL binded to this button for a specified state.
241 |
242 | - parameter state: The state that uses the specified background image.
243 |
244 | - returns: Current URL for background image.
245 | */
246 | public func backgroundWebURL(for state: UIControl.State) -> URL? {
247 | return backgroundWebURLs[NSNumber(value:state.rawValue)] as? URL
248 | }
249 |
250 | fileprivate func setBackgroundWebURL(_ url: URL?, for state: UIControl.State) {
251 | backgroundWebURLs[NSNumber(value:state.rawValue)] = url
252 | }
253 |
254 | fileprivate var backgroundWebURLs: NSMutableDictionary {
255 | var dictionary = objc_getAssociatedObject(base, &lastBackgroundURLKey) as? NSMutableDictionary
256 | if dictionary == nil {
257 | dictionary = NSMutableDictionary()
258 | setBackgroundWebURLs(dictionary!)
259 | }
260 | return dictionary!
261 | }
262 |
263 | fileprivate func setBackgroundWebURLs(_ URLs: NSMutableDictionary) {
264 | objc_setAssociatedObject(base, &lastBackgroundURLKey, URLs, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
265 | }
266 |
267 | fileprivate var backgroundImageTask: RetrieveImageTask? {
268 | return objc_getAssociatedObject(base, &backgroundImageTaskKey) as? RetrieveImageTask
269 | }
270 |
271 | fileprivate func setBackgroundImageTask(_ task: RetrieveImageTask?) {
272 | objc_setAssociatedObject(base, &backgroundImageTaskKey, task, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/KFImageViewer.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "KFImageViewer",
3 | "version": "1.0.0",
4 | "summary": "KFImageViewer written in Swift with download progress, circular scrolling, timer and full screen viewer",
5 | "description": "KFImageViewer is a Kingfisher supported Swift library providing customizable image viewer with download progress, circular scrolling, timer and full screen viewer and extendable image source.",
6 | "homepage": "https://github.com/faisalazeez/KFImageViewer",
7 | "swift_version": "4.0",
8 | "license": {
9 | "type": "MIT",
10 | "file": "LICENSE"
11 | },
12 | "authors": {
13 | "faisalazeez": "faisalazeez7@gmail.com"
14 | },
15 | "source": {
16 | "git": "https://github.com/faisalazeez/KFImageViewer.git",
17 | "tag": "1.0.0"
18 | },
19 | "platforms": {
20 | "ios": "9.0"
21 | },
22 | "requires_arc": true,
23 | "default_subspecs": "Core",
24 | "subspecs": [
25 | {
26 | "name": "Core",
27 | "source_files": "Core/**/*",
28 | "resources": "Core/Resources/*.png"
29 | },
30 | {
31 | "name": "Kingfisher",
32 | "dependencies": {
33 | "KFImageViewer/Core": [
34 |
35 | ],
36 | "Kingfisher": [
37 | "> 4.0"
38 | ]
39 | },
40 | "source_files": "Kingfisher/KingfisherSource.swift"
41 | }
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - KFImageViewer (1.0.0):
3 | - KFImageViewer/Core (= 1.0.0)
4 | - KFImageViewer/Core (1.0.0)
5 | - KFImageViewer/Kingfisher (1.0.0):
6 | - KFImageViewer/Core
7 | - Kingfisher (> 4.0)
8 | - Kingfisher (4.8.0)
9 |
10 | DEPENDENCIES:
11 | - KFImageViewer (from `../`)
12 | - KFImageViewer/Kingfisher (from `../`)
13 |
14 | SPEC REPOS:
15 | https://github.com/cocoapods/specs.git:
16 | - Kingfisher
17 |
18 | EXTERNAL SOURCES:
19 | KFImageViewer:
20 | :path: "../"
21 |
22 | SPEC CHECKSUMS:
23 | KFImageViewer: 98e9bbf8eb8547cbe068501675b95d8e14c5658a
24 | Kingfisher: 976d828df2b24834c6a3f2fc4d82cdbd26552be1
25 |
26 | PODFILE CHECKSUM: ec48d017d47cd4da82807056131dfeea12515cee
27 |
28 | COCOAPODS: 1.5.3
29 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/KFImageViewer-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_KFImageViewer : NSObject
3 | @end
4 | @implementation PodsDummy_KFImageViewer
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/KFImageViewer-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/KFImageViewer-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double KFImageViewerVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char KFImageViewerVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/KFImageViewer.modulemap:
--------------------------------------------------------------------------------
1 | framework module KFImageViewer {
2 | umbrella header "KFImageViewer-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/KFImageViewer/KFImageViewer.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 4.8.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Kingfisher : NSObject
3 | @end
4 | @implementation PodsDummy_Kingfisher
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "Kingfisher.h"
14 |
15 | FOUNDATION_EXPORT double KingfisherVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Kingfisher.modulemap:
--------------------------------------------------------------------------------
1 | framework module Kingfisher {
2 | umbrella header "Kingfisher-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Kingfisher/Kingfisher.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_LDFLAGS = -framework "CFNetwork"
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## KFImageViewer
5 |
6 | Copyright (c) 2018 faisalazeez
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 |
27 | ## Kingfisher
28 |
29 | The MIT License (MIT)
30 |
31 | Copyright (c) 2018 Wei Wang
32 |
33 | Permission is hereby granted, free of charge, to any person obtaining a copy
34 | of this software and associated documentation files (the "Software"), to deal
35 | in the Software without restriction, including without limitation the rights
36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37 | copies of the Software, and to permit persons to whom the Software is
38 | furnished to do so, subject to the following conditions:
39 |
40 | The above copyright notice and this permission notice shall be included in all
41 | copies or substantial portions of the Software.
42 |
43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49 | SOFTWARE.
50 |
51 |
52 | Generated by CocoaPods - https://cocoapods.org
53 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2018 faisalazeez <faisal.azeez@msisoft.in>
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | KFImageViewer
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | The MIT License (MIT)
47 |
48 | Copyright (c) 2018 Wei Wang
49 |
50 | Permission is hereby granted, free of charge, to any person obtaining a copy
51 | of this software and associated documentation files (the "Software"), to deal
52 | in the Software without restriction, including without limitation the rights
53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54 | copies of the Software, and to permit persons to whom the Software is
55 | furnished to do so, subject to the following conditions:
56 |
57 | The above copyright notice and this permission notice shall be included in all
58 | copies or substantial portions of the Software.
59 |
60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66 | SOFTWARE.
67 |
68 |
69 | License
70 | MIT
71 | Title
72 | Kingfisher
73 | Type
74 | PSGroupSpecifier
75 |
76 |
77 | FooterText
78 | Generated by CocoaPods - https://cocoapods.org
79 | Title
80 |
81 | Type
82 | PSGroupSpecifier
83 |
84 |
85 | StringsTable
86 | Acknowledgements
87 | Title
88 | Acknowledgements
89 |
90 |
91 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_KFImageViewer_Example : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_KFImageViewer_Example
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # frameworks to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
14 |
15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
17 |
18 | # Used as a return value for each invocation of `strip_invalid_archs` function.
19 | STRIP_BINARY_RETVAL=0
20 |
21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
24 |
25 | # Copies and strips a vendored framework
26 | install_framework()
27 | {
28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
29 | local source="${BUILT_PRODUCTS_DIR}/$1"
30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
32 | elif [ -r "$1" ]; then
33 | local source="$1"
34 | fi
35 |
36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
37 |
38 | if [ -L "${source}" ]; then
39 | echo "Symlinked..."
40 | source="$(readlink "${source}")"
41 | fi
42 |
43 | # Use filter instead of exclude so missing patterns don't throw errors.
44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
46 |
47 | local basename
48 | basename="$(basename -s .framework "$1")"
49 | binary="${destination}/${basename}.framework/${basename}"
50 | if ! [ -r "$binary" ]; then
51 | binary="${destination}/${basename}"
52 | fi
53 |
54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
56 | strip_invalid_archs "$binary"
57 | fi
58 |
59 | # Resign the code if required by the build settings to avoid unstable apps
60 | code_sign_if_enabled "${destination}/$(basename "$1")"
61 |
62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
64 | local swift_runtime_libs
65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
66 | for lib in $swift_runtime_libs; do
67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
69 | code_sign_if_enabled "${destination}/${lib}"
70 | done
71 | fi
72 | }
73 |
74 | # Copies and strips a vendored dSYM
75 | install_dsym() {
76 | local source="$1"
77 | if [ -r "$source" ]; then
78 | # Copy the dSYM into a the targets temp dir.
79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
81 |
82 | local basename
83 | basename="$(basename -s .framework.dSYM "$source")"
84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
85 |
86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
88 | strip_invalid_archs "$binary"
89 | fi
90 |
91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
92 | # Move the stripped file into its final destination.
93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
95 | else
96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
98 | fi
99 | fi
100 | }
101 |
102 | # Signs a framework with the provided identity
103 | code_sign_if_enabled() {
104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
105 | # Use the current code_sign_identitiy
106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
108 |
109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
110 | code_sign_cmd="$code_sign_cmd &"
111 | fi
112 | echo "$code_sign_cmd"
113 | eval "$code_sign_cmd"
114 | fi
115 | }
116 |
117 | # Strip invalid architectures
118 | strip_invalid_archs() {
119 | binary="$1"
120 | # Get architectures for current target binary
121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
122 | # Intersect them with the architectures we are building for
123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
124 | # If there are no archs supported by this binary then warn the user
125 | if [[ -z "$intersected_archs" ]]; then
126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
127 | STRIP_BINARY_RETVAL=0
128 | return
129 | fi
130 | stripped=""
131 | for arch in $binary_archs; do
132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
133 | # Strip non-valid architectures in-place
134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
135 | stripped="$stripped $arch"
136 | fi
137 | done
138 | if [[ "$stripped" ]]; then
139 | echo "Stripped $binary of architectures:$stripped"
140 | fi
141 | STRIP_BINARY_RETVAL=1
142 | }
143 |
144 |
145 | if [[ "$CONFIGURATION" == "Debug" ]]; then
146 | install_framework "${BUILT_PRODUCTS_DIR}/KFImageViewer/KFImageViewer.framework"
147 | install_framework "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework"
148 | fi
149 | if [[ "$CONFIGURATION" == "Release" ]]; then
150 | install_framework "${BUILT_PRODUCTS_DIR}/KFImageViewer/KFImageViewer.framework"
151 | install_framework "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework"
152 | fi
153 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
154 | wait
155 | fi
156 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # resources to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
13 |
14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
15 | > "$RESOURCES_TO_COPY"
16 |
17 | XCASSET_FILES=()
18 |
19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
22 |
23 | case "${TARGETED_DEVICE_FAMILY:-}" in
24 | 1,2)
25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
26 | ;;
27 | 1)
28 | TARGET_DEVICE_ARGS="--target-device iphone"
29 | ;;
30 | 2)
31 | TARGET_DEVICE_ARGS="--target-device ipad"
32 | ;;
33 | 3)
34 | TARGET_DEVICE_ARGS="--target-device tv"
35 | ;;
36 | 4)
37 | TARGET_DEVICE_ARGS="--target-device watch"
38 | ;;
39 | *)
40 | TARGET_DEVICE_ARGS="--target-device mac"
41 | ;;
42 | esac
43 |
44 | install_resource()
45 | {
46 | if [[ "$1" = /* ]] ; then
47 | RESOURCE_PATH="$1"
48 | else
49 | RESOURCE_PATH="${PODS_ROOT}/$1"
50 | fi
51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
52 | cat << EOM
53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
54 | EOM
55 | exit 1
56 | fi
57 | case $RESOURCE_PATH in
58 | *.storyboard)
59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
61 | ;;
62 | *.xib)
63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
65 | ;;
66 | *.framework)
67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
71 | ;;
72 | *.xcdatamodel)
73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
75 | ;;
76 | *.xcdatamodeld)
77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
79 | ;;
80 | *.xcmappingmodel)
81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
83 | ;;
84 | *.xcassets)
85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
87 | ;;
88 | *)
89 | echo "$RESOURCE_PATH" || true
90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
91 | ;;
92 | esac
93 | }
94 |
95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
100 | fi
101 | rm -f "$RESOURCES_TO_COPY"
102 |
103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
104 | then
105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
107 | while read line; do
108 | if [[ $line != "${PODS_ROOT}*" ]]; then
109 | XCASSET_FILES+=("$line")
110 | fi
111 | done <<<"$OTHER_XCASSETS"
112 |
113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
115 | else
116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
117 | fi
118 | fi
119 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_KFImageViewer_ExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_KFImageViewer_ExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer/KFImageViewer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "KFImageViewer" -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_KFImageViewer_Example {
2 | umbrella header "Pods-KFImageViewer_Example-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Example/Pods-KFImageViewer_Example.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer/KFImageViewer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "KFImageViewer" -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 | Generated by CocoaPods - https://cocoapods.org
4 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Generated by CocoaPods - https://cocoapods.org
18 | Title
19 |
20 | Type
21 | PSGroupSpecifier
22 |
23 |
24 | StringsTable
25 | Acknowledgements
26 | Title
27 | Acknowledgements
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_KFImageViewer_Tests : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_KFImageViewer_Tests
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # frameworks to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
14 |
15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
17 |
18 | # Used as a return value for each invocation of `strip_invalid_archs` function.
19 | STRIP_BINARY_RETVAL=0
20 |
21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
24 |
25 | # Copies and strips a vendored framework
26 | install_framework()
27 | {
28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
29 | local source="${BUILT_PRODUCTS_DIR}/$1"
30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
32 | elif [ -r "$1" ]; then
33 | local source="$1"
34 | fi
35 |
36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
37 |
38 | if [ -L "${source}" ]; then
39 | echo "Symlinked..."
40 | source="$(readlink "${source}")"
41 | fi
42 |
43 | # Use filter instead of exclude so missing patterns don't throw errors.
44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
46 |
47 | local basename
48 | basename="$(basename -s .framework "$1")"
49 | binary="${destination}/${basename}.framework/${basename}"
50 | if ! [ -r "$binary" ]; then
51 | binary="${destination}/${basename}"
52 | fi
53 |
54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
56 | strip_invalid_archs "$binary"
57 | fi
58 |
59 | # Resign the code if required by the build settings to avoid unstable apps
60 | code_sign_if_enabled "${destination}/$(basename "$1")"
61 |
62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
64 | local swift_runtime_libs
65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
66 | for lib in $swift_runtime_libs; do
67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
69 | code_sign_if_enabled "${destination}/${lib}"
70 | done
71 | fi
72 | }
73 |
74 | # Copies and strips a vendored dSYM
75 | install_dsym() {
76 | local source="$1"
77 | if [ -r "$source" ]; then
78 | # Copy the dSYM into a the targets temp dir.
79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
81 |
82 | local basename
83 | basename="$(basename -s .framework.dSYM "$source")"
84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
85 |
86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
88 | strip_invalid_archs "$binary"
89 | fi
90 |
91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
92 | # Move the stripped file into its final destination.
93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
95 | else
96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
98 | fi
99 | fi
100 | }
101 |
102 | # Signs a framework with the provided identity
103 | code_sign_if_enabled() {
104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
105 | # Use the current code_sign_identitiy
106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
108 |
109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
110 | code_sign_cmd="$code_sign_cmd &"
111 | fi
112 | echo "$code_sign_cmd"
113 | eval "$code_sign_cmd"
114 | fi
115 | }
116 |
117 | # Strip invalid architectures
118 | strip_invalid_archs() {
119 | binary="$1"
120 | # Get architectures for current target binary
121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
122 | # Intersect them with the architectures we are building for
123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
124 | # If there are no archs supported by this binary then warn the user
125 | if [[ -z "$intersected_archs" ]]; then
126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
127 | STRIP_BINARY_RETVAL=0
128 | return
129 | fi
130 | stripped=""
131 | for arch in $binary_archs; do
132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
133 | # Strip non-valid architectures in-place
134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
135 | stripped="$stripped $arch"
136 | fi
137 | done
138 | if [[ "$stripped" ]]; then
139 | echo "Stripped $binary of architectures:$stripped"
140 | fi
141 | STRIP_BINARY_RETVAL=1
142 | }
143 |
144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
145 | wait
146 | fi
147 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
8 | # resources to, so exit 0 (signalling the script phase was successful).
9 | exit 0
10 | fi
11 |
12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
13 |
14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
15 | > "$RESOURCES_TO_COPY"
16 |
17 | XCASSET_FILES=()
18 |
19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
22 |
23 | case "${TARGETED_DEVICE_FAMILY:-}" in
24 | 1,2)
25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
26 | ;;
27 | 1)
28 | TARGET_DEVICE_ARGS="--target-device iphone"
29 | ;;
30 | 2)
31 | TARGET_DEVICE_ARGS="--target-device ipad"
32 | ;;
33 | 3)
34 | TARGET_DEVICE_ARGS="--target-device tv"
35 | ;;
36 | 4)
37 | TARGET_DEVICE_ARGS="--target-device watch"
38 | ;;
39 | *)
40 | TARGET_DEVICE_ARGS="--target-device mac"
41 | ;;
42 | esac
43 |
44 | install_resource()
45 | {
46 | if [[ "$1" = /* ]] ; then
47 | RESOURCE_PATH="$1"
48 | else
49 | RESOURCE_PATH="${PODS_ROOT}/$1"
50 | fi
51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
52 | cat << EOM
53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
54 | EOM
55 | exit 1
56 | fi
57 | case $RESOURCE_PATH in
58 | *.storyboard)
59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
61 | ;;
62 | *.xib)
63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
65 | ;;
66 | *.framework)
67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
71 | ;;
72 | *.xcdatamodel)
73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
75 | ;;
76 | *.xcdatamodeld)
77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
79 | ;;
80 | *.xcmappingmodel)
81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
83 | ;;
84 | *.xcassets)
85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
87 | ;;
88 | *)
89 | echo "$RESOURCE_PATH" || true
90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
91 | ;;
92 | esac
93 | }
94 |
95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
100 | fi
101 | rm -f "$RESOURCES_TO_COPY"
102 |
103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
104 | then
105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
107 | while read line; do
108 | if [[ $line != "${PODS_ROOT}*" ]]; then
109 | XCASSET_FILES+=("$line")
110 | fi
111 | done <<<"$OTHER_XCASSETS"
112 |
113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
115 | else
116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
117 | fi
118 | fi
119 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_KFImageViewer_TestsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_KFImageViewer_TestsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests.debug.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer/KFImageViewer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_KFImageViewer_Tests {
2 | umbrella header "Pods-KFImageViewer_Tests-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-KFImageViewer_Tests/Pods-KFImageViewer_Tests.release.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/KFImageViewer/KFImageViewer.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import KFImageViewer
3 |
4 | class Tests: XCTestCase {
5 |
6 | override func setUp() {
7 | super.setUp()
8 | // Put setup code here. This method is called before the invocation of each test method in the class.
9 | }
10 |
11 | override func tearDown() {
12 | // Put teardown code here. This method is called after the invocation of each test method in the class.
13 | super.tearDown()
14 | }
15 |
16 | func testExample() {
17 | // This is an example of a functional test case.
18 | XCTAssert(true, "Pass")
19 | }
20 |
21 | func testPerformanceExample() {
22 | // This is an example of a performance test case.
23 | self.measure() {
24 | // Put the code you want to measure the time of here.
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/KFImageViewer.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint KFImageViewer.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = 'KFImageViewer'
11 | s.version = '1.0.0'
12 | s.summary = 'KFImageViewer written in Swift with download progress, circular scrolling, timer and full screen viewer'
13 |
14 | # This description is used to generate tags and improve search results.
15 | # * Think: What does it do? Why did you write it? What is the focus?
16 | # * Try to keep it short, snappy and to the point.
17 | # * Write the description between the DESC delimiters below.
18 | # * Finally, don't worry about the indent, CocoaPods strips it!
19 |
20 | s.description = <<-DESC
21 | KFImageViewer is a Kingfisher supported Swift library providing customizable image viewer with download progress, circular scrolling, timer and full screen viewer and extendable image source.
22 | DESC
23 |
24 | s.homepage = 'https://github.com/faisalazeez/KFImageViewer'
25 | s.swift_version = '4.0'
26 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
27 | s.license = { :type => 'MIT', :file => 'LICENSE' }
28 | s.author = { 'faisalazeez' => 'faisalazeez7@gmail.com' }
29 | s.source = { :git => 'https://github.com/faisalazeez/KFImageViewer.git', :tag => s.version.to_s }
30 | # s.social_media_url = 'https://twitter.com/'
31 |
32 | s.ios.deployment_target = '11.0'
33 |
34 | s.requires_arc = true
35 |
36 | s.subspec 'Core' do |core|
37 | core.source_files = 'Core/**/*'
38 | core.resources = 'Core/Resources/*.png'
39 | end
40 |
41 | s.subspec 'Kingfisher' do |subspec|
42 | subspec.dependency 'KFImageViewer/Core'
43 | subspec.dependency 'Kingfisher', '> 5.2'
44 | subspec.source_files = 'Kingfisher/KingfisherSource.swift'
45 | end
46 |
47 | s.default_subspec = 'Core'
48 | end
49 |
--------------------------------------------------------------------------------
/Kingfisher/KingfisherSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KingfisherSource.swift
3 | // KFImageViewer
4 | //
5 | // Created by feiin
6 | //
7 | //
8 |
9 | import Kingfisher
10 |
11 | /// Input Source to image using Kingfisher
12 | public class KingfisherSource: NSObject, InputSource {
13 | /// url to load
14 | public var url: URL
15 |
16 | /// placeholder used before image is loaded
17 | public var placeholder: UIImage?
18 |
19 | /// options for displaying, ie. [.transition(.fade(0.2))]
20 | public var options: KingfisherOptionsInfo?
21 |
22 | /// Initializes a new source with a URL
23 | /// - parameter url: a url to be loaded
24 | /// - parameter placeholder: a placeholder used before image is loaded
25 | /// - parameter options: options for displaying
26 | public init(url: URL, placeholder: UIImage? = nil, options: KingfisherOptionsInfo? = nil) {
27 | self.url = url
28 | self.placeholder = placeholder
29 | self.options = options
30 | super.init()
31 | }
32 |
33 | /// Initializes a new source with a URL string
34 | /// - parameter urlString: a string url to load
35 | /// - parameter placeholder: a placeholder used before image is loaded
36 | /// - parameter options: options for displaying
37 | public init?(urlString: String, placeholder: UIImage? = nil, options: KingfisherOptionsInfo? = nil) {
38 | if let validUrl = URL(string: urlString) {
39 | self.url = validUrl
40 | self.placeholder = placeholder
41 | self.options = options
42 | super.init()
43 | } else {
44 | return nil
45 | }
46 | }
47 |
48 | @objc public func load(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void) {
49 | imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock: nil) { (image, _, _, _) in
50 | callback(image)
51 | }
52 | }
53 |
54 | public func loadWithProgress(to imageView: UIImageView, with callback: @escaping (UIImage?) -> Void, progress: @escaping (CGFloat) -> Void) {
55 | imageView.kf.setImage(with: self.url, placeholder: self.placeholder, options: self.options, progressBlock:{
56 | (recieved,total)
57 | in
58 | progress((CGFloat(recieved)/CGFloat(total)))
59 | }) { (image, _, _, _) in
60 | callback(image)
61 | }
62 | }
63 |
64 | public func cancelLoad(on imageView: UIImageView) {
65 | imageView.kf.cancelDownloadTask()
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 faisalazeez
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'KFImageViewer' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for KFImageViewer
9 |
10 | end
11 |
12 | target 'Pods-KFImageViewer_Example' do
13 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
14 | use_frameworks!
15 |
16 | # Pods for Pods-KFImageViewer_Example
17 |
18 | end
19 |
20 | target 'Pods-KFImageViewer_Tests' do
21 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
22 | # use_frameworks!
23 |
24 | # Pods for Pods-KFImageViewer_Tests
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🖼 KFImageViewer
2 |
3 | **Customizable Kingfisher dependent Swift image slideshow with download progress, circular scrolling, timer and full screen viewer**
4 |
5 | 
6 | 
7 |
8 | ## 📱 Example
9 |
10 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
11 |
12 | ## 🔧 Installation
13 |
14 | ### CocoaPods
15 | KFImageViewer is available through [CocoaPods](http://cocoapods.org). To install
16 | it, simply add the following line to your Podfile:
17 |
18 | ```ruby
19 | pod 'KFImageViewer', '~> 1.0.0'
20 | ```
21 |
22 | ### Manually
23 |
24 | Alternatively can also grab the whole `KFImageViewer` directory and copy it to your project.
25 |
26 | ## 🔨 How to use
27 |
28 | Add KFImageViewer view to your view hiearchy either in Interface Builder or in code.
29 |
30 | ### Loading images
31 |
32 | Set images by using ```setImageInputs``` method on ```KFImageViewer``` instance with an array of *InputSource*s. You can also create your own input source by implementing ```InputSource``` protocol.
33 |
34 | | Library | InputSource name | Pod |
35 | | ------------------------------------------------------------- |:----------------:| ---------------------------------:|
36 | | [Kingfisher](https://github.com/onevcat/Kingfisher) | KingfisherSource | `pod "KFImageViewer/Kingfisher"` |
37 |
38 |
39 | ```swift
40 | slideshow.setImageInputs([
41 | KingfisherSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080"),
42 | ])
43 | ```
44 |
45 | ### Configuration
46 |
47 | Behaviour is configurable by those properties:
48 |
49 | - ```slideshowInterval``` - slideshow interval in seconds (default `0` – disabled)
50 | - ```zoomEnabled``` - enables zooming (default `false`)
51 | - ```circular``` - enables circular scrolling (default `true`)
52 | - ```activityIndicator``` – allows to set custom activity indicator, see *Activity indicator* section
53 | - ```pageIndicator``` – allows to set custom page indicator, see *Page indicator* section; assign `nil` to hide page indicator
54 | - ```pageIndicatorPosition``` - configures position of the page indicator
55 | - ```contentScaleMode``` - configures the scaling (default `ScaleAspectFit`)
56 | - ```draggingEnabled``` - enables dragging (default `true`)
57 | - ```currentPageChanged``` - closure called on page change
58 | - ```willBeginDragging``` - closure called on scrollViewWillBeginDragging
59 | - ```didEndDecelerating``` - closure called on scrollViewDidEndDecelerating
60 | - ```preload``` - image preloading configuration (default `all` preloading, also `fixed`)
61 |
62 | ### Page Indicator
63 |
64 | Page indicator can be customized using the `pageIndicator` property on KFImageViewer. By defualt, a plain UIPageControl is used. If needed, page control can be customized:
65 |
66 | ```swift
67 | let pageIndicator = UIPageControl()
68 | pageIndicator.currentPageIndicatorTintColor = UIColor.lightGray
69 | pageIndicator.pageIndicatorTintColor = UIColor.black
70 | slideshow.pageIndicator = pageIndicator
71 | ```
72 |
73 | Also, a simple label page indicator that shows pages in style "5/21" (fifth page from twenty one) is provided:
74 |
75 | ```swift
76 | slideshow.pageIndicator = LabelPageIndicator()
77 | ```
78 |
79 | You can also use your own page indicator by adopting the `PageIndicatorView` protocol.
80 |
81 | Position of the page indicator can be configured by assigning a `PageIndicatorPosition` value to the `pageIndicatorPosition` property on KFImageViewer. You may specify the horizontal and vertical positioning separately.
82 |
83 | **Horizontal** positioning options are: `.left(padding: Int)`, `.center`, `.right(padding: Int)`
84 |
85 | **Vertical** positioning options are: `.top`, `.bottom`, `.under`, `customTop(padding: Int)`, `customBottom(padding: Int)`, `customUnder(padding: Int)`
86 |
87 | Example:
88 | ```swift
89 | slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .left(padding: 20), vertical: .bottom)
90 | ```
91 |
92 |
93 | ### Activity Indicator
94 |
95 | By default activity indicator is not shown, but you can enable it by setting `DefaultActivityIndicator` instance to KFImageViewer :
96 |
97 | ```swift
98 | slideshow.activityIndicator = DefaultActivityIndicator()
99 | ```
100 |
101 | You can customize style and color of the indicator:
102 |
103 | ```swift
104 | slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
105 | ```
106 |
107 | There's also an option to use your own activity indicator. You just need to implement `ActivityIndicatorView` and `ActivityIndicatorFactory` protocols. See `ActivityIndicator.swift` for more information.
108 |
109 | ### Full Screen view
110 |
111 | There is also a possibility to open full-screen image view using attached `FullScreenSlideshowViewController`. The simplest way is to call:
112 |
113 | ```swift
114 | override func viewDidLoad() {
115 | let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.didTap))
116 | slideshow.addGestureRecognizer(gestureRecognizer)
117 | }
118 |
119 | func didTap() {
120 | slideshow.presentFullScreenController(from: self)
121 | }
122 | ```
123 |
124 | `FullScreenSlideshowViewController` can also be instantiated and configured manually if more advanced behavior is needed.
125 |
126 | ## 👤 Author
127 |
128 | Faisal Azeez faisalazeez7@gmail.com
129 |
130 | ## 📄 License
131 |
132 | KFImageViewer is available under the MIT license. See the LICENSE file for more info.
133 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------