├── LICENSE ├── PhotoBrowser.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── PhotoBrowser.xccheckout │ └── xcuserdata │ │ └── Charlin.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Charlin.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── PhotoBrowser.xcscheme │ └── xcschememanagement.plist ├── PhotoBrowser ├── AppDelegate.swift ├── DisplayVC+Host.swift ├── DisplayVC+Local.swift ├── DisplayVC.swift ├── DisplayView.swift ├── Frameworks │ ├── CFSnapKit │ │ ├── CFSnapKit.swift │ │ └── Source │ │ │ ├── Constraint.swift │ │ │ ├── ConstraintAttributes.swift │ │ │ ├── ConstraintConfig.swift │ │ │ ├── ConstraintConstantTarget.swift │ │ │ ├── ConstraintDSL.swift │ │ │ ├── ConstraintDescription.swift │ │ │ ├── ConstraintInsetTarget.swift │ │ │ ├── ConstraintInsets.swift │ │ │ ├── ConstraintItem.swift │ │ │ ├── ConstraintLayoutGuide+Extensions.swift │ │ │ ├── ConstraintLayoutGuide.swift │ │ │ ├── ConstraintLayoutGuideDSL.swift │ │ │ ├── ConstraintLayoutSupport.swift │ │ │ ├── ConstraintLayoutSupportDSL.swift │ │ │ ├── ConstraintMaker.swift │ │ │ ├── ConstraintMakerEditable.swift │ │ │ ├── ConstraintMakerExtendable.swift │ │ │ ├── ConstraintMakerFinalizable.swift │ │ │ ├── ConstraintMakerPriortizable.swift │ │ │ ├── ConstraintMakerRelatable.swift │ │ │ ├── ConstraintMultiplierTarget.swift │ │ │ ├── ConstraintOffsetTarget.swift │ │ │ ├── ConstraintPriority.swift │ │ │ ├── ConstraintPriorityTarget.swift │ │ │ ├── ConstraintRelatableTarget.swift │ │ │ ├── ConstraintRelation.swift │ │ │ ├── ConstraintView+Extensions.swift │ │ │ ├── ConstraintView.swift │ │ │ ├── ConstraintViewDSL.swift │ │ │ ├── Debugging.swift │ │ │ ├── Info.plist │ │ │ ├── LayoutConstraint.swift │ │ │ ├── LayoutConstraintItem.swift │ │ │ ├── SnapKit.h │ │ │ └── UILayoutSupport+Extensions.swift │ ├── Haneke │ │ ├── CGSize+Swift.swift │ │ ├── Cache.swift │ │ ├── CryptoSwiftMD5.swift │ │ ├── Data.swift │ │ ├── DiskCache.swift │ │ ├── DiskFetcher.swift │ │ ├── Fetch.swift │ │ ├── Fetcher.swift │ │ ├── Format.swift │ │ ├── Haneke.h │ │ ├── Haneke.swift │ │ ├── Info-iOS.plist │ │ ├── Info-tvOS.plist │ │ ├── Log.swift │ │ ├── NSFileManager+Haneke.swift │ │ ├── NSHTTPURLResponse+Haneke.swift │ │ ├── NSURLResponse+Haneke.swift │ │ ├── NetworkFetcher.swift │ │ ├── String+Haneke.swift │ │ ├── UIButton+Haneke.swift │ │ ├── UIImage+Haneke.swift │ │ ├── UIImageView+Haneke.swift │ │ └── UIView+Haneke.swift │ └── NVActivityIndicatorView │ │ ├── Animations │ │ ├── NVActivityIndicatorAnimationAudioEqualizer.swift │ │ ├── NVActivityIndicatorAnimationBallBeat.swift │ │ ├── NVActivityIndicatorAnimationBallClipRotate.swift │ │ ├── NVActivityIndicatorAnimationBallClipRotateMultiple.swift │ │ ├── NVActivityIndicatorAnimationBallClipRotatePulse.swift │ │ ├── NVActivityIndicatorAnimationBallGridBeat.swift │ │ ├── NVActivityIndicatorAnimationBallGridPulse.swift │ │ ├── NVActivityIndicatorAnimationBallPulse.swift │ │ ├── NVActivityIndicatorAnimationBallPulseRise.swift │ │ ├── NVActivityIndicatorAnimationBallPulseSync.swift │ │ ├── NVActivityIndicatorAnimationBallRotate.swift │ │ ├── NVActivityIndicatorAnimationBallRotateChase.swift │ │ ├── NVActivityIndicatorAnimationBallScale.swift │ │ ├── NVActivityIndicatorAnimationBallScaleMultiple.swift │ │ ├── NVActivityIndicatorAnimationBallScaleRipple.swift │ │ ├── NVActivityIndicatorAnimationBallScaleRippleMultiple.swift │ │ ├── NVActivityIndicatorAnimationBallSpinFadeLoader.swift │ │ ├── NVActivityIndicatorAnimationBallTrianglePath.swift │ │ ├── NVActivityIndicatorAnimationBallZigZag.swift │ │ ├── NVActivityIndicatorAnimationBallZigZagDeflect.swift │ │ ├── NVActivityIndicatorAnimationBlank.swift │ │ ├── NVActivityIndicatorAnimationCubeTransition.swift │ │ ├── NVActivityIndicatorAnimationLineScale.swift │ │ ├── NVActivityIndicatorAnimationLineScaleParty.swift │ │ ├── NVActivityIndicatorAnimationLineScalePulseOut.swift │ │ ├── NVActivityIndicatorAnimationLineScalePulseOutRapid.swift │ │ ├── NVActivityIndicatorAnimationLineSpinFadeLoader.swift │ │ ├── NVActivityIndicatorAnimationOrbit.swift │ │ ├── NVActivityIndicatorAnimationPacman.swift │ │ ├── NVActivityIndicatorAnimationSemiCircleSpin.swift │ │ ├── NVActivityIndicatorAnimationSquareSpin.swift │ │ └── NVActivityIndicatorAnimationTriangleSkewSpin.swift │ │ ├── NVActivityIndicatorAnimationDelegate.swift │ │ ├── NVActivityIndicatorPresenter.swift │ │ ├── NVActivityIndicatorShape.swift │ │ ├── NVActivityIndicatorView.h │ │ ├── NVActivityIndicatorView.swift │ │ └── NVActivityIndicatorViewable.swift ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage-2.launchimage │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ └── Local │ │ ├── 1.imageset │ │ ├── 1.jpg │ │ └── Contents.json │ │ ├── 10.imageset │ │ ├── 10.jpg │ │ └── Contents.json │ │ ├── 2.imageset │ │ ├── 2.jpg │ │ └── Contents.json │ │ ├── 3.imageset │ │ ├── 3.jpg │ │ └── Contents.json │ │ ├── 4.imageset │ │ ├── 4.jpg │ │ └── Contents.json │ │ ├── 5.imageset │ │ ├── 5.jpg │ │ └── Contents.json │ │ ├── 6.imageset │ │ ├── 6.jpg │ │ └── Contents.json │ │ ├── 7.imageset │ │ ├── 7.jpg │ │ └── Contents.json │ │ ├── 8.imageset │ │ ├── 8.jpg │ │ └── Contents.json │ │ └── 9.imageset │ │ ├── 9.jpg │ │ └── Contents.json ├── Info.plist ├── LangVC.swift ├── LaunchScreen.xib ├── Main.storyboard ├── PhotoBrowser │ ├── Common │ │ ├── PhotoBrowser+Common.swift │ │ └── pic.bundle │ │ │ ├── cancel@2x.png │ │ │ ├── cancel@3x.png │ │ │ ├── save@2x.png │ │ │ └── save@3x.png │ ├── Controller │ │ ├── PhotoBrowser+CollectionViewExtend.swift │ │ ├── PhotoBrowser+HUD.swift │ │ ├── PhotoBrowser+Indicator.swift │ │ ├── PhotoBrowser+Main.swift │ │ ├── PhotoBrowser+PBType.swift │ │ └── PhotoBrowser+ZoomAnim.swift │ ├── Layout │ │ └── Layout.swift │ ├── Model │ │ └── PhotoBrowser+Model.swift │ ├── PhotoBrowser.swift │ └── View │ │ ├── CollectionView.swift │ │ ├── ItemCell.swift │ │ ├── ItemCell.xib │ │ └── ShowImageView.swift ├── PhotoTypeChooseVC.swift ├── PhotoTypeChooseVC.xib └── ShowTypeChooseTVC.swift ├── PhotoBrowserTests ├── Info.plist └── PhotoBrowserTests.swift ├── README.md └── README_CH.md /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 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 | -------------------------------------------------------------------------------- /PhotoBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PhotoBrowser.xcodeproj/project.xcworkspace/xcshareddata/PhotoBrowser.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 562BD118-C22B-4968-9336-D700C8D60A84 9 | IDESourceControlProjectName 10 | PhotoBrowser 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 234351B82CAB484320AFDFB8097FA765FB356BBF 14 | https://github.com/nsdictionary/PhotoBrowser.git 15 | 16 | IDESourceControlProjectPath 17 | PhotoBrowser.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 234351B82CAB484320AFDFB8097FA765FB356BBF 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/nsdictionary/PhotoBrowser.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 234351B82CAB484320AFDFB8097FA765FB356BBF 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 234351B82CAB484320AFDFB8097FA765FB356BBF 36 | IDESourceControlWCCName 37 | PhotoBrowser 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PhotoBrowser.xcodeproj/project.xcworkspace/xcuserdata/Charlin.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser.xcodeproj/project.xcworkspace/xcuserdata/Charlin.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PhotoBrowser.xcodeproj/xcuserdata/Charlin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PhotoBrowser.xcodeproj/xcuserdata/Charlin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PhotoBrowser.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 89CA44421B7F96030061FEFC 16 | 17 | primary 18 | 19 | 20 | 89CA44571B7F96030061FEFC 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PhotoBrowser/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. 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 | 19 | // window = UIWindow(frame: UIScreen.mainScreen().bounds) 20 | // window?.backgroundColor = UIColor.whiteColor() 21 | // let displayVC = DisplayVC() 22 | // 23 | // displayVC.tabBarItem.title = "Charlin Feng" 24 | // 25 | //// let navVC = UINavigationController(rootViewController: displayVC) 26 | //// 27 | // let tabVC = UITabBarController() 28 | //// 29 | // tabVC.viewControllers = [displayVC] 30 | // 31 | // window?.rootViewController = tabVC 32 | // 33 | // window?.makeKeyAndVisible() 34 | 35 | return true 36 | } 37 | 38 | func applicationWillResignActive(_ application: UIApplication) { 39 | // 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. 40 | // 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. 41 | } 42 | 43 | func applicationDidEnterBackground(_ application: UIApplication) { 44 | // 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. 45 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 46 | } 47 | 48 | func applicationWillEnterForeground(_ application: UIApplication) { 49 | // 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. 50 | } 51 | 52 | func applicationDidBecomeActive(_ application: UIApplication) { 53 | // 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. 54 | } 55 | 56 | func applicationWillTerminate(_ application: UIApplication) { 57 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 58 | } 59 | 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /PhotoBrowser/DisplayVC+Local.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Display+Local.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | extension DisplayVC { 13 | 14 | var titleLocalCH: String {return "哆啦A梦:伴我同行"} 15 | var titleEN: String {return "Doraemon: walk with me"} 16 | 17 | 18 | 19 | var descLocalCH: [String] { 20 | return [ 21 | "《哆啦A梦:伴我同行》是一部纪念《哆啦A梦》之父藤子·F·不二雄诞辰80周年的3D动画电影,该片讲述了哆啦A梦圆满完成了他的使命,启程返回22世纪,大雄该如何以一己之力实现他那来之不易的幸福未来。该片于2014年8月8日在日本上映,2015年5月28日在中国内地上映。", 22 | "为了什么都做不来的野比大雄,22 世纪的玄孙野比世修送了猫型机器人──哆啦A梦来现代。", 23 | "笨笨的野比大雄原本自己开了间公司,但很不幸的倒闭,之后剩下了一屁股债务,子孙们吃了莫大的苦。于是,野比世修才打算送哆啦A梦到现代", 24 | "哆啦A梦于是开始勉勉强强的协助野比大雄的日常生活。", 25 | "虽然刚开始不太习惯,但两个人的关系也日渐变的紧密。", 26 | "得知野比大雄的梦想是打算与梦中情人的同班同学源静香结婚以后,哆啦A梦就想尽办法要帮助野比大雄获得静香的芳心。", 27 | "正当源静香总算答应了野比大雄的求婚的时候,任务完成的哆啦A梦却被完成程式要求", 28 | "在48小时内回到22世纪。难道,得到了什么,自然的,也会失去些什么这个命定的预言,没办法被哆啦A梦跟野比大雄突破。", 29 | "面对哆啦A梦即将离开的冲击,野比大雄又该如何自处。", 30 | ] 31 | } 32 | 33 | var descLocalEN: [String] { 34 | return [ 35 | "The duo la a dream: with my peers is a commemoration of Duo La a dream the father of Tengzi f. bu'erxiong birtThumbNailay 80th anniversary of 3D animated film, the film tells the story of the Duo a dream the successful completion of his mission, the journey back to the 22nd century, Nobita the how to single handedly achieve his hard won happiness in the future. The film was released in Japan in August 8, 2014 and released in May 28, 2015 in China.", 36 | "In order to do anything not to wild than male, the 22nd century's great great grandson Yebishixiu sent cat robot, duo la a dream to modern.", 37 | "Simple minded, wild than male originally opened his own company, but unfortunately the collapse, after the rest of the buttocks debt, children eat the great suffering. So, Yebishixiu only intend to send the duo A dream of modern", 38 | "Doraemon reluctantly began to assist the daily life of wild than male.", 39 | "Although just started not too accustomed to, but the relationship between the two people also gradually change the close.", 40 | "That wild than male's dream is to dream lover's classmate classmate Shizuka source married later, the duo la a dream will try to help wild than male Shizuka's heart.", 41 | "As promised when Shizuka source finally marry the wild than male tasks, Doraemon was completing the program requirements", 42 | "Back to twenty-second Century in 48 hours. Do what, natural and lose some what the fate of the prophecy, no way is the Duo a dream with wild than male breakthrough.", 43 | "In the face of Doraemon leaving the impact, how can wild than male.", 44 | ] 45 | } 46 | 47 | 48 | 49 | 50 | /** 本地相册 */ 51 | func showLocal(_ index: Int){ 52 | 53 | 54 | let pbVC = PhotoBrowser() 55 | 56 | /** 设置相册展示样式 */ 57 | pbVC.showType = showType 58 | 59 | /** 设置相册类型 */ 60 | pbVC.photoType = PhotoBrowser.PhotoType.local 61 | 62 | //强制关闭显示一切信息 63 | pbVC.hideMsgForZoomAndDismissWithSingleTap = true 64 | 65 | var models: [PhotoBrowser.PhotoModel] = [] 66 | 67 | let title = langType == LangType.chinese ? titleLocalCH : titleEN 68 | let desc = langType == LangType.chinese ? descLocalCH : descLocalEN 69 | 70 | //模型数据数组 71 | for i in 0 ..< 9 { 72 | 73 | let model = PhotoBrowser.PhotoModel(localImg:UIImage(named: "\(i+1).jpg")! , titleStr: title, descStr:desc[i], sourceView: displayView.subviews[i] as! UIView) 74 | 75 | models.append(model) 76 | } 77 | 78 | /** 设置数据 */ 79 | pbVC.photoModels = models 80 | 81 | pbVC.show(inVC: self,index: index) 82 | } 83 | 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /PhotoBrowser/DisplayVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DisplayVC.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DisplayVC: UIViewController { 12 | 13 | 14 | var langType: LangType = LangType.chinese 15 | 16 | var photoType: PhotoType = PhotoType.local 17 | 18 | var showType: PhotoBrowser.ShowType = PhotoBrowser.ShowType.zoomAndDismissWithSingleTap 19 | 20 | lazy var localImages: [String] = {["1.jpg","2.jpg","3.jpg","4.jpg","5.jpg","6.jpg","7.jpg","8.jpg","9.jpg"]}() 21 | 22 | let displayView = DisplayView() 23 | 24 | lazy var hostThumbNailImageUrls: [String] = { 25 | 26 | return [ 27 | 28 | "http://ios-android.cn/PB/ThumbNail/1.jpg", 29 | "http://ios-android.cn/PB/ThumbNail/2.jpg", 30 | "http://ios-android.cn/PB/ThumbNail/3.jpg", 31 | "http://ios-android.cn/PB/ThumbNail/4.jpg", 32 | "http://ios-android.cn/PB/ThumbNail/5.jpg", 33 | "http://ios-android.cn/PB/ThumbNail/6.jpg", 34 | "http://ios-android.cn/PB/ThumbNail/7.jpg", 35 | "http://ios-android.cn/PB/ThumbNail/8.jpg", 36 | "http://ios-android.cn/PB/ThumbNail/9.jpg", 37 | ] 38 | }() 39 | 40 | } 41 | 42 | 43 | 44 | 45 | extension DisplayVC{ 46 | 47 | 48 | override func viewDidLoad() { 49 | super.viewDidLoad() 50 | 51 | self.view.backgroundColor = UIColor.white 52 | 53 | self.navigationItem.title = langType == LangType.chinese ? "照片浏览器终结者" : "Photo Browser Terminator" 54 | 55 | if photoType == PhotoType.local { //本地 56 | displayView.imgsPrepare(localImages, isLocal: true) 57 | }else{ //网络 58 | displayView.imgsPrepare(hostThumbNailImageUrls, isLocal: false) 59 | } 60 | view.addSubview(displayView) 61 | 62 | let wh = min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) 63 | 64 | displayView.make_center(offsest: CGPoint.zero, width: wh, height: wh) 65 | 66 | 67 | displayView.tapedImageV = {[unowned self] index in 68 | 69 | if self.photoType == PhotoType.local { //本地 70 | self.showLocal(index) 71 | }else{ //网络 72 | self.showHost(index) 73 | } 74 | } 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /PhotoBrowser/DisplayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DisplayView.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DisplayView: UIView { 12 | 13 | 14 | var tapedImageV: ((_ index: Int)->())? 15 | 16 | } 17 | 18 | 19 | extension DisplayView{ 20 | 21 | /** 准备 */ 22 | func imgsPrepare(_ imgs: [String], isLocal: Bool){ 23 | 24 | for i in 0 ..< imgs.count { 25 | 26 | let imgV = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) 27 | imgV.backgroundColor = UIColor.lightGray 28 | imgV.isUserInteractionEnabled = true 29 | imgV.contentMode = UIViewContentMode.scaleAspectFill 30 | imgV.clipsToBounds = true 31 | imgV.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DisplayView.tapAction(_:)))) 32 | imgV.tag = i 33 | if isLocal { 34 | imgV.image = UIImage(named: imgs[i]) 35 | }else{ 36 | imgV.hnk_setImageFromURL(URL(string: imgs[i])!) 37 | } 38 | self.addSubview(imgV) 39 | } 40 | } 41 | 42 | 43 | func tapAction(_ tap: UITapGestureRecognizer){ 44 | tapedImageV?(tap.view!.tag) 45 | } 46 | 47 | 48 | 49 | override func layoutSubviews() { 50 | 51 | super.layoutSubviews() 52 | 53 | let totalRow = 3 54 | let totalWidth = self.bounds.size.width 55 | 56 | let margin: CGFloat = 10 57 | let itemWH = (totalWidth - margin * CGFloat(totalRow + 1)) / CGFloat(totalRow) 58 | 59 | /** 数组遍历 */ 60 | var i=0 61 | 62 | for view in self.subviews{ 63 | 64 | let row = i / totalRow 65 | let col = i % totalRow 66 | 67 | let x = (CGFloat(col) + 1) * margin + CGFloat(col) * itemWH 68 | let y = (CGFloat(row) + 1) * margin + CGFloat(row) * itemWH 69 | let frame = CGRect(x: x, y: y, width: itemWH, height: itemWH) 70 | view.frame = frame 71 | i += 1 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection 27 | #else 28 | import AppKit 29 | public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection 30 | #endif 31 | 32 | 33 | public struct ConstraintConfig { 34 | 35 | public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight 36 | 37 | } 38 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintDescription.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintDescription { 32 | 33 | internal let item: LayoutConstraintItem 34 | internal var attributes: ConstraintAttributes 35 | internal var relation: ConstraintRelation? = nil 36 | internal var sourceLocation: (String, UInt)? = nil 37 | internal var label: String? = nil 38 | internal var related: ConstraintItem? = nil 39 | internal var multiplier: ConstraintMultiplierTarget = 1.0 40 | internal var constant: ConstraintConstantTarget = 0.0 41 | internal var priority: ConstraintPriorityTarget = 1000.0 42 | internal lazy var constraint: Constraint? = { 43 | guard let relation = self.relation, 44 | let related = self.related, 45 | let sourceLocation = self.sourceLocation else { 46 | return nil 47 | } 48 | let from = ConstraintItem(target: self.item, attributes: self.attributes) 49 | 50 | return Constraint( 51 | from: from, 52 | to: related, 53 | relation: relation, 54 | sourceLocation: sourceLocation, 55 | label: self.label, 56 | multiplier: self.multiplier, 57 | constant: self.constant, 58 | priority: self.priority 59 | ) 60 | }() 61 | 62 | // MARK: Initialization 63 | 64 | internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) { 65 | self.item = item 66 | self.attributes = attributes 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintInsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintInsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintInsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintInsetTarget { 38 | } 39 | 40 | extension Float: ConstraintInsetTarget { 41 | } 42 | 43 | extension Double: ConstraintInsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintInsetTarget { 47 | } 48 | 49 | extension ConstraintInsets: ConstraintInsetTarget { 50 | } 51 | 52 | extension ConstraintInsetTarget { 53 | 54 | internal var constraintInsetTargetValue: ConstraintInsets { 55 | if let amount = self as? ConstraintInsets { 56 | return amount 57 | } else if let amount = self as? Float { 58 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 59 | } else if let amount = self as? Double { 60 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 61 | } else if let amount = self as? CGFloat { 62 | return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount) 63 | } else if let amount = self as? Int { 64 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 65 | } else if let amount = self as? UInt { 66 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 67 | } else { 68 | return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0) 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintInsets = UIEdgeInsets 33 | #else 34 | public typealias ConstraintInsets = EdgeInsets 35 | #endif 36 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public final class ConstraintItem { 32 | 33 | internal weak var target: AnyObject? 34 | internal let attributes: ConstraintAttributes 35 | 36 | internal init(target: AnyObject?, attributes: ConstraintAttributes) { 37 | self.target = target 38 | self.attributes = attributes 39 | } 40 | 41 | internal var layoutConstraintItem: LayoutConstraintItem? { 42 | return self.target as? LayoutConstraintItem 43 | } 44 | 45 | } 46 | 47 | public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool { 48 | // pointer equality 49 | guard lhs !== rhs else { 50 | return true 51 | } 52 | 53 | // must both have valid targets and identical attributes 54 | guard let target1 = lhs.target, 55 | let target2 = rhs.target, 56 | target1 === target2 && lhs.attributes == rhs.attributes else { 57 | return false 58 | } 59 | 60 | return true 61 | } 62 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintLayoutGuide+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 9.0, OSX 10.11, *) 30 | public extension ConstraintLayoutGuide { 31 | 32 | public var snp: ConstraintLayoutGuideDSL { 33 | return ConstraintLayoutGuideDSL(guide: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintLayoutGuide.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 9.0, *) 33 | public typealias ConstraintLayoutGuide = UILayoutGuide 34 | #else 35 | @available(OSX 10.11, *) 36 | public typealias ConstraintLayoutGuide = NSLayoutGuide 37 | #endif 38 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintLayoutGuideDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 9.0, OSX 10.11, *) 32 | public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL { 33 | 34 | @discardableResult 35 | public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 36 | return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure) 37 | } 38 | 39 | public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 40 | ConstraintMaker.makeConstraints(item: self.guide, closure: closure) 41 | } 42 | 43 | public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 44 | ConstraintMaker.remakeConstraints(item: self.guide, closure: closure) 45 | } 46 | 47 | public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 48 | ConstraintMaker.updateConstraints(item: self.guide, closure: closure) 49 | } 50 | 51 | public func removeConstraints() { 52 | ConstraintMaker.removeConstraints(item: self.guide) 53 | } 54 | 55 | public var target: AnyObject? { 56 | return self.guide 57 | } 58 | 59 | internal let guide: ConstraintLayoutGuide 60 | 61 | internal init(guide: ConstraintLayoutGuide) { 62 | self.guide = guide 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintLayoutSupport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 8.0, *) 33 | public typealias ConstraintLayoutSupport = UILayoutSupport 34 | #else 35 | public class ConstraintLayoutSupport {} 36 | #endif 37 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintLayoutSupportDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 8.0, *) 32 | public struct ConstraintLayoutSupportDSL: ConstraintDSL { 33 | 34 | public var target: AnyObject? { 35 | return self.support 36 | } 37 | 38 | internal let support: ConstraintLayoutSupport 39 | 40 | internal init(support: ConstraintLayoutSupport) { 41 | self.support = support 42 | 43 | } 44 | 45 | public var top: ConstraintItem { 46 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top) 47 | } 48 | 49 | public var bottom: ConstraintItem { 50 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom) 51 | } 52 | 53 | public var height: ConstraintItem { 54 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintMakerEditable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerEditable: ConstraintMakerPriortizable { 32 | 33 | @discardableResult 34 | public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 35 | self.description.multiplier = amount 36 | return self 37 | } 38 | 39 | @discardableResult 40 | public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 41 | return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue) 42 | } 43 | 44 | @discardableResult 45 | public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable { 46 | self.description.constant = amount.constraintOffsetTargetValue 47 | return self 48 | } 49 | 50 | @discardableResult 51 | public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable { 52 | self.description.constant = amount.constraintInsetTargetValue 53 | return self 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintMakerFinalizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerFinalizable { 32 | 33 | internal let description: ConstraintDescription 34 | 35 | internal init(_ description: ConstraintDescription) { 36 | self.description = description 37 | } 38 | 39 | @discardableResult 40 | public func labeled(_ label: String) -> ConstraintMakerFinalizable { 41 | self.description.label = label 42 | return self 43 | } 44 | 45 | public var constraint: Constraint { 46 | return self.description.constraint! 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintMakerPriortizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerPriortizable: ConstraintMakerFinalizable { 32 | 33 | @discardableResult 34 | public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable { 35 | self.description.priority = amount.value 36 | return self 37 | } 38 | 39 | @discardableResult 40 | public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable { 41 | self.description.priority = amount 42 | return self 43 | } 44 | 45 | @available(*, deprecated:3.0, message:"Use priority(.required) instead.") 46 | @discardableResult 47 | public func priorityRequired() -> ConstraintMakerFinalizable { 48 | return self.priority(.required) 49 | } 50 | 51 | @available(*, deprecated:3.0, message:"Use priority(.high) instead.") 52 | @discardableResult 53 | public func priorityHigh() -> ConstraintMakerFinalizable { 54 | return self.priority(.high) 55 | } 56 | 57 | @available(*, deprecated:3.0, message:"Use priority(.medium) instead.") 58 | @discardableResult 59 | public func priorityMedium() -> ConstraintMakerFinalizable { 60 | return self.priority(.medium) 61 | } 62 | 63 | @available(*, deprecated:3.0, message:"Use priority(.low) instead.") 64 | @discardableResult 65 | public func priorityLow() -> ConstraintMakerFinalizable { 66 | return self.priority(.low) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintMultiplierTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintMultiplierTarget { 32 | 33 | var constraintMultiplierTargetValue: CGFloat { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintMultiplierTarget { 38 | 39 | public var constraintMultiplierTargetValue: CGFloat { 40 | return CGFloat(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintMultiplierTarget { 46 | 47 | public var constraintMultiplierTargetValue: CGFloat { 48 | return CGFloat(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintMultiplierTarget { 54 | 55 | public var constraintMultiplierTargetValue: CGFloat { 56 | return CGFloat(self) 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintMultiplierTarget { 62 | 63 | public var constraintMultiplierTargetValue: CGFloat { 64 | return CGFloat(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintMultiplierTarget { 70 | 71 | public var constraintMultiplierTargetValue: CGFloat { 72 | return self 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintOffsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintOffsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintOffsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintOffsetTarget { 38 | } 39 | 40 | extension Float: ConstraintOffsetTarget { 41 | } 42 | 43 | extension Double: ConstraintOffsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintOffsetTarget { 47 | } 48 | 49 | extension ConstraintOffsetTarget { 50 | 51 | internal var constraintOffsetTargetValue: CGFloat { 52 | let offset: CGFloat 53 | if let amount = self as? Float { 54 | offset = CGFloat(amount) 55 | } else if let amount = self as? Double { 56 | offset = CGFloat(amount) 57 | } else if let amount = self as? CGFloat { 58 | offset = CGFloat(amount) 59 | } else if let amount = self as? Int { 60 | offset = CGFloat(amount) 61 | } else if let amount = self as? UInt { 62 | offset = CGFloat(amount) 63 | } else { 64 | offset = 0.0 65 | } 66 | return offset 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintPriority.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable { 31 | public typealias FloatLiteralType = Float 32 | 33 | public let value: Float 34 | 35 | public init(floatLiteral value: Float) { 36 | self.value = value 37 | } 38 | 39 | public init(_ value: Float) { 40 | self.value = value 41 | } 42 | 43 | public static var required: ConstraintPriority { 44 | return 1000.0 45 | } 46 | 47 | public static var high: ConstraintPriority { 48 | return 750.0 49 | } 50 | 51 | public static var medium: ConstraintPriority { 52 | #if os(OSX) 53 | return 501.0 54 | #else 55 | return 500.0 56 | #endif 57 | 58 | } 59 | 60 | public static var low: ConstraintPriority { 61 | return 250.0 62 | } 63 | 64 | public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool { 65 | return lhs.value == rhs.value 66 | } 67 | 68 | // MARK: Strideable 69 | 70 | public func advanced(by n: FloatLiteralType) -> ConstraintPriority { 71 | return ConstraintPriority(floatLiteral: value + n) 72 | } 73 | 74 | public func distance(to other: ConstraintPriority) -> FloatLiteralType { 75 | return other.value - value 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintPriorityTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintPriorityTarget { 32 | 33 | var constraintPriorityTargetValue: Float { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintPriorityTarget { 38 | 39 | public var constraintPriorityTargetValue: Float { 40 | return Float(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintPriorityTarget { 46 | 47 | public var constraintPriorityTargetValue: Float { 48 | return Float(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintPriorityTarget { 54 | 55 | public var constraintPriorityTargetValue: Float { 56 | return self 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintPriorityTarget { 62 | 63 | public var constraintPriorityTargetValue: Float { 64 | return Float(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintPriorityTarget { 70 | 71 | public var constraintPriorityTargetValue: Float { 72 | return Float(self) 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintRelatableTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintRelatableTarget { 32 | } 33 | 34 | extension Int: ConstraintRelatableTarget { 35 | } 36 | 37 | extension UInt: ConstraintRelatableTarget { 38 | } 39 | 40 | extension Float: ConstraintRelatableTarget { 41 | } 42 | 43 | extension Double: ConstraintRelatableTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintRelatableTarget { 47 | } 48 | 49 | extension CGSize: ConstraintRelatableTarget { 50 | } 51 | 52 | extension CGPoint: ConstraintRelatableTarget { 53 | } 54 | 55 | extension ConstraintInsets: ConstraintRelatableTarget { 56 | } 57 | 58 | extension ConstraintItem: ConstraintRelatableTarget { 59 | } 60 | 61 | extension ConstraintView: ConstraintRelatableTarget { 62 | } 63 | 64 | @available(iOS 9.0, OSX 10.11, *) 65 | extension ConstraintLayoutGuide: ConstraintRelatableTarget { 66 | } 67 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintRelation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | internal enum ConstraintRelation : Int { 32 | case equal = 1 33 | case lessThanOrEqual 34 | case greaterThanOrEqual 35 | 36 | internal var layoutRelation: NSLayoutRelation { 37 | get { 38 | switch(self) { 39 | case .equal: 40 | return .equal 41 | case .lessThanOrEqual: 42 | return .lessThanOrEqual 43 | case .greaterThanOrEqual: 44 | return .greaterThanOrEqual 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintView = UIView 33 | #else 34 | public typealias ConstraintView = NSView 35 | #endif 36 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/ConstraintViewDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public struct ConstraintViewDSL: ConstraintAttributesDSL { 32 | 33 | @discardableResult 34 | public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 35 | return ConstraintMaker.prepareConstraints(item: self.view, closure: closure) 36 | } 37 | 38 | public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 39 | ConstraintMaker.makeConstraints(item: self.view, closure: closure) 40 | } 41 | 42 | public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 43 | ConstraintMaker.remakeConstraints(item: self.view, closure: closure) 44 | } 45 | 46 | public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 47 | ConstraintMaker.updateConstraints(item: self.view, closure: closure) 48 | } 49 | 50 | public func removeConstraints() { 51 | ConstraintMaker.removeConstraints(item: self.view) 52 | } 53 | 54 | public var contentHuggingHorizontalPriority: Float { 55 | get { 56 | return self.view.contentHuggingPriority(for: .horizontal) 57 | } 58 | set { 59 | self.view.setContentHuggingPriority(newValue, for: .horizontal) 60 | } 61 | } 62 | 63 | public var contentHuggingVerticalPriority: Float { 64 | get { 65 | return self.view.contentHuggingPriority(for: .vertical) 66 | } 67 | set { 68 | self.view.setContentHuggingPriority(newValue, for: .vertical) 69 | } 70 | } 71 | 72 | public var contentCompressionResistanceHorizontalPriority: Float { 73 | get { 74 | return self.view.contentCompressionResistancePriority(for: .horizontal) 75 | } 76 | set { 77 | self.view.setContentCompressionResistancePriority(newValue, for: .horizontal) 78 | } 79 | } 80 | 81 | public var contentCompressionResistanceVerticalPriority: Float { 82 | get { 83 | return self.view.contentCompressionResistancePriority(for: .vertical) 84 | } 85 | set { 86 | self.view.setContentCompressionResistancePriority(newValue, for: .vertical) 87 | } 88 | } 89 | 90 | public var target: AnyObject? { 91 | return self.view 92 | } 93 | 94 | internal let view: ConstraintView 95 | 96 | internal init(view: ConstraintView) { 97 | self.view = view 98 | 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(CURRENT_PROJECT_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/LayoutConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class LayoutConstraint : NSLayoutConstraint { 32 | 33 | public var label: String? { 34 | get { 35 | return self.identifier 36 | } 37 | set { 38 | self.identifier = newValue 39 | } 40 | } 41 | 42 | internal weak var constraint: Constraint? = nil 43 | 44 | } 45 | 46 | internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool { 47 | guard lhs.firstItem === rhs.firstItem && 48 | lhs.secondItem === rhs.secondItem && 49 | lhs.firstAttribute == rhs.firstAttribute && 50 | lhs.secondAttribute == rhs.secondAttribute && 51 | lhs.relation == rhs.relation && 52 | lhs.priority == rhs.priority && 53 | lhs.multiplier == rhs.multiplier else { 54 | return false 55 | } 56 | return true 57 | } 58 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/LayoutConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol LayoutConstraintItem: class { 32 | } 33 | 34 | @available(iOS 9.0, OSX 10.11, *) 35 | extension ConstraintLayoutGuide : LayoutConstraintItem { 36 | } 37 | 38 | extension ConstraintView : LayoutConstraintItem { 39 | } 40 | 41 | 42 | extension LayoutConstraintItem { 43 | 44 | internal func prepare() { 45 | if let view = self as? ConstraintView { 46 | view.translatesAutoresizingMaskIntoConstraints = false 47 | } 48 | } 49 | 50 | internal var superview: ConstraintView? { 51 | if let view = self as? ConstraintView { 52 | return view.superview 53 | } 54 | 55 | if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide { 56 | return guide.owningView 57 | } 58 | 59 | return nil 60 | } 61 | internal var constraints: [Constraint] { 62 | return self.constraintsSet.allObjects as! [Constraint] 63 | } 64 | 65 | internal func add(constraints: [Constraint]) { 66 | let constraintsSet = self.constraintsSet 67 | for constraint in constraints { 68 | constraintsSet.add(constraint) 69 | } 70 | } 71 | 72 | internal func remove(constraints: [Constraint]) { 73 | let constraintsSet = self.constraintsSet 74 | for constraint in constraints { 75 | constraintsSet.remove(constraint) 76 | } 77 | } 78 | 79 | private var constraintsSet: NSMutableSet { 80 | let constraintsSet: NSMutableSet 81 | 82 | if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet { 83 | constraintsSet = existing 84 | } else { 85 | constraintsSet = NSMutableSet() 86 | objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 87 | } 88 | return constraintsSet 89 | 90 | } 91 | 92 | } 93 | private var constraintsKey: UInt8 = 0 94 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/SnapKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #import 25 | 26 | FOUNDATION_EXPORT double SnapKitVersionNumber; 27 | FOUNDATION_EXPORT const unsigned char SnapKitVersionString[]; -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/CFSnapKit/Source/UILayoutSupport+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 8.0, *) 30 | public extension ConstraintLayoutSupport { 31 | 32 | public var snp: ConstraintLayoutSupportDSL { 33 | return ConstraintLayoutSupportDSL(support: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/CGSize+Swift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGSize+Swift.swift 3 | // Haneke 4 | // 5 | // Created by Oriol Blanc Gimeno on 09/09/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGSize { 12 | 13 | func hnk_aspectFillSize(_ size: CGSize) -> CGSize { 14 | let scaleWidth = size.width / self.width 15 | let scaleHeight = size.height / self.height 16 | let scale = max(scaleWidth, scaleHeight) 17 | 18 | let resultSize = CGSize(width: self.width * scale, height: self.height * scale) 19 | return CGSize(width: ceil(resultSize.width), height: ceil(resultSize.height)) 20 | } 21 | 22 | func hnk_aspectFitSize(_ size: CGSize) -> CGSize { 23 | let targetAspect = size.width / size.height 24 | let sourceAspect = self.width / self.height 25 | var resultSize = size 26 | 27 | if (targetAspect > sourceAspect) { 28 | resultSize.width = size.height * sourceAspect 29 | } 30 | else { 31 | resultSize.height = size.width / sourceAspect 32 | } 33 | return CGSize(width: ceil(resultSize.width), height: ceil(resultSize.height)) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 9/19/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // See: http://stackoverflow.com/questions/25922152/not-identical-to-self 12 | public protocol DataConvertible { 13 | associatedtype Result 14 | 15 | static func convertFromData(_ data:Data) -> Result? 16 | } 17 | 18 | public protocol DataRepresentable { 19 | 20 | func asData() -> Data! 21 | } 22 | 23 | private let imageSync = NSLock() 24 | 25 | extension UIImage : DataConvertible, DataRepresentable { 26 | 27 | public typealias Result = UIImage 28 | 29 | // HACK: UIImage data initializer is no longer thread safe. See: https://github.com/AFNetworking/AFNetworking/issues/2572#issuecomment-115854482 30 | static func safeImageWithData(_ data:Data) -> Result? { 31 | imageSync.lock() 32 | let image = UIImage(data:data, scale: scale) 33 | imageSync.unlock() 34 | return image 35 | } 36 | 37 | public class func convertFromData(_ data: Data) -> Result? { 38 | let image = UIImage.safeImageWithData(data) 39 | return image 40 | } 41 | 42 | public func asData() -> Data! { 43 | return self.hnk_data() as Data! 44 | } 45 | 46 | fileprivate static let scale = UIScreen.main.scale 47 | 48 | } 49 | 50 | extension String : DataConvertible, DataRepresentable { 51 | 52 | public typealias Result = String 53 | 54 | public static func convertFromData(_ data: Data) -> Result? { 55 | let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) 56 | return string as Result? 57 | } 58 | 59 | public func asData() -> Data! { 60 | return self.data(using: String.Encoding.utf8) 61 | } 62 | 63 | } 64 | 65 | extension Data : DataConvertible, DataRepresentable { 66 | 67 | public typealias Result = Data 68 | 69 | public static func convertFromData(_ data: Data) -> Result? { 70 | return data 71 | } 72 | 73 | public func asData() -> Data! { 74 | return self 75 | } 76 | 77 | } 78 | 79 | public enum JSON : DataConvertible, DataRepresentable { 80 | public typealias Result = JSON 81 | 82 | case Dictionary([String:AnyObject]) 83 | case Array([AnyObject]) 84 | 85 | public static func convertFromData(_ data: Data) -> Result? { 86 | do { 87 | let object : Any = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) 88 | switch (object) { 89 | case let dictionary as [String:AnyObject]: 90 | return JSON.Dictionary(dictionary) 91 | case let array as [AnyObject]: 92 | return JSON.Array(array) 93 | default: 94 | return nil 95 | } 96 | } catch { 97 | Log.error(message: "Invalid JSON data", error: error) 98 | return nil 99 | } 100 | } 101 | 102 | public func asData() -> Data! { 103 | switch (self) { 104 | case .Dictionary(let dictionary): 105 | return try? JSONSerialization.data(withJSONObject: dictionary, options: JSONSerialization.WritingOptions()) 106 | case .Array(let array): 107 | return try? JSONSerialization.data(withJSONObject: array, options: JSONSerialization.WritingOptions()) 108 | } 109 | } 110 | 111 | public var array : [AnyObject]! { 112 | switch (self) { 113 | case .Dictionary(_): 114 | return nil 115 | case .Array(let array): 116 | return array 117 | } 118 | } 119 | 120 | public var dictionary : [String:AnyObject]! { 121 | switch (self) { 122 | case .Dictionary(let dictionary): 123 | return dictionary 124 | case .Array(_): 125 | return nil 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/DiskFetcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiskFetcher.swift 3 | // Haneke 4 | // 5 | // Created by Joan Romano on 9/16/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension HanekeGlobals { 12 | 13 | // It'd be better to define this in the DiskFetcher class but Swift doesn't allow to declare an enum in a generic type 14 | public struct DiskFetcher { 15 | 16 | public enum ErrorCode : Int { 17 | case invalidData = -500 18 | } 19 | 20 | } 21 | 22 | } 23 | 24 | open class DiskFetcher : Fetcher { 25 | 26 | let path: String 27 | var cancelled = false 28 | 29 | public init(path: String) { 30 | self.path = path 31 | let key = path 32 | super.init(key: key) 33 | } 34 | 35 | // MARK: Fetcher 36 | 37 | 38 | open override func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { 39 | self.cancelled = false 40 | DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { [weak self] in 41 | if let strongSelf = self { 42 | strongSelf.privateFetch(failure: fail, success: succeed) 43 | } 44 | }) 45 | } 46 | 47 | open override func cancelFetch() { 48 | self.cancelled = true 49 | } 50 | 51 | // MARK: Private 52 | 53 | fileprivate func privateFetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { 54 | if self.cancelled { 55 | return 56 | } 57 | 58 | let data : Data 59 | do { 60 | data = try Data(contentsOf: URL(fileURLWithPath: self.path), options: Data.ReadingOptions()) 61 | } catch { 62 | DispatchQueue.main.async { 63 | if self.cancelled { 64 | return 65 | } 66 | fail(error) 67 | } 68 | return 69 | } 70 | 71 | if self.cancelled { 72 | return 73 | } 74 | 75 | guard let value : T.Result = T.convertFromData(data) else { 76 | let localizedFormat = NSLocalizedString("Failed to convert value from data at path %@", comment: "Error description") 77 | let description = String(format:localizedFormat, self.path) 78 | let error = errorWithCode(HanekeGlobals.DiskFetcher.ErrorCode.invalidData.rawValue, description: description) 79 | DispatchQueue.main.async { 80 | fail(error) 81 | } 82 | return 83 | } 84 | 85 | DispatchQueue.main.async(execute: { 86 | if self.cancelled { 87 | return 88 | } 89 | succeed(value) 90 | }) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Fetch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fetch.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 9/28/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum FetchState { 12 | case pending 13 | // Using Wrapper as a workaround for error 'unimplemented IR generation feature non-fixed multi-payload enum layout' 14 | // See: http://swiftradar.tumblr.com/post/88314603360/swift-fails-to-compile-enum-with-two-data-cases 15 | // See: http://owensd.io/2014/08/06/fixed-enum-layout.html 16 | case success(Wrapper) 17 | case failure(Error?) 18 | } 19 | 20 | open class Fetch { 21 | 22 | public typealias Succeeder = (T) -> () 23 | 24 | public typealias Failer = (Error?) -> () 25 | 26 | fileprivate var onSuccess : Succeeder? 27 | 28 | fileprivate var onFailure : Failer? 29 | 30 | fileprivate var state : FetchState = FetchState.pending 31 | 32 | public init() {} 33 | 34 | @discardableResult open func onSuccess(_ onSuccess: @escaping Succeeder) -> Self { 35 | self.onSuccess = onSuccess 36 | switch self.state { 37 | case FetchState.success(let wrapper): 38 | onSuccess(wrapper.value) 39 | default: 40 | break 41 | } 42 | return self 43 | } 44 | 45 | @discardableResult open func onFailure(_ onFailure: @escaping Failer) -> Self { 46 | self.onFailure = onFailure 47 | switch self.state { 48 | case FetchState.failure(let error): 49 | onFailure(error) 50 | default: 51 | break 52 | } 53 | return self 54 | } 55 | 56 | func succeed(_ value: T) { 57 | self.state = FetchState.success(Wrapper(value)) 58 | self.onSuccess?(value) 59 | } 60 | 61 | func fail(_ error: Error? = nil) { 62 | self.state = FetchState.failure(error) 63 | self.onFailure?(error) 64 | } 65 | 66 | var hasFailed : Bool { 67 | switch self.state { 68 | case FetchState.failure(_): 69 | return true 70 | default: 71 | return false 72 | } 73 | } 74 | 75 | var hasSucceeded : Bool { 76 | switch self.state { 77 | case FetchState.success(_): 78 | return true 79 | default: 80 | return false 81 | } 82 | } 83 | 84 | } 85 | 86 | open class Wrapper { 87 | open let value: T 88 | public init(_ value: T) { self.value = value } 89 | } 90 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Fetcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fetcher.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 9/9/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // See: http://stackoverflow.com/questions/25915306/generic-closure-in-protocol 12 | open class Fetcher { 13 | 14 | open let key: String 15 | 16 | public init(key: String) { 17 | self.key = key 18 | } 19 | 20 | open func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) {} 21 | 22 | open func cancelFetch() {} 23 | } 24 | 25 | class SimpleFetcher : Fetcher { 26 | 27 | let getValue : () -> T.Result 28 | 29 | init(key: String, value getValue : @autoclosure @escaping () -> T.Result) { 30 | self.getValue = getValue 31 | super.init(key: key) 32 | } 33 | 34 | override func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { 35 | let value = getValue() 36 | succeed(value) 37 | } 38 | 39 | override func cancelFetch() {} 40 | 41 | } 42 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Format.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Format.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 8/27/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct Format { 12 | 13 | public let name: String 14 | 15 | public let diskCapacity : UInt64 16 | 17 | public var transform : ((T) -> (T))? 18 | 19 | public var convertToData : ((T) -> Data)? 20 | 21 | public init(name: String, diskCapacity : UInt64 = UINT64_MAX, transform: ((T) -> (T))? = nil) { 22 | self.name = name 23 | self.diskCapacity = diskCapacity 24 | self.transform = transform 25 | } 26 | 27 | public func apply(_ value : T) -> T { 28 | var transformed = value 29 | if let transform = self.transform { 30 | transformed = transform(value) 31 | } 32 | return transformed 33 | } 34 | 35 | var isIdentity : Bool { 36 | return self.transform == nil 37 | } 38 | 39 | } 40 | 41 | public struct ImageResizer { 42 | 43 | public enum ScaleMode: String { 44 | case Fill = "fill", AspectFit = "aspectfit", AspectFill = "aspectfill", None = "none" 45 | } 46 | 47 | public typealias T = UIImage 48 | 49 | public let allowUpscaling : Bool 50 | 51 | public let size : CGSize 52 | 53 | public let scaleMode: ScaleMode 54 | 55 | public let compressionQuality : Float 56 | 57 | public init(size: CGSize = CGSize.zero, scaleMode: ScaleMode = .None, allowUpscaling: Bool = true, compressionQuality: Float = 1.0) { 58 | self.size = size 59 | self.scaleMode = scaleMode 60 | self.allowUpscaling = allowUpscaling 61 | self.compressionQuality = compressionQuality 62 | } 63 | 64 | public func resizeImage(_ image: UIImage) -> UIImage { 65 | var resizeToSize: CGSize 66 | switch self.scaleMode { 67 | case .Fill: 68 | resizeToSize = self.size 69 | case .AspectFit: 70 | resizeToSize = image.size.hnk_aspectFitSize(self.size) 71 | case .AspectFill: 72 | resizeToSize = image.size.hnk_aspectFillSize(self.size) 73 | case .None: 74 | return image 75 | } 76 | assert(self.size.width > 0 && self.size.height > 0, "Expected non-zero size. Use ScaleMode.None to avoid resizing.") 77 | 78 | // If does not allow to scale up the image 79 | if (!self.allowUpscaling) { 80 | if (resizeToSize.width > image.size.width || resizeToSize.height > image.size.height) { 81 | return image 82 | } 83 | } 84 | 85 | // Avoid unnecessary computations 86 | if (resizeToSize.width == image.size.width && resizeToSize.height == image.size.height) { 87 | return image 88 | } 89 | 90 | let resizedImage = image.hnk_imageByScaling(toSize: resizeToSize) 91 | return resizedImage 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Haneke.h: -------------------------------------------------------------------------------- 1 | // 2 | // Haneke.h 3 | // Haneke 4 | // 5 | // Created by Luis Ascorbe on 23/07/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Haneke. 12 | FOUNDATION_EXPORT double HanekeVersionNumber; 13 | 14 | //! Project version string for Haneke. 15 | FOUNDATION_EXPORT const unsigned char HanekeVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 9/9/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct HanekeGlobals { 12 | 13 | public static let Domain = "io.haneke" 14 | 15 | } 16 | 17 | public struct Shared { 18 | 19 | public static var imageCache : Cache { 20 | struct Static { 21 | static let name = "shared-images" 22 | static let cache = Cache(name: name) 23 | } 24 | return Static.cache 25 | } 26 | 27 | public static var dataCache : Cache { 28 | struct Static { 29 | static let name = "shared-data" 30 | static let cache = Cache(name: name) 31 | } 32 | return Static.cache 33 | } 34 | 35 | public static var stringCache : Cache { 36 | struct Static { 37 | static let name = "shared-strings" 38 | static let cache = Cache(name: name) 39 | } 40 | return Static.cache 41 | } 42 | 43 | public static var JSONCache : Cache { 44 | struct Static { 45 | static let name = "shared-json" 46 | static let cache = Cache(name: name) 47 | } 48 | return Static.cache 49 | } 50 | } 51 | 52 | func errorWithCode(_ code: Int, description: String) -> Error { 53 | let userInfo = [NSLocalizedDescriptionKey: description] 54 | return NSError(domain: HanekeGlobals.Domain, code: code, userInfo: userInfo) as Error 55 | } 56 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Info-iOS.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 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Info-tvOS.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 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/Log.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Log.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 11/10/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Log { 12 | 13 | fileprivate static let Tag = "[HANEKE]" 14 | 15 | fileprivate enum Level : String { 16 | case Debug = "[DEBUG]" 17 | case Error = "[ERROR]" 18 | } 19 | 20 | fileprivate static func log(_ level: Level, _ message: @autoclosure () -> String, _ error: Error? = nil) { 21 | if let error = error { 22 | print("\(Tag)\(level.rawValue) \(message()) with error \(error)") 23 | } else { 24 | print("\(Tag)\(level.rawValue) \(message())") 25 | } 26 | } 27 | 28 | static func debug(message: @autoclosure () -> String, error: Error? = nil) { 29 | #if DEBUG 30 | log(.Debug, message, error) 31 | #endif 32 | } 33 | 34 | static func error(message: @autoclosure () -> String, error: Error? = nil) { 35 | log(.Error, message, error) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/NSFileManager+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileManager+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 8/26/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension FileManager { 12 | 13 | func enumerateContentsOfDirectory(atPath path: String, orderedByProperty property: String, ascending: Bool, usingBlock block: (URL, Int, inout Bool) -> Void ) { 14 | 15 | let directoryURL = URL(fileURLWithPath: path) 16 | do { 17 | let contents = try self.contentsOfDirectory(at: directoryURL, includingPropertiesForKeys: [URLResourceKey(rawValue: property)], options: FileManager.DirectoryEnumerationOptions()) 18 | let sortedContents = contents.sorted(by: {(URL1: URL, URL2: URL) -> Bool in 19 | 20 | // Maybe there's a better way to do this. See: http://stackoverflow.com/questions/25502914/comparing-anyobject-in-swift 21 | 22 | var value1 : AnyObject? 23 | do { 24 | try (URL1 as NSURL).getResourceValue(&value1, forKey: URLResourceKey(rawValue: property)) 25 | } catch { 26 | return true 27 | } 28 | var value2 : AnyObject? 29 | do { 30 | try (URL2 as NSURL).getResourceValue(&value2, forKey: URLResourceKey(rawValue: property)) 31 | } catch { 32 | return false 33 | } 34 | 35 | if let string1 = value1 as? String, let string2 = value2 as? String { 36 | return ascending ? string1 < string2 : string2 < string1 37 | } 38 | 39 | if let date1 = value1 as? Date, let date2 = value2 as? Date { 40 | return ascending ? date1 < date2 : date2 < date1 41 | } 42 | 43 | if let number1 = value1 as? NSNumber, let number2 = value2 as? NSNumber { 44 | return ascending ? number1 < number2 : number2 < number1 45 | } 46 | 47 | return false 48 | }) 49 | 50 | for (i, v) in sortedContents.enumerated() { 51 | var stop : Bool = false 52 | block(v, i, &stop) 53 | if stop { break } 54 | } 55 | 56 | } catch { 57 | Log.error(message: "Failed to list directory", error: error) 58 | } 59 | } 60 | 61 | } 62 | 63 | func < (lhs: NSNumber, rhs: NSNumber) -> Bool { 64 | return lhs.compare(rhs) == ComparisonResult.orderedAscending 65 | } 66 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/NSHTTPURLResponse+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 1/2/16. 6 | // Copyright © 2016 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension HTTPURLResponse { 12 | 13 | func hnk_isValidStatusCode() -> Bool { 14 | switch self.statusCode { 15 | case 200...201: 16 | return true 17 | default: 18 | return false 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/NSURLResponse+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 9/12/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension URLResponse { 12 | 13 | func hnk_validateLength(ofData data: Data) -> Bool { 14 | let expectedContentLength = self.expectedContentLength 15 | if (expectedContentLength > -1) { 16 | let dataLength = data.count 17 | return Int64(dataLength) >= expectedContentLength 18 | } 19 | return true 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/String+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 8/30/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | 13 | func escapedFilename() -> String { 14 | return [ "\0":"%00", ":":"%3A", "/":"%2F" ] 15 | .reduce(self.components(separatedBy: "%").joined(separator: "%25")) { 16 | str, m in str.components(separatedBy: m.0).joined(separator: m.1) 17 | } 18 | } 19 | 20 | func MD5String() -> String { 21 | guard let data = self.data(using: String.Encoding.utf8) else { 22 | return self 23 | } 24 | 25 | let MD5Calculator = MD5(Array(data)) 26 | let MD5Data = MD5Calculator.calculate() 27 | let resultBytes = UnsafeMutablePointer(mutating: MD5Data) 28 | let resultEnumerator = UnsafeBufferPointer(start: resultBytes, count: MD5Data.count) 29 | let MD5String = NSMutableString() 30 | for c in resultEnumerator { 31 | MD5String.appendFormat("%02x", c) 32 | } 33 | return MD5String as String 34 | } 35 | 36 | func MD5Filename() -> String { 37 | let MD5String = self.MD5String() 38 | 39 | // NSString.pathExtension alone could return a query string, which can lead to very long filenames. 40 | let pathExtension = URL(string: self)?.pathExtension ?? (self as NSString).pathExtension 41 | 42 | if pathExtension.characters.count > 0 { 43 | return (MD5String as NSString).appendingPathExtension(pathExtension) ?? MD5String 44 | } else { 45 | return MD5String 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/UIImage+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Hermes Pique on 8/10/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIImage { 12 | 13 | func hnk_imageByScaling(toSize size: CGSize) -> UIImage { 14 | UIGraphicsBeginImageContextWithOptions(size, !hnk_hasAlpha(), 0.0) 15 | draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) 16 | let resizedImage = UIGraphicsGetImageFromCurrentImageContext() 17 | UIGraphicsEndImageContext() 18 | return resizedImage! 19 | } 20 | 21 | func hnk_hasAlpha() -> Bool { 22 | guard let alphaInfo = self.cgImage?.alphaInfo else { return false } 23 | switch alphaInfo { 24 | case .first, .last, .premultipliedFirst, .premultipliedLast, .alphaOnly: 25 | return true 26 | case .none, .noneSkipFirst, .noneSkipLast: 27 | return false 28 | } 29 | } 30 | 31 | func hnk_data(compressionQuality: Float = 1.0) -> Data! { 32 | let hasAlpha = self.hnk_hasAlpha() 33 | let data = hasAlpha ? UIImagePNGRepresentation(self) : UIImageJPEGRepresentation(self, CGFloat(compressionQuality)) 34 | return data 35 | } 36 | 37 | func hnk_decompressedImage() -> UIImage! { 38 | let originalImageRef = self.cgImage 39 | let originalBitmapInfo = originalImageRef?.bitmapInfo 40 | guard let alphaInfo = originalImageRef?.alphaInfo else { return UIImage() } 41 | 42 | // See: http://stackoverflow.com/questions/23723564/which-cgimagealphainfo-should-we-use 43 | var bitmapInfo = originalBitmapInfo 44 | switch alphaInfo { 45 | case .none: 46 | let rawBitmapInfoWithoutAlpha = (bitmapInfo?.rawValue)! & ~CGBitmapInfo.alphaInfoMask.rawValue 47 | let rawBitmapInfo = rawBitmapInfoWithoutAlpha | CGImageAlphaInfo.noneSkipFirst.rawValue 48 | bitmapInfo = CGBitmapInfo(rawValue: rawBitmapInfo) 49 | case .premultipliedFirst, .premultipliedLast, .noneSkipFirst, .noneSkipLast: 50 | break 51 | case .alphaOnly, .last, .first: // Unsupported 52 | return self 53 | } 54 | 55 | let colorSpace = CGColorSpaceCreateDeviceRGB() 56 | let pixelSize = CGSize(width: self.size.width * self.scale, height: self.size.height * self.scale) 57 | guard let context = CGContext(data: nil, width: Int(ceil(pixelSize.width)), height: Int(ceil(pixelSize.height)), bitsPerComponent: (originalImageRef?.bitsPerComponent)!, bytesPerRow: 0, space: colorSpace, bitmapInfo: (bitmapInfo?.rawValue)!) else { 58 | return self 59 | } 60 | 61 | let imageRect = CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height) 62 | UIGraphicsPushContext(context) 63 | 64 | // Flip coordinate system. See: http://stackoverflow.com/questions/506622/cgcontextdrawimage-draws-image-upside-down-when-passed-uiimage-cgimage 65 | context.translateBy(x: 0, y: pixelSize.height) 66 | context.scaleBy(x: 1.0, y: -1.0) 67 | 68 | // UIImage and drawInRect takes into account image orientation, unlike CGContextDrawImage. 69 | self.draw(in: imageRect) 70 | UIGraphicsPopContext() 71 | 72 | guard let decompressedImageRef = context.makeImage() else { 73 | return self 74 | } 75 | 76 | let scale = UIScreen.main.scale 77 | let image = UIImage(cgImage: decompressedImageRef, scale:scale, orientation:UIImageOrientation.up) 78 | return image 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/Haneke/UIView+Haneke.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Haneke.swift 3 | // Haneke 4 | // 5 | // Created by Joan Romano on 15/10/14. 6 | // Copyright (c) 2014 Haneke. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension HanekeGlobals { 12 | 13 | public struct UIKit { 14 | 15 | static func formatWithSize(_ size : CGSize, scaleMode : ImageResizer.ScaleMode, allowUpscaling: Bool = true) -> Format { 16 | let name = "auto-\(size.width)x\(size.height)-\(scaleMode.rawValue)" 17 | let cache = Shared.imageCache 18 | if let (format,_,_) = cache.formats[name] { 19 | return format 20 | } 21 | 22 | var format = Format(name: name, 23 | diskCapacity: HanekeGlobals.UIKit.DefaultFormat.DiskCapacity) { 24 | let resizer = ImageResizer(size:size, 25 | scaleMode: scaleMode, 26 | allowUpscaling: allowUpscaling, 27 | compressionQuality: HanekeGlobals.UIKit.DefaultFormat.CompressionQuality) 28 | return resizer.resizeImage($0) 29 | } 30 | format.convertToData = {(image : UIImage) -> Data in 31 | image.hnk_data(compressionQuality: HanekeGlobals.UIKit.DefaultFormat.CompressionQuality) as Data 32 | } 33 | return format 34 | } 35 | 36 | public struct DefaultFormat { 37 | 38 | public static let DiskCapacity : UInt64 = 50 * 1024 * 1024 39 | public static let CompressionQuality : Float = 0.75 40 | 41 | } 42 | 43 | static var SetImageAnimationDuration = 0.1 44 | static var SetImageFetcherKey = 0 45 | static var SetBackgroundImageFetcherKey = 1 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationAudioEqualizer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationAudioEqualizer.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationAudioEqualizer: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let lineSize = size.width / 9 34 | let x = (layer.bounds.size.width - lineSize * 7) / 2 35 | let y = (layer.bounds.size.height - size.height) / 2 36 | let duration: [CFTimeInterval] = [4.3, 2.5, 1.7, 3.1] 37 | let values = [0, 0.7, 0.4, 0.05, 0.95, 0.3, 0.9, 0.4, 0.15, 0.18, 0.75, 0.01] 38 | 39 | // Draw lines 40 | for i in 0 ..< 4 { 41 | let animation = CAKeyframeAnimation() 42 | 43 | animation.keyPath = "path" 44 | animation.isAdditive = true 45 | animation.values = [] 46 | 47 | for j in 0 ..< values.count { 48 | let heightFactor = values[j] 49 | let height = size.height * CGFloat(heightFactor) 50 | let point = CGPoint(x: 0, y: size.height - height) 51 | let path = UIBezierPath(rect: CGRect(origin: point, size: CGSize(width: lineSize, height: height))) 52 | 53 | animation.values?.append(path.cgPath) 54 | } 55 | animation.duration = duration[i] 56 | animation.repeatCount = HUGE 57 | animation.isRemovedOnCompletion = false 58 | 59 | let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color) 60 | let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), 61 | y: y, 62 | width: lineSize, 63 | height: size.height) 64 | 65 | line.frame = frame 66 | line.add(animation, forKey: "animation") 67 | layer.addSublayer(line) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallBeat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallBeat.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallBeat: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSpacing: CGFloat = 2 34 | let circleSize = (size.width - circleSpacing * 2) / 3 35 | let x = (layer.bounds.size.width - size.width) / 2 36 | let y = (layer.bounds.size.height - circleSize) / 2 37 | let duration: CFTimeInterval = 0.7 38 | let beginTime = CACurrentMediaTime() 39 | let beginTimes = [0.35, 0, 0.35] 40 | 41 | // Scale animation 42 | let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") 43 | 44 | scaleAnimation.keyTimes = [0, 0.5, 1] 45 | scaleAnimation.values = [1, 0.75, 1] 46 | scaleAnimation.duration = duration 47 | 48 | // Opacity animation 49 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 50 | 51 | opacityAnimation.keyTimes = [0, 0.5, 1] 52 | opacityAnimation.values = [1, 0.2, 1] 53 | opacityAnimation.duration = duration 54 | 55 | // Aniamtion 56 | let animation = CAAnimationGroup() 57 | 58 | animation.animations = [scaleAnimation, opacityAnimation] 59 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 60 | animation.duration = duration 61 | animation.repeatCount = HUGE 62 | animation.isRemovedOnCompletion = false 63 | 64 | // Draw circles 65 | for i in 0 ..< 3 { 66 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 67 | let frame = CGRect(x: x + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), 68 | y: y, 69 | width: circleSize, 70 | height: circleSize) 71 | 72 | animation.beginTime = beginTime + beginTimes[i] 73 | circle.frame = frame 74 | circle.add(animation, forKey: "animation") 75 | layer.addSublayer(circle) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallClipRotate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorBallClipRotate.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallClipRotate: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 0.75 34 | 35 | // Scale animation 36 | let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") 37 | 38 | scaleAnimation.keyTimes = [0, 0.5, 1] 39 | scaleAnimation.values = [1, 0.6, 1] 40 | 41 | // Rotate animation 42 | let rotateAnimation = CAKeyframeAnimation(keyPath: "transform.rotation.z") 43 | 44 | rotateAnimation.keyTimes = scaleAnimation.keyTimes 45 | rotateAnimation.values = [0, Double.pi, 2 * Double.pi] 46 | 47 | // Animation 48 | let animation = CAAnimationGroup() 49 | 50 | animation.animations = [scaleAnimation, rotateAnimation] 51 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 52 | animation.duration = duration 53 | animation.repeatCount = HUGE 54 | animation.isRemovedOnCompletion = false 55 | 56 | // Draw circle 57 | let circle = NVActivityIndicatorShape.ringThirdFour.layerWith(size: CGSize(width: size.width, height: size.height), color: color) 58 | let frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 59 | y: (layer.bounds.size.height - size.height) / 2, 60 | width: size.width, 61 | height: size.height) 62 | 63 | circle.frame = frame 64 | circle.add(animation, forKey: "animation") 65 | layer.addSublayer(circle) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallGridBeat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallGridBeat.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallGridBeat: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSpacing: CGFloat = 2 34 | let circleSize = (size.width - circleSpacing * 2) / 3 35 | let x = (layer.bounds.size.width - size.width) / 2 36 | let y = (layer.bounds.size.height - size.height) / 2 37 | let durations = [0.96, 0.93, 1.19, 1.13, 1.34, 0.94, 1.2, 0.82, 1.19] 38 | let beginTime = CACurrentMediaTime() 39 | let beginTimes = [0.36, 0.4, 0.68, 0.41, 0.71, -0.15, -0.12, 0.01, 0.32] 40 | let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) 41 | 42 | // Animation 43 | let animation = CAKeyframeAnimation(keyPath: "opacity") 44 | 45 | animation.keyTimes = [0, 0.5, 1] 46 | animation.timingFunctions = [timingFunction, timingFunction] 47 | animation.values = [1, 0.7, 1] 48 | animation.repeatCount = HUGE 49 | animation.isRemovedOnCompletion = false 50 | 51 | // Draw circles 52 | for i in 0 ..< 3 { 53 | for j in 0 ..< 3 { 54 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 55 | let frame = CGRect(x: x + circleSize * CGFloat(j) + circleSpacing * CGFloat(j), 56 | y: y + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), 57 | width: circleSize, 58 | height: circleSize) 59 | 60 | animation.duration = durations[3 * i + j] 61 | animation.beginTime = beginTime + beginTimes[3 * i + j] 62 | circle.frame = frame 63 | circle.add(animation, forKey: "animation") 64 | layer.addSublayer(circle) 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallGridPulse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallGridPulse.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallGridPulse: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSpacing: CGFloat = 2 34 | let circleSize = (size.width - circleSpacing * 2) / 3 35 | let x = (layer.bounds.size.width - size.width) / 2 36 | let y = (layer.bounds.size.height - size.height) / 2 37 | let durations: [CFTimeInterval] = [0.72, 1.02, 1.28, 1.42, 1.45, 1.18, 0.87, 1.45, 1.06] 38 | let beginTime = CACurrentMediaTime() 39 | let beginTimes: [CFTimeInterval] = [ -0.06, 0.25, -0.17, 0.48, 0.31, 0.03, 0.46, 0.78, 0.45] 40 | let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) 41 | 42 | // Scale animation 43 | let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") 44 | 45 | scaleAnimation.keyTimes = [0, 0.5, 1] 46 | scaleAnimation.timingFunctions = [timingFunction, timingFunction] 47 | scaleAnimation.values = [1, 0.5, 1] 48 | 49 | // Opacity animation 50 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 51 | 52 | opacityAnimation.keyTimes = [0, 0.5, 1] 53 | opacityAnimation.timingFunctions = [timingFunction, timingFunction] 54 | opacityAnimation.values = [1, 0.7, 1] 55 | 56 | // Animation 57 | let animation = CAAnimationGroup() 58 | 59 | animation.animations = [scaleAnimation, opacityAnimation] 60 | animation.repeatCount = HUGE 61 | animation.isRemovedOnCompletion = false 62 | 63 | // Draw circles 64 | for i in 0 ..< 3 { 65 | for j in 0 ..< 3 { 66 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 67 | let frame = CGRect(x: x + circleSize * CGFloat(j) + circleSpacing * CGFloat(j), 68 | y: y + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), 69 | width: circleSize, 70 | height: circleSize) 71 | 72 | animation.duration = durations[3 * i + j] 73 | animation.beginTime = beginTime + beginTimes[3 * i + j] 74 | circle.frame = frame 75 | circle.add(animation, forKey: "animation") 76 | layer.addSublayer(circle) 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallPulse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallPulse.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallPulse: NVActivityIndicatorAnimationDelegate { 31 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 32 | let circleSpacing: CGFloat = 2 33 | let circleSize: CGFloat = (size.width - 2 * circleSpacing) / 3 34 | let x: CGFloat = (layer.bounds.size.width - size.width) / 2 35 | let y: CGFloat = (layer.bounds.size.height - circleSize) / 2 36 | let duration: CFTimeInterval = 0.75 37 | let beginTime = CACurrentMediaTime() 38 | let beginTimes: [CFTimeInterval] = [0.12, 0.24, 0.36] 39 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.2, 0.68, 0.18, 1.08) 40 | let animation = CAKeyframeAnimation(keyPath: "transform.scale") 41 | 42 | // Animation 43 | animation.keyTimes = [0, 0.3, 1] 44 | animation.timingFunctions = [timingFunction, timingFunction] 45 | animation.values = [1, 0.3, 1] 46 | animation.duration = duration 47 | animation.repeatCount = HUGE 48 | animation.isRemovedOnCompletion = false 49 | 50 | // Draw circles 51 | for i in 0 ..< 3 { 52 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 53 | let frame = CGRect(x: x + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), 54 | y: y, 55 | width: circleSize, 56 | height: circleSize) 57 | 58 | animation.beginTime = beginTime + beginTimes[i] 59 | circle.frame = frame 60 | circle.add(animation, forKey: "animation") 61 | layer.addSublayer(circle) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallPulseSync.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallPulseSync.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallPulseSync: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSpacing: CGFloat = 2 34 | let circleSize = (size.width - circleSpacing * 2) / 3 35 | let x = (layer.bounds.size.width - size.width) / 2 36 | let y = (layer.bounds.size.height - circleSize) / 2 37 | let deltaY = (size.height / 2 - circleSize / 2) / 2 38 | let duration: CFTimeInterval = 0.6 39 | let beginTime = CACurrentMediaTime() 40 | let beginTimes: [CFTimeInterval] = [0.07, 0.14, 0.21] 41 | let timingFunciton = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 42 | 43 | // Animation 44 | let animation = CAKeyframeAnimation(keyPath: "transform.translation.y") 45 | 46 | animation.keyTimes = [0, 0.33, 0.66, 1] 47 | animation.timingFunctions = [timingFunciton, timingFunciton, timingFunciton] 48 | animation.values = [0, deltaY, -deltaY, 0] 49 | animation.duration = duration 50 | animation.repeatCount = HUGE 51 | animation.isRemovedOnCompletion = false 52 | 53 | // Draw circles 54 | for i in 0 ..< 3 { 55 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 56 | let frame = CGRect(x: x + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), 57 | y: y, 58 | width: circleSize, 59 | height: circleSize) 60 | 61 | animation.beginTime = beginTime + beginTimes[i] 62 | circle.frame = frame 63 | circle.add(animation, forKey: "animation") 64 | layer.addSublayer(circle) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallRotateChase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallRotateChase.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallRotateChase: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSize = size.width / 5 34 | 35 | // Draw circles 36 | for i in 0 ..< 5 { 37 | let factor = Float(i) * 1 / 5 38 | let circle = NVActivityIndicatorShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) 39 | let animation = rotateAnimation(factor, x: layer.bounds.size.width / 2, y: layer.bounds.size.height / 2, size: CGSize(width: size.width - circleSize, height: size.height - circleSize)) 40 | 41 | circle.frame = CGRect(x: 0, y: 0, width: circleSize, height: circleSize) 42 | circle.add(animation, forKey: "animation") 43 | layer.addSublayer(circle) 44 | } 45 | } 46 | 47 | func rotateAnimation(_ rate: Float, x: CGFloat, y: CGFloat, size: CGSize) -> CAAnimationGroup { 48 | let duration: CFTimeInterval = 1.5 49 | let fromScale = 1 - rate 50 | let toScale = 0.2 + rate 51 | let timeFunc = CAMediaTimingFunction(controlPoints: 0.5, 0.15 + rate, 0.25, 1) 52 | 53 | // Scale animation 54 | let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") 55 | scaleAnimation.duration = duration 56 | scaleAnimation.repeatCount = HUGE 57 | scaleAnimation.fromValue = fromScale 58 | scaleAnimation.toValue = toScale 59 | 60 | // Position animation 61 | let positionAnimation = CAKeyframeAnimation(keyPath: "position") 62 | positionAnimation.duration = duration 63 | positionAnimation.repeatCount = HUGE 64 | positionAnimation.path = UIBezierPath(arcCenter: CGPoint(x: x, y: y), radius: size.width / 2, startAngle: CGFloat(3 * Double.pi * 0.5), endAngle: CGFloat(3 * Double.pi * 0.5 + 2 * Double.pi), clockwise: true).cgPath 65 | 66 | // Aniamtion 67 | let animation = CAAnimationGroup() 68 | animation.animations = [scaleAnimation, positionAnimation] 69 | animation.timingFunction = timeFunc 70 | animation.duration = duration 71 | animation.repeatCount = HUGE 72 | animation.isRemovedOnCompletion = false 73 | 74 | return animation 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallScale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallScale.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallScale: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 1 34 | 35 | // Scale animation 36 | let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") 37 | 38 | scaleAnimation.duration = duration 39 | scaleAnimation.fromValue = 0 40 | scaleAnimation.toValue = 1 41 | 42 | // Opacity animation 43 | let opacityAnimation = CABasicAnimation(keyPath: "opacity") 44 | 45 | opacityAnimation.duration = duration 46 | opacityAnimation.fromValue = 1 47 | opacityAnimation.toValue = 0 48 | 49 | // Animation 50 | let animation = CAAnimationGroup() 51 | 52 | animation.animations = [scaleAnimation, opacityAnimation] 53 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 54 | animation.duration = duration 55 | animation.repeatCount = HUGE 56 | animation.isRemovedOnCompletion = false 57 | 58 | // Draw circle 59 | let circle = NVActivityIndicatorShape.circle.layerWith(size: size, color: color) 60 | 61 | circle.frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 62 | y: (layer.bounds.size.height - size.height) / 2, 63 | width: size.width, 64 | height: size.height) 65 | circle.add(animation, forKey: "animation") 66 | layer.addSublayer(circle) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallScaleMultiple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallScaleMultiple.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallScaleMultiple: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 1 34 | let beginTime = CACurrentMediaTime() 35 | let beginTimes = [0, 0.2, 0.4] 36 | 37 | // Scale animation 38 | let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") 39 | 40 | scaleAnimation.duration = duration 41 | scaleAnimation.fromValue = 0 42 | scaleAnimation.toValue = 1 43 | 44 | // Opacity animation 45 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 46 | 47 | opacityAnimation.duration = duration 48 | opacityAnimation.keyTimes = [0, 0.05, 1] 49 | opacityAnimation.values = [0, 1, 0] 50 | 51 | // Animation 52 | let animation = CAAnimationGroup() 53 | 54 | animation.animations = [scaleAnimation, opacityAnimation] 55 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 56 | animation.duration = duration 57 | animation.repeatCount = HUGE 58 | animation.isRemovedOnCompletion = false 59 | 60 | // Draw balls 61 | for i in 0 ..< 3 { 62 | let circle = NVActivityIndicatorShape.circle.layerWith(size: size, color: color) 63 | let frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 64 | y: (layer.bounds.size.height - size.height) / 2, 65 | width: size.width, 66 | height: size.height) 67 | 68 | animation.beginTime = beginTime + beginTimes[i] 69 | circle.frame = frame 70 | circle.opacity = 0 71 | circle.add(animation, forKey: "animation") 72 | layer.addSublayer(circle) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallScaleRipple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallScaleRipple.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallScaleRipple: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 1 34 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.21, 0.53, 0.56, 0.8) 35 | 36 | // Scale animation 37 | let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") 38 | 39 | scaleAnimation.keyTimes = [0, 0.7] 40 | scaleAnimation.timingFunction = timingFunction 41 | scaleAnimation.values = [0.1, 1] 42 | scaleAnimation.duration = duration 43 | 44 | // Opacity animation 45 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 46 | 47 | opacityAnimation.keyTimes = [0, 0.7, 1] 48 | opacityAnimation.timingFunctions = [timingFunction, timingFunction] 49 | opacityAnimation.values = [1, 0.7, 0] 50 | opacityAnimation.duration = duration 51 | 52 | // Animation 53 | let animation = CAAnimationGroup() 54 | 55 | animation.animations = [scaleAnimation, opacityAnimation] 56 | animation.duration = duration 57 | animation.repeatCount = HUGE 58 | animation.isRemovedOnCompletion = false 59 | 60 | // Draw circle 61 | let circle = NVActivityIndicatorShape.ring.layerWith(size: size, color: color) 62 | let frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 63 | y: (layer.bounds.size.height - size.height) / 2, 64 | width: size.width, 65 | height: size.height) 66 | 67 | circle.frame = frame 68 | circle.add(animation, forKey: "animation") 69 | layer.addSublayer(circle) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallScaleRippleMultiple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallScaleRippleMultiple.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallScaleRippleMultiple: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 1.25 34 | let beginTime = CACurrentMediaTime() 35 | let beginTimes = [0, 0.2, 0.4] 36 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.21, 0.53, 0.56, 0.8) 37 | 38 | // Scale animation 39 | let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") 40 | 41 | scaleAnimation.keyTimes = [0, 0.7] 42 | scaleAnimation.timingFunction = timingFunction 43 | scaleAnimation.values = [0, 1] 44 | scaleAnimation.duration = duration 45 | 46 | // Opacity animation 47 | let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") 48 | 49 | opacityAnimation.keyTimes = [0, 0.7, 1] 50 | opacityAnimation.timingFunctions = [timingFunction, timingFunction] 51 | opacityAnimation.values = [1, 0.7, 0] 52 | opacityAnimation.duration = duration 53 | 54 | // Animation 55 | let animation = CAAnimationGroup() 56 | 57 | animation.animations = [scaleAnimation, opacityAnimation] 58 | animation.duration = duration 59 | animation.repeatCount = HUGE 60 | animation.isRemovedOnCompletion = false 61 | 62 | // Draw circles 63 | for i in 0 ..< 3 { 64 | let circle = NVActivityIndicatorShape.ring.layerWith(size: size, color: color) 65 | let frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 66 | y: (layer.bounds.size.height - size.height) / 2, 67 | width: size.width, 68 | height: size.height) 69 | 70 | animation.beginTime = beginTime + beginTimes[i] 71 | circle.frame = frame 72 | circle.add(animation, forKey: "animation") 73 | layer.addSublayer(circle) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallZigZag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallZigZag.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | import QuartzCore 30 | 31 | class NVActivityIndicatorAnimationBallZigZag: NVActivityIndicatorAnimationDelegate { 32 | 33 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 34 | let circleSize: CGFloat = size.width / 5 35 | let duration: CFTimeInterval = 0.7 36 | let deltaX = size.width / 2 - circleSize / 2 37 | let deltaY = size.height / 2 - circleSize / 2 38 | let frame = CGRect(x: (layer.bounds.size.width - circleSize) / 2, y: (layer.bounds.size.height - circleSize) / 2, width: circleSize, height: circleSize) 39 | 40 | // Circle 1 animation 41 | let animation = CAKeyframeAnimation(keyPath: "transform") 42 | 43 | animation.keyTimes = [0, 0.33, 0.66, 1] 44 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 45 | 46 | animation.values = [ 47 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 48 | NSValue(caTransform3D: CATransform3DMakeTranslation(-deltaX, -deltaY, 0)), 49 | NSValue(caTransform3D: CATransform3DMakeTranslation(deltaX, -deltaY, 0)), 50 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 51 | ] 52 | animation.duration = duration 53 | animation.repeatCount = HUGE 54 | animation.isRemovedOnCompletion = false 55 | 56 | // Draw circle 1 57 | circleAt(frame: frame, layer: layer, size: CGSize(width: circleSize, height: circleSize), color: color, animation: animation) 58 | 59 | // Circle 2 animation 60 | animation.values = [ 61 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 62 | NSValue(caTransform3D: CATransform3DMakeTranslation(deltaX, deltaY, 0)), 63 | NSValue(caTransform3D: CATransform3DMakeTranslation(-deltaX, deltaY, 0)), 64 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 65 | ] 66 | 67 | // Draw circle 2 68 | circleAt(frame: frame, layer: layer, size: CGSize(width: circleSize, height: circleSize), color: color, animation: animation) 69 | } 70 | 71 | func circleAt(frame: CGRect, layer: CALayer, size: CGSize, color: UIColor, animation: CAAnimation) { 72 | let circle = NVActivityIndicatorShape.circle.layerWith(size: size, color: color) 73 | 74 | circle.frame = frame 75 | circle.add(animation, forKey: "animation") 76 | layer.addSublayer(circle) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBallZigZagDeflect.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBallZigZagDeflect.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBallZigZagDeflect: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let circleSize: CGFloat = size.width / 5 34 | let duration: CFTimeInterval = 0.75 35 | let deltaX = size.width / 2 - circleSize / 2 36 | let deltaY = size.height / 2 - circleSize / 2 37 | let frame = CGRect(x: (layer.bounds.size.width - circleSize) / 2, y: (layer.bounds.size.height - circleSize) / 2, width: circleSize, height: circleSize) 38 | 39 | // Circle 1 animation 40 | let animation = CAKeyframeAnimation(keyPath: "transform") 41 | 42 | animation.keyTimes = [0, 0.33, 0.66, 1] 43 | animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 44 | 45 | animation.values = [ 46 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 47 | NSValue(caTransform3D: CATransform3DMakeTranslation(-deltaX, -deltaY, 0)), 48 | NSValue(caTransform3D: CATransform3DMakeTranslation(deltaX, -deltaY, 0)), 49 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 50 | ] 51 | animation.duration = duration 52 | animation.repeatCount = HUGE 53 | animation.autoreverses = true 54 | animation.isRemovedOnCompletion = false 55 | 56 | // Draw circle 1 57 | circleAt(frame: frame, layer: layer, size: CGSize(width: circleSize, height: circleSize), color: color, animation: animation) 58 | 59 | // Circle 2 animation 60 | animation.values = [ 61 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 62 | NSValue(caTransform3D: CATransform3DMakeTranslation(deltaX, deltaY, 0)), 63 | NSValue(caTransform3D: CATransform3DMakeTranslation(-deltaX, deltaY, 0)), 64 | NSValue(caTransform3D: CATransform3DMakeTranslation(0, 0, 0)), 65 | ] 66 | 67 | // Draw circle 2 68 | circleAt(frame: frame, layer: layer, size: CGSize(width: circleSize, height: circleSize), color: color, animation: animation) 69 | } 70 | 71 | func circleAt(frame: CGRect, layer: CALayer, size: CGSize, color: UIColor, animation: CAAnimation) { 72 | let circle = NVActivityIndicatorShape.circle.layerWith(size: size, color: color) 73 | 74 | circle.frame = frame 75 | circle.add(animation, forKey: "animation") 76 | layer.addSublayer(circle) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationBlank.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBlank.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationBlank: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in _: CALayer, size _: CGSize, color _: UIColor) { 33 | // Do nothing 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationLineScale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationBarScale.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationLineScale: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let lineSize = size.width / 9 34 | let x = (layer.bounds.size.width - size.width) / 2 35 | let y = (layer.bounds.size.height - size.height) / 2 36 | let duration: CFTimeInterval = 1 37 | let beginTime = CACurrentMediaTime() 38 | let beginTimes = [0.1, 0.2, 0.3, 0.4, 0.5] 39 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.2, 0.68, 0.18, 1.08) 40 | 41 | // Animation 42 | let animation = CAKeyframeAnimation(keyPath: "transform.scale.y") 43 | 44 | animation.keyTimes = [0, 0.5, 1] 45 | animation.timingFunctions = [timingFunction, timingFunction] 46 | animation.values = [1, 0.4, 1] 47 | animation.duration = duration 48 | animation.repeatCount = HUGE 49 | animation.isRemovedOnCompletion = false 50 | 51 | // Draw lines 52 | for i in 0 ..< 5 { 53 | let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color) 54 | let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), y: y, width: lineSize, height: size.height) 55 | 56 | animation.beginTime = beginTime + beginTimes[i] 57 | line.frame = frame 58 | line.add(animation, forKey: "animation") 59 | layer.addSublayer(line) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationLineScaleParty.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationLineScaleParty.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationLineScaleParty: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let lineSize = size.width / 7 34 | let x = (layer.bounds.size.width - size.width) / 2 35 | let y = (layer.bounds.size.height - size.height) / 2 36 | let durations: [CFTimeInterval] = [1.26, 0.43, 1.01, 0.73] 37 | let beginTime = CACurrentMediaTime() 38 | let beginTimes: [CFTimeInterval] = [0.77, 0.29, 0.28, 0.74] 39 | let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) 40 | 41 | // Animation 42 | let animation = CAKeyframeAnimation(keyPath: "transform.scale") 43 | 44 | animation.keyTimes = [0, 0.5, 1] 45 | animation.timingFunctions = [timingFunction, timingFunction] 46 | animation.values = [1, 0.5, 1] 47 | animation.repeatCount = HUGE 48 | animation.isRemovedOnCompletion = false 49 | 50 | for i in 0 ..< 4 { 51 | let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color) 52 | let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), y: y, width: lineSize, height: size.height) 53 | 54 | animation.beginTime = beginTime + beginTimes[i] 55 | animation.duration = durations[i] 56 | line.frame = frame 57 | line.add(animation, forKey: "animation") 58 | layer.addSublayer(line) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationLineScalePulseOut.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationLineScalePulseOut.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationLineScalePulseOut: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let lineSize = size.width / 9 34 | let x = (layer.bounds.size.width - size.width) / 2 35 | let y = (layer.bounds.size.height - size.height) / 2 36 | let duration: CFTimeInterval = 1 37 | let beginTime = CACurrentMediaTime() 38 | let beginTimes = [0.4, 0.2, 0, 0.2, 0.4] 39 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.85, 0.25, 0.37, 0.85) 40 | 41 | // Animation 42 | let animation = CAKeyframeAnimation(keyPath: "transform.scale.y") 43 | 44 | animation.keyTimes = [0, 0.5, 1] 45 | animation.timingFunctions = [timingFunction, timingFunction] 46 | animation.values = [1, 0.4, 1] 47 | animation.duration = duration 48 | animation.repeatCount = HUGE 49 | animation.isRemovedOnCompletion = false 50 | 51 | // Draw lines 52 | for i in 0 ..< 5 { 53 | let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color) 54 | let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), 55 | y: y, 56 | width: lineSize, 57 | height: size.height) 58 | 59 | animation.beginTime = beginTime + beginTimes[i] 60 | line.frame = frame 61 | line.add(animation, forKey: "animation") 62 | layer.addSublayer(line) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationLineScalePulseOutRapid.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationLineScalePulseOutRapid.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationLineScalePulseOutRapid: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let lineSize = size.width / 9 34 | let x = (layer.bounds.size.width - size.width) / 2 35 | let y = (layer.bounds.size.height - size.height) / 2 36 | let duration: CFTimeInterval = 0.9 37 | let beginTime = CACurrentMediaTime() 38 | let beginTimes = [0.5, 0.25, 0, 0.25, 0.5] 39 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.11, 0.49, 0.38, 0.78) 40 | 41 | // Animation 42 | let animation = CAKeyframeAnimation(keyPath: "transform.scale.y") 43 | 44 | animation.keyTimes = [0, 0.8, 0.9] 45 | animation.timingFunctions = [timingFunction, timingFunction] 46 | animation.beginTime = beginTime 47 | animation.values = [1, 0.3, 1] 48 | animation.duration = duration 49 | animation.repeatCount = HUGE 50 | animation.isRemovedOnCompletion = false 51 | 52 | // Draw lines 53 | for i in 0 ..< 5 { 54 | let line = NVActivityIndicatorShape.line.layerWith(size: CGSize(width: lineSize, height: size.height), color: color) 55 | let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), 56 | y: y, 57 | width: lineSize, 58 | height: size.height) 59 | 60 | animation.beginTime = beginTime + beginTimes[i] 61 | line.frame = frame 62 | line.add(animation, forKey: "animation") 63 | layer.addSublayer(line) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationSemiCircleSpin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationSemiCircleSpin.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationSemiCircleSpin: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 0.6 34 | 35 | // Animation 36 | let animation = CAKeyframeAnimation(keyPath: "transform.rotation.z") 37 | 38 | animation.keyTimes = [0, 0.5, 1] 39 | animation.values = [0, Double.pi, 2 * Double.pi] 40 | animation.duration = duration 41 | animation.repeatCount = HUGE 42 | animation.isRemovedOnCompletion = false 43 | 44 | // Draw circle 45 | let circle = NVActivityIndicatorShape.circleSemi.layerWith(size: size, color: color) 46 | let frame = CGRect( 47 | x: (layer.bounds.width - size.width) / 2, 48 | y: (layer.bounds.height - size.height) / 2, 49 | width: size.width, 50 | height: size.height 51 | ) 52 | 53 | circle.frame = frame 54 | circle.add(animation, forKey: "animation") 55 | layer.addSublayer(circle) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationSquareSpin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationSquareSpin.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationSquareSpin: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let duration: CFTimeInterval = 3 34 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.09, 0.57, 0.49, 0.9) 35 | 36 | // Animation 37 | let animation = CAKeyframeAnimation(keyPath: "transform") 38 | 39 | animation.keyTimes = [0, 0.25, 0.5, 0.75, 1] 40 | animation.timingFunctions = [timingFunction, timingFunction, timingFunction, timingFunction] 41 | animation.values = [ 42 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: 0))), 43 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: CGFloat(Double.pi)), createRotateYTransform(angle: 0))), 44 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: CGFloat(Double.pi)), createRotateYTransform(angle: CGFloat(Double.pi)))), 45 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: CGFloat(Double.pi)))), 46 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: 0))), 47 | ] 48 | animation.duration = duration 49 | animation.repeatCount = HUGE 50 | animation.isRemovedOnCompletion = false 51 | 52 | // Draw square 53 | let square = NVActivityIndicatorShape.rectangle.layerWith(size: size, color: color) 54 | let frame = CGRect(x: (layer.bounds.size.width - size.width) / 2, 55 | y: (layer.bounds.size.height - size.height) / 2, 56 | width: size.width, 57 | height: size.height) 58 | 59 | square.frame = frame 60 | square.add(animation, forKey: "animation") 61 | layer.addSublayer(square) 62 | } 63 | 64 | func createRotateXTransform(angle: CGFloat) -> CATransform3D { 65 | var transform = CATransform3DMakeRotation(angle, 1, 0, 0) 66 | 67 | transform.m34 = CGFloat(-1) / 100 68 | 69 | return transform 70 | } 71 | 72 | func createRotateYTransform(angle: CGFloat) -> CATransform3D { 73 | var transform = CATransform3DMakeRotation(angle, 0, 1, 0) 74 | 75 | transform.m34 = CGFloat(-1) / 100 76 | 77 | return transform 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/Animations/NVActivityIndicatorAnimationTriangleSkewSpin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorAnimationTriangleSkewSpin.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | class NVActivityIndicatorAnimationTriangleSkewSpin: NVActivityIndicatorAnimationDelegate { 31 | 32 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) { 33 | let x = (layer.bounds.size.width - size.width) / 2 34 | let y = (layer.bounds.size.height - size.height) / 2 35 | let duration: CFTimeInterval = 3 36 | let timingFunction = CAMediaTimingFunction(controlPoints: 0.09, 0.57, 0.49, 0.9) 37 | 38 | // Animation 39 | let animation = CAKeyframeAnimation(keyPath: "transform") 40 | 41 | animation.keyTimes = [0, 0.25, 0.5, 0.75, 1] 42 | animation.timingFunctions = [timingFunction, timingFunction, timingFunction, timingFunction] 43 | animation.values = [ 44 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: 0))), 45 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: CGFloat(Double.pi)), createRotateYTransform(angle: 0))), 46 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: CGFloat(Double.pi)), createRotateYTransform(angle: CGFloat(Double.pi)))), 47 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: CGFloat(Double.pi)))), 48 | NSValue(caTransform3D: CATransform3DConcat(createRotateXTransform(angle: 0), createRotateYTransform(angle: 0))), 49 | ] 50 | animation.duration = duration 51 | animation.repeatCount = HUGE 52 | animation.isRemovedOnCompletion = false 53 | 54 | // Draw triangle 55 | let triangle = NVActivityIndicatorShape.triangle.layerWith(size: size, color: color) 56 | 57 | triangle.frame = CGRect(x: x, y: y, width: size.width, height: size.height) 58 | triangle.add(animation, forKey: "animation") 59 | layer.addSublayer(triangle) 60 | } 61 | 62 | func createRotateXTransform(angle: CGFloat) -> CATransform3D { 63 | var transform = CATransform3DMakeRotation(angle, 1, 0, 0) 64 | 65 | transform.m34 = CGFloat(-1) / 100 66 | 67 | return transform 68 | } 69 | 70 | func createRotateYTransform(angle: CGFloat) -> CATransform3D { 71 | var transform = CATransform3DMakeRotation(angle, 0, 1, 0) 72 | 73 | transform.m34 = CGFloat(-1) / 100 74 | 75 | return transform 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/NVActivityIndicatorAnimationDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorDelegate.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | protocol NVActivityIndicatorAnimationDelegate { 31 | func setUpAnimation(in layer: CALayer, size: CGSize, color: UIColor) 32 | } 33 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/NVActivityIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorView.h 3 | // NVActivityIndicatorView 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | #import 29 | 30 | //! Project version number for NVActivityIndicatorView. 31 | FOUNDATION_EXPORT double NVActivityIndicatorViewVersionNumber; 32 | 33 | //! Project version string for NVActivityIndicatorView. 34 | FOUNDATION_EXPORT const unsigned char NVActivityIndicatorViewVersionString[]; 35 | 36 | // In this header, you should import all the public headers of your framework using statements like #import 37 | 38 | 39 | -------------------------------------------------------------------------------- /PhotoBrowser/Frameworks/NVActivityIndicatorView/NVActivityIndicatorViewable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NVActivityIndicatorViewable.swift 3 | // NVActivityIndicatorViewDemo 4 | // 5 | // The MIT License (MIT) 6 | 7 | // Copyright (c) 2016 Vinh Nguyen 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 all 17 | // 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 THE 25 | // SOFTWARE. 26 | // 27 | 28 | import UIKit 29 | 30 | /** 31 | * UIViewController conforms this protocol to be able to display NVActivityIndicatorView as UI blocker. 32 | * 33 | * This extends abilities of UIViewController to display and remove UI blocker. 34 | */ 35 | public protocol NVActivityIndicatorViewable {} 36 | 37 | public extension NVActivityIndicatorViewable where Self: UIViewController { 38 | 39 | /** 40 | Display UI blocker. 41 | 42 | Appropriate NVActivityIndicatorView.DEFAULT_* values are used for omitted params. 43 | 44 | - parameter size: size of activity indicator view. 45 | - parameter message: message displayed under activity indicator view. 46 | - parameter messageFont: font of message displayed under activity indicator view. 47 | - parameter type: animation type. 48 | - parameter color: color of activity indicator view. 49 | - parameter padding: padding of activity indicator view. 50 | - parameter displayTimeThreshold: display time threshold to actually display UI blocker. 51 | - parameter minimumDisplayTime: minimum display time of UI blocker. 52 | */ 53 | public final func startAnimating( 54 | _ size: CGSize? = nil, 55 | message: String? = nil, 56 | messageFont: UIFont? = nil, 57 | type: NVActivityIndicatorType? = nil, 58 | color: UIColor? = nil, 59 | padding: CGFloat? = nil, 60 | displayTimeThreshold: Int? = nil, 61 | minimumDisplayTime: Int? = nil, 62 | backgroundColor: UIColor? = nil, 63 | textColor: UIColor? = nil) { 64 | let activityData = ActivityData(size: size, 65 | message: message, 66 | messageFont: messageFont, 67 | type: type, 68 | color: color, 69 | padding: padding, 70 | displayTimeThreshold: displayTimeThreshold, 71 | minimumDisplayTime: minimumDisplayTime, 72 | backgroundColor: backgroundColor, 73 | textColor: textColor) 74 | 75 | NVActivityIndicatorPresenter.sharedInstance.startAnimating(activityData) 76 | } 77 | 78 | /** 79 | Remove UI blocker. 80 | */ 81 | public final func stopAnimating() { 82 | NVActivityIndicatorPresenter.sharedInstance.stopAnimating() 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/LaunchImage-2.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "minimum-system-version" : "7.0", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "orientation" : "portrait", 11 | "idiom" : "iphone", 12 | "minimum-system-version" : "7.0", 13 | "subtype" : "retina4", 14 | "scale" : "2x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "minimum-system-version" : "7.0", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "orientation" : "portrait", 11 | "idiom" : "iphone", 12 | "minimum-system-version" : "7.0", 13 | "subtype" : "retina4", 14 | "scale" : "2x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/1.imageset/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/1.imageset/1.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "1.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/10.imageset/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/10.imageset/10.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "10.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/2.imageset/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/2.imageset/2.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "2.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/3.imageset/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/3.imageset/3.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "3.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/4.imageset/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/4.imageset/4.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "4.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/5.imageset/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/5.imageset/5.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "5.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/6.imageset/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/6.imageset/6.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "6.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/7.imageset/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/7.imageset/7.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "7.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/8.imageset/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/8.imageset/8.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "8.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/9.imageset/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/Images.xcassets/Local/9.imageset/9.jpg -------------------------------------------------------------------------------- /PhotoBrowser/Images.xcassets/Local/9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "9.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PhotoBrowser/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 | UIInterfaceOrientationLandscapeRight 38 | 39 | UIViewControllerBasedStatusBarAppearance 40 | 41 | NSAppTransportSecurity 42 | 43 | NSAllowsArbitraryLoads 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /PhotoBrowser/LangVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum LangType: Int{ 12 | 13 | case english 14 | case chinese 15 | } 16 | 17 | 18 | 19 | 20 | 21 | class LangVC: UIViewController { 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | } 27 | } 28 | 29 | 30 | extension LangVC{ 31 | 32 | 33 | @IBAction func btnClick(_ sender: UIButton) { 34 | 35 | let photoTypeChooseVC = PhotoTypeChooseVC(nibName: "PhotoTypeChooseVC", bundle: nil) 36 | photoTypeChooseVC.langType = LangType(rawValue: sender.tag) 37 | self.navigationController?.pushViewController(photoTypeChooseVC, animated: true) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /PhotoBrowser/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Common/PhotoBrowser+Common.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CFPhotoBroserVC+Common.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/8/2. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | let CFPBExtraWidth: CGFloat = 20 13 | let CFPBThumbNailWH: CGFloat = 120 14 | 15 | let CFPBSingleTapNofi = "CFPBSingleTapNofi" 16 | let CFPBDismissBtnClickNoti = "CFPBDismissBtnClickNoti" 17 | let PhotoBrowserDidShowNoti = "PhotoBrowserDidShowNoti" 18 | let PhotoBrowserDidDismissNoti = "PhotoBrowserDidDismissNoti" 19 | let CFPBShowKey = "CFPBShowKey" 20 | let CFPBCacheKey = "CFPBCacheKey" 21 | 22 | extension CGSize{ 23 | 24 | var sizeWithExtraWidth: CGSize {return CGSize(width: self.width + CFPBExtraWidth, height: self.height)} 25 | 26 | var sizeMinusExtraWidth: CGSize {return CGSize(width: self.width - CFPBExtraWidth, height: self.height)} 27 | 28 | /** 按比例缩放 */ 29 | func ratioSize(_ ratio: CGFloat) -> CGSize{ 30 | 31 | return CGSize(width: self.width / ratio, height: self.height / ratio) } 32 | 33 | static func decisionShowSize(_ imgSize: CGSize, contentSize: CGSize) ->CGSize{ 34 | 35 | let heightRatio = imgSize.height / contentSize.height 36 | let widthRatio = imgSize.width / contentSize.width 37 | 38 | if heightRatio > 1 && widthRatio>1 {return imgSize.ratioSize(max(heightRatio, widthRatio))} 39 | 40 | if heightRatio > 1 && widthRatio <= 1 {return imgSize.ratioSize(heightRatio)} 41 | 42 | if heightRatio <= 1 && widthRatio > 1 {return imgSize.ratioSize(widthRatio)} 43 | 44 | if heightRatio <= 1 && widthRatio <= 1 {return imgSize.ratioSize(max(heightRatio, widthRatio))} 45 | 46 | return imgSize 47 | } 48 | } 49 | 50 | extension UIView{ 51 | 52 | /** Debug */ 53 | func debug(_ color: UIColor = UIColor.red, borderWidth: CGFloat = 5){ 54 | self.layer.borderColor = color.cgColor 55 | self.layer.borderWidth = borderWidth 56 | } 57 | 58 | } 59 | 60 | 61 | 62 | extension UIImage{ 63 | 64 | /** 源于色彩的UIImage,可自定义size */ 65 | class func imageWithColor(_ color: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1), size: CGSize = CGSize(width: 1, height: 1)) -> UIImage{ 66 | 67 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) 68 | 69 | //开启一个图形上下文 70 | UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) 71 | 72 | //获取图形上下文 73 | let context = UIGraphicsGetCurrentContext() 74 | 75 | context?.setFillColor(color.cgColor) 76 | 77 | context?.fill(rect) 78 | 79 | //获取图像 80 | let image = UIGraphicsGetImageFromCurrentImageContext() 81 | 82 | //关闭上下文 83 | UIGraphicsEndImageContext(); 84 | 85 | return image!; 86 | } 87 | } 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Common/pic.bundle/cancel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/PhotoBrowser/Common/pic.bundle/cancel@2x.png -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Common/pic.bundle/cancel@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/PhotoBrowser/Common/pic.bundle/cancel@3x.png -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Common/pic.bundle/save@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/PhotoBrowser/Common/pic.bundle/save@2x.png -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Common/pic.bundle/save@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharlinFeng/PhotoBrowser/54240e519f1fca65b850a65f11ae71138c673805/PhotoBrowser/PhotoBrowser/Common/pic.bundle/save@3x.png -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Controller/PhotoBrowser+HUD.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowser+HUD.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/11. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | extension PhotoBrowser{ 13 | 14 | 15 | /** 展示 */ 16 | func showHUD(_ text: String,autoDismiss: Double){ 17 | 18 | UIView.animate(withDuration: 0.25, animations: { () -> Void in 19 | self.hud.alpha = 1 20 | }) 21 | 22 | hud.text = text 23 | 24 | self.view.addSubview(hud) 25 | hud.make_center(offsest: CGPoint.zero, width: 120, height: 44) 26 | 27 | if autoDismiss == -1 {return} 28 | 29 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(autoDismiss * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {[unowned self] () -> Void in 30 | 31 | self.dismissHUD() 32 | }) 33 | } 34 | 35 | /** 消失 */ 36 | func dismissHUD(){ 37 | 38 | UIView.animate(withDuration: 0.25, animations: {[unowned self] () -> Void in 39 | 40 | self.hud.alpha = 0 41 | 42 | }, completion: { (compelte) -> Void in 43 | 44 | self.hud.text = "" 45 | 46 | self.hud.removeFromSuperview() 47 | }) 48 | } 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Controller/PhotoBrowser+Indicator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowser+Indicator.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/13. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension PhotoBrowser{ 12 | 13 | /** pagecontrol准备 */ 14 | func pagecontrolPrepare(){ 15 | 16 | if !hideMsgForZoomAndDismissWithSingleTap {return} 17 | 18 | view.addSubview(pagecontrol) 19 | pagecontrol.make_bottomInsets_bottomHeight(left: 0, bottom: 0, right: 0, bottomHeight: 37) 20 | pagecontrol.numberOfPages = photoModels.count 21 | pagecontrol.isEnabled = false 22 | } 23 | 24 | /** pageControl页面变动 */ 25 | func pageControlPageChanged(_ page: Int){ 26 | 27 | if page<0 || page>=photoModels.count {return} 28 | 29 | if showType == PhotoBrowser.ShowType.zoomAndDismissWithSingleTap && hideMsgForZoomAndDismissWithSingleTap{ 30 | 31 | pagecontrol.currentPage = page 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Controller/PhotoBrowser+PBType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowser+PBType.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/8/2. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension PhotoBrowser{ 13 | 14 | /** 展示样式 */ 15 | enum ShowType{ 16 | 17 | /** push展示:网易新闻 */ 18 | case push 19 | 20 | /** modal展示:可能有需要 */ 21 | case modal 22 | 23 | /** frame放大模式:单击相册可关闭 */ 24 | case zoomAndDismissWithSingleTap 25 | 26 | /** frame放大模式:点击按钮可关闭 */ 27 | case zoomAndDismissWithCancelBtnClick 28 | } 29 | 30 | 31 | /** 相册类型 */ 32 | enum PhotoType{ 33 | 34 | /** 本地相册 */ 35 | case local 36 | 37 | /** 服务器相册 */ 38 | case host 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Layout/Layout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Layout.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/7/29. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension PhotoBrowser{ 12 | 13 | 14 | class Layout: UICollectionViewFlowLayout { 15 | 16 | override init(){ 17 | 18 | super.init() 19 | 20 | /** 配置 */ 21 | layoutSetting() 22 | } 23 | 24 | required init(coder aDecoder: NSCoder) { 25 | super.init(coder: aDecoder)! 26 | } 27 | 28 | /** 配置 */ 29 | func layoutSetting(){ 30 | 31 | let size = UIScreen.main.bounds.size 32 | self.itemSize = size.sizeWithExtraWidth 33 | 34 | self.minimumInteritemSpacing = 0 35 | self.minimumLineSpacing = 0 36 | self.sectionInset = UIEdgeInsets.zero 37 | self.scrollDirection = UICollectionViewScrollDirection.horizontal 38 | } 39 | 40 | } 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/Model/PhotoBrowser+Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CFPhotoBroserVC+Model.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/8/10. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension PhotoBrowser{ 12 | 13 | class PhotoModel{ 14 | 15 | /** 本地相册模式下的本地相册数据 */ 16 | var localImg: UIImage! 17 | 18 | /** 网络相册模式下的网络相册URL地址 */ 19 | /** 高清 */ 20 | var hostHDImgURL: String! 21 | 22 | /** 缩略图 */ 23 | var hostThumbnailImg: UIImage! 24 | 25 | /** 标题 */ 26 | var titleStr: String! 27 | 28 | /** 详细说明文字 */ 29 | var descStr: String! 30 | 31 | /** 源ImageView: zoom模式需要传 */ 32 | var sourceView: UIView! 33 | 34 | var isLocal: Bool! 35 | 36 | /** 暴力去除异常 */ 37 | var excetionFlag = false 38 | 39 | /** 由于hanake有bug,增加此属性 */ 40 | var modelCell: UICollectionViewCell! 41 | 42 | /** 本地相册专业初始化方法 */ 43 | init(localImg: UIImage!, titleStr: String!, descStr: String!, sourceView: UIView!){ 44 | 45 | self.isLocal = true 46 | 47 | self.localImg = localImg 48 | self.titleStr = titleStr 49 | self.descStr = descStr 50 | self.sourceView = sourceView 51 | excetionFlag = true 52 | } 53 | 54 | 55 | /** 本地相册专业初始化方法 */ 56 | init(hostHDImgURL: String!, hostThumbnailImg: UIImage!, titleStr: String!, descStr: String!, sourceView: UIView!){ 57 | 58 | self.isLocal = false 59 | 60 | self.hostHDImgURL = hostHDImgURL 61 | self.hostThumbnailImg = hostThumbnailImg 62 | self.titleStr = titleStr 63 | self.descStr = descStr 64 | self.sourceView = sourceView 65 | excetionFlag = true 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/PhotoBrowser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowser.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/7/29. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PhotoBrowser: UIViewController { 12 | 13 | lazy var collectionView: UICollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: Layout()) 14 | 15 | /** 展示样式:请设置 */ 16 | var showType: ShowType! 17 | 18 | /** 相册类型:请设置 */ 19 | var photoType: PhotoType! 20 | 21 | /** 相册数据 */ 22 | var photoModels: [PhotoModel]!{didSet{collectionView.reloadData()}} 23 | 24 | /** 强制关闭一切信息显示: 仅仅针对ZoomAndDismissWithSingleTap模式有效 */ 25 | var hideMsgForZoomAndDismissWithSingleTap: Bool = false 26 | 27 | lazy var pagecontrol = UIPageControl() 28 | 29 | var page: Int = 0 {didSet{pageControlPageChanged(page)}} 30 | 31 | weak var vc: UIViewController! 32 | 33 | var isNavBarHidden: Bool! 34 | var isTabBarHidden: Bool! 35 | var isStatusBarHidden: Bool! 36 | 37 | var showIndex: Int = 0 38 | 39 | var dismissBtn,saveBtn: UIButton! 40 | var isHiddenBar: Bool = false 41 | 42 | lazy var photoArchiverArr: [Int] = [] 43 | 44 | deinit{NotificationCenter.default.removeObserver(self);print("deinit")} 45 | 46 | lazy var hud: UILabel = { 47 | 48 | let hud = UILabel() 49 | hud.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4) 50 | hud.textColor = UIColor.white 51 | hud.alpha = 0 52 | hud.textAlignment = NSTextAlignment.center 53 | hud.layer.cornerRadius = 5 54 | hud.layer.masksToBounds = true 55 | return hud 56 | }() 57 | } 58 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/View/CollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowser+CollectionView.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 成林 on 15/7/29. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension PhotoBrowser{ 12 | 13 | 14 | class CollectionView: UICollectionView { 15 | 16 | 17 | } 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoBrowser/View/ShowImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShowImageView.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/12. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShowImageView: UIImageView { 12 | var showSize:CGSize! 13 | } 14 | -------------------------------------------------------------------------------- /PhotoBrowser/PhotoTypeChooseVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TypeChooseVC.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | enum PhotoType: Int { 13 | 14 | case local 15 | case host 16 | } 17 | 18 | 19 | 20 | class PhotoTypeChooseVC: UIViewController { 21 | 22 | var langType: LangType! 23 | 24 | @IBOutlet weak var titleLabel: UILabel! 25 | 26 | @IBOutlet weak var localBtn: UIButton! 27 | 28 | @IBOutlet weak var hostBtn: UIButton! 29 | } 30 | 31 | extension PhotoTypeChooseVC{ 32 | 33 | override func viewDidLoad() { 34 | 35 | super.viewDidLoad() 36 | 37 | if langType == LangType.chinese {return} 38 | 39 | titleLabel.text = "Select Type" 40 | localBtn.setTitle("Local Album", for: UIControlState()) 41 | localBtn.titleLabel?.font = UIFont.systemFont(ofSize: 20) 42 | hostBtn.setTitle("Host Album", for: UIControlState()) 43 | hostBtn.titleLabel?.font = UIFont.systemFont(ofSize: 20) 44 | } 45 | 46 | @IBAction func btnClick(_ sender: UIButton) { 47 | 48 | let showTypeChooseVC = ShowTypeChooseTVC(style: UITableViewStyle.plain) 49 | showTypeChooseVC.langType = langType 50 | showTypeChooseVC.photoType = PhotoType(rawValue: sender.tag) 51 | self.navigationController?.pushViewController(showTypeChooseVC, animated: true) 52 | } 53 | 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /PhotoBrowser/ShowTypeChooseTVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShowTypeChooseVCTableViewController.swift 3 | // PhotoBrowser 4 | // 5 | // Created by 冯成林 on 15/8/14. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShowTypeChooseTVC: UITableViewController { 12 | 13 | var langType: LangType! 14 | 15 | var photoType: PhotoType! 16 | 17 | let rid = "ShowTypeChooseTVCCell" 18 | 19 | lazy var dataList: [String] = {["Push","Modal","CancelBtnClickDissmiss","SingleTapDismiss"]}() 20 | 21 | 22 | } 23 | 24 | extension ShowTypeChooseTVC{ 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | tableView.tableFooterView = UIView() 29 | } 30 | 31 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 32 | return dataList.count 33 | } 34 | 35 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 36 | 37 | let cell = tableView.dequeueReusableCell(withIdentifier: rid) ?? UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: rid) 38 | 39 | cell.textLabel?.text = dataList[indexPath.row] 40 | cell.textLabel?.font = UIFont.systemFont(ofSize: 24) 41 | return cell 42 | } 43 | 44 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 45 | return 80 46 | } 47 | 48 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 49 | 50 | let displayVC = DisplayVC() 51 | displayVC.langType = langType 52 | displayVC.photoType = photoType 53 | 54 | switch indexPath.row { 55 | 56 | case 0:displayVC.showType = PhotoBrowser.ShowType.push 57 | case 1:displayVC.showType = PhotoBrowser.ShowType.modal 58 | case 2:displayVC.showType = PhotoBrowser.ShowType.zoomAndDismissWithCancelBtnClick 59 | case 3:displayVC.showType = PhotoBrowser.ShowType.zoomAndDismissWithSingleTap 60 | default: break 61 | } 62 | 63 | self.navigationController?.pushViewController(displayVC, animated: true) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PhotoBrowserTests/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 | -------------------------------------------------------------------------------- /PhotoBrowserTests/PhotoBrowserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowserTests.swift 3 | // PhotoBrowserTests 4 | // 5 | // Created by 成林 on 15/8/15. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class PhotoBrowserTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | --------------------------------------------------------------------------------