diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..137985c --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# OS X Finder +.DS_Store + +# Xcode per-user config +*.mode1 +*.mode1v3 +*.mode2v3 +*.perspective +*.perspectivev3 +*.pbxuser +xcuserdata +*.xccheckout + +# Build products +build/ +*.o +*.LinkFileList +*.hmap + +# Automatic backup files +*~.nib/ +*.swp +*~ +*.dat +*.dep + +# AppCode specific files +.idea/ +*.iml + +# Cucumber console history +*.irb-history + +# Python specific files +*.pyc diff --git a/AppDelegate.swift b/AppDelegate.swift deleted file mode 100644 index 24bc691..0000000 --- a/AppDelegate.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// AppDelegate.swift -// Dindr -// -// Created by lsecrease on 8/9/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { - - Parse.enableLocalDatastore() - - // Parse App ID - Parse.setApplicationId("0rubnb7O4htTp2ebMAM2KXnPazFxilATgmZvKLde", clientKey: "0shAOvyF065qlhgquNoHwSlu7dLOtv6vavggY8fp") - - // Override point for customization after application launch. - return true - } - - func applicationWillResignActive(application: UIApplication) { - // 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. - // 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. - } - - func applicationDidEnterBackground(application: UIApplication) { - // 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. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(application: UIApplication) { - // 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. - } - - func applicationDidBecomeActive(application: UIApplication) { - // 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. - } - - func applicationWillTerminate(application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} - diff --git a/Base.lproj/LaunchScreen.xib b/Base.lproj/LaunchScreen.xib deleted file mode 100644 index b5956a6..0000000 --- a/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Base.lproj/Main.storyboard b/Base.lproj/Main.storyboard deleted file mode 100644 index a9409b3..0000000 --- a/Base.lproj/Main.storyboard +++ /dev/null @@ -1,615 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Dindr b/Dindr new file mode 160000 index 0000000..9aac091 --- /dev/null +++ b/Dindr @@ -0,0 +1 @@ +Subproject commit 9aac09113620ec7747b035d6449ef0c77820a046 diff --git a/Dindr-Bridging-Header.h b/Dindr-Bridging-Header.h deleted file mode 100644 index 69a90ae..0000000 --- a/Dindr-Bridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - -#import \ No newline at end of file diff --git a/Dindr.xcodeproj/project.pbxproj b/Dindr.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0e3780c --- /dev/null +++ b/Dindr.xcodeproj/project.pbxproj @@ -0,0 +1,726 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + A220C6DAAB6AF6BECEAE4045 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EF77CB6F97A26FE14C38AE /* Pods.framework */; }; + CE2D49C11BE06D28007DCBE3 /* SpecialsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */; }; + CE4605481BC33AB1007A2B7D /* GalleryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4605471BC33AB1007A2B7D /* GalleryVC.swift */; }; + CE46054A1BC33FA7007A2B7D /* GalleryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4605491BC33FA7007A2B7D /* GalleryCell.swift */; }; + CE9C42FD1BC1D6CD00504B69 /* AnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */; }; + CE9C42FE1BC1D6CD00504B69 /* ImageAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */; }; + CE9C42FF1BC1D6CD00504B69 /* ImageCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */; }; + CE9C43001BC1D6CD00504B69 /* ImagePickerCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */; }; + CE9C43011BC1D6CD00504B69 /* ImagePickerSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */; }; + CE9C43021BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */; }; + CE9C43031BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */; }; + CE9C43041BC1D6CD00504B69 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */; }; + CE9C43051BC1D6CD00504B69 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = CE9C42FB1BC1D6CD00504B69 /* Info.plist */; }; + CE9C43061BC1D6CD00504B69 /* PreviewSupplementaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */; }; + CE9F9EEF1B802C1B0060D993 /* RestaurantDataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */; }; + CEB40EBE1BD6B9D500863F60 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */; }; + CEB40EC11BD6B9EF00863F60 /* ImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */; }; + CEB40EC41BD6B9FB00863F60 /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */; }; + CEB40EC81BD6BA3C00863F60 /* ViewUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */; }; + CEB40ECB1BD6BA5D00863F60 /* UIImage+Crop.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */; }; + CEB40ECE1BD6BA6600863F60 /* UIImage+Resize.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */; }; + CEB40ED21BD6BA9200863F60 /* UIImage+FixOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */; }; + CEB40ED51BD6BA9C00863F60 /* LLSimpleCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */; }; + CEB40ED81BD6BCE700863F60 /* PreviewImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */; }; + CEB8897A1B7858A000B28A90 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889791B7858A000B28A90 /* AudioToolbox.framework */; }; + CEB8897C1B7858A500B28A90 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897B1B7858A500B28A90 /* CFNetwork.framework */; }; + CEB8897E1B7858B300B28A90 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */; }; + CEB889801B7858BA00B28A90 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */; }; + CEB889821B7858CD00B28A90 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889811B7858CD00B28A90 /* libz.dylib */; }; + CEB889841B7858E500B28A90 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889831B7858E500B28A90 /* MobileCoreServices.framework */; }; + CEB889861B7858ED00B28A90 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889851B7858ED00B28A90 /* QuartzCore.framework */; }; + CEB889881B7858FA00B28A90 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889871B7858FA00B28A90 /* Security.framework */; }; + CEB8898A1B78590100B28A90 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889891B78590100B28A90 /* StoreKit.framework */; }; + CEB8898C1B78591100B28A90 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */; }; + CEB8898E1B78592A00B28A90 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */; }; + CEBA3B521B7FB261009AE917 /* LoginVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBA3B511B7FB261009AE917 /* LoginVC.swift */; }; + CEC9F20D1B7851B3000A74A9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */; }; + CEC9F2121B7851B3000A74A9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2101B7851B3000A74A9 /* Main.storyboard */; }; + CEC9F2141B7851B3000A74A9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2131B7851B3000A74A9 /* Images.xcassets */; }; + CEC9F2171B7851B3000A74A9 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */; }; + CEC9F2231B7851B3000A74A9 /* DindrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC9F2221B7851B3000A74A9 /* DindrTests.swift */; }; + CEEF5DA01BA8A7610077769E /* RestCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */; }; + CEEF5DA21BA8A8BF0077769E /* DishModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5DA11BA8A8BF0077769E /* DishModel.swift */; }; + CEEF5DA41BA8B55F0077769E /* SpecialsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + CEC9F21D1B7851B3000A74A9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CEC9F1FF1B7851B3000A74A9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = CEC9F2061B7851B3000A74A9; + remoteInfo = Dindr; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + B9EF77CB6F97A26FE14C38AE /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecialsTableViewCell.swift; sourceTree = ""; }; + CE4605471BC33AB1007A2B7D /* GalleryVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryVC.swift; sourceTree = ""; }; + CE4605491BC33FA7007A2B7D /* GalleryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryCell.swift; sourceTree = ""; }; + CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationController.swift; sourceTree = ""; }; + CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAction.swift; sourceTree = ""; }; + CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCollectionViewCell.swift; sourceTree = ""; }; + CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerCollectionView.swift; sourceTree = ""; }; + CE9C42F61BC1D6CD00504B69 /* ImagePickerSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImagePickerSheetController.h; sourceTree = ""; }; + CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerSheetController.swift; sourceTree = ""; }; + CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePreviewFlowLayout.swift; sourceTree = ""; }; + CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePreviewTableViewCell.swift; sourceTree = ""; }; + CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + CE9C42FB1BC1D6CD00504B69 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewSupplementaryView.swift; sourceTree = ""; }; + CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestaurantDataViewController.swift; sourceTree = ""; }; + CEB40EBC1BD6B9D500863F60 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; }; + CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; }; + CEB40EBF1BD6B9EF00863F60 /* ImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageViewController.h; sourceTree = ""; }; + CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageViewController.m; sourceTree = ""; }; + CEB40EC21BD6B9FB00863F60 /* VideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; }; + CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; }; + CEB40EC61BD6BA3C00863F60 /* ViewUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewUtils.h; sourceTree = ""; }; + CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewUtils.m; sourceTree = ""; }; + CEB40EC91BD6BA5D00863F60 /* UIImage+Crop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Crop.h"; sourceTree = ""; }; + CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Crop.m"; sourceTree = ""; }; + CEB40ECC1BD6BA6600863F60 /* UIImage+Resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Resize.h"; sourceTree = ""; }; + CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Resize.m"; sourceTree = ""; }; + CEB40ED01BD6BA9200863F60 /* UIImage+FixOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixOrientation.h"; sourceTree = ""; }; + CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixOrientation.m"; sourceTree = ""; }; + CEB40ED31BD6BA9C00863F60 /* LLSimpleCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLSimpleCamera.h; sourceTree = ""; }; + CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLSimpleCamera.m; sourceTree = ""; }; + CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewImageViewController.swift; sourceTree = ""; }; + CEB889791B7858A000B28A90 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + CEB8897B1B7858A500B28A90 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + CEB889811B7858CD00B28A90 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + CEB889831B7858E500B28A90 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + CEB889851B7858ED00B28A90 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + CEB889871B7858FA00B28A90 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + CEB889891B78590100B28A90 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + CEB8898F1B78598100B28A90 /* Dindr-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Dindr-Bridging-Header.h"; sourceTree = ""; }; + CEBA3B511B7FB261009AE917 /* LoginVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginVC.swift; sourceTree = ""; }; + CEC9F2071B7851B3000A74A9 /* Dindr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Dindr.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CEC9F20B1B7851B3000A74A9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + CEC9F2111B7851B3000A74A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + CEC9F2131B7851B3000A74A9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + CEC9F2161B7851B3000A74A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DindrTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + CEC9F2211B7851B3000A74A9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CEC9F2221B7851B3000A74A9 /* DindrTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DindrTests.swift; sourceTree = ""; }; + CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestCollectionViewCell.swift; sourceTree = ""; }; + CEEF5DA11BA8A8BF0077769E /* DishModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DishModel.swift; sourceTree = ""; }; + CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecialsTableViewController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + CEC9F2041B7851B3000A74A9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CEB8898E1B78592A00B28A90 /* libsqlite3.dylib in Frameworks */, + CEB8898C1B78591100B28A90 /* SystemConfiguration.framework in Frameworks */, + CEB8898A1B78590100B28A90 /* StoreKit.framework in Frameworks */, + CEB889881B7858FA00B28A90 /* Security.framework in Frameworks */, + CEB889861B7858ED00B28A90 /* QuartzCore.framework in Frameworks */, + CEB889841B7858E500B28A90 /* MobileCoreServices.framework in Frameworks */, + CEB889821B7858CD00B28A90 /* libz.dylib in Frameworks */, + CEB889801B7858BA00B28A90 /* CoreLocation.framework in Frameworks */, + CEB8897E1B7858B300B28A90 /* CoreGraphics.framework in Frameworks */, + CEB8897C1B7858A500B28A90 /* CFNetwork.framework in Frameworks */, + CEB8897A1B7858A000B28A90 /* AudioToolbox.framework in Frameworks */, + A220C6DAAB6AF6BECEAE4045 /* Pods.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CEC9F2191B7851B3000A74A9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13F1B618C4156F8E977A6AF0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */, + CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */, + CEB889891B78590100B28A90 /* StoreKit.framework */, + CEB889871B7858FA00B28A90 /* Security.framework */, + CEB889851B7858ED00B28A90 /* QuartzCore.framework */, + CEB889831B7858E500B28A90 /* MobileCoreServices.framework */, + CEB889811B7858CD00B28A90 /* libz.dylib */, + CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */, + CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */, + CEB8897B1B7858A500B28A90 /* CFNetwork.framework */, + CEB889791B7858A000B28A90 /* AudioToolbox.framework */, + B9EF77CB6F97A26FE14C38AE /* Pods.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + CE46054B1BC33FAF007A2B7D /* Gallery */ = { + isa = PBXGroup; + children = ( + CE4605471BC33AB1007A2B7D /* GalleryVC.swift */, + CE4605491BC33FA7007A2B7D /* GalleryCell.swift */, + ); + name = Gallery; + sourceTree = ""; + }; + CE9C42F01BC1D36000504B69 /* Login */ = { + isa = PBXGroup; + children = ( + CEBA3B511B7FB261009AE917 /* LoginVC.swift */, + ); + name = Login; + sourceTree = ""; + }; + CE9C42F11BC1D6CD00504B69 /* ImagePickerSheet6.4 */ = { + isa = PBXGroup; + children = ( + CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */, + CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */, + CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */, + CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */, + CE9C42F61BC1D6CD00504B69 /* ImagePickerSheetController.h */, + CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */, + CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */, + CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */, + CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */, + CE9C42FB1BC1D6CD00504B69 /* Info.plist */, + CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */, + ); + path = ImagePickerSheet6.4; + sourceTree = ""; + }; + CEB40EC51BD6BA1100863F60 /* CameraControllers */ = { + isa = PBXGroup; + children = ( + CEB40EBC1BD6B9D500863F60 /* HomeViewController.h */, + CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */, + CEB40EBF1BD6B9EF00863F60 /* ImageViewController.h */, + CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */, + CEB40EC21BD6B9FB00863F60 /* VideoViewController.h */, + CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */, + ); + name = CameraControllers; + sourceTree = ""; + }; + CEB40ECF1BD6BA7300863F60 /* CameraUtilities */ = { + isa = PBXGroup; + children = ( + CEB40EC91BD6BA5D00863F60 /* UIImage+Crop.h */, + CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */, + CEB40EC61BD6BA3C00863F60 /* ViewUtils.h */, + CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */, + CEB40ECC1BD6BA6600863F60 /* UIImage+Resize.h */, + CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */, + ); + name = CameraUtilities; + sourceTree = ""; + }; + CEB40ED61BD6BAA700863F60 /* LLSimpleCamera */ = { + isa = PBXGroup; + children = ( + CEB40ED01BD6BA9200863F60 /* UIImage+FixOrientation.h */, + CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */, + CEB40ED31BD6BA9C00863F60 /* LLSimpleCamera.h */, + CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */, + ); + name = LLSimpleCamera; + sourceTree = ""; + }; + CEC9F1FE1B7851B3000A74A9 = { + isa = PBXGroup; + children = ( + CEC9F2091B7851B3000A74A9 /* Dindr */, + CEC9F21F1B7851B3000A74A9 /* DindrTests */, + CE9C42F11BC1D6CD00504B69 /* ImagePickerSheet6.4 */, + CEC9F2081B7851B3000A74A9 /* Products */, + DDA2E1AC0F8591B8D089FC9A /* Pods */, + 13F1B618C4156F8E977A6AF0 /* Frameworks */, + ); + sourceTree = ""; + }; + CEC9F2081B7851B3000A74A9 /* Products */ = { + isa = PBXGroup; + children = ( + CEC9F2071B7851B3000A74A9 /* Dindr.app */, + CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + CEC9F2091B7851B3000A74A9 /* Dindr */ = { + isa = PBXGroup; + children = ( + CEB40EC51BD6BA1100863F60 /* CameraControllers */, + CEB40ECF1BD6BA7300863F60 /* CameraUtilities */, + CEB40ED61BD6BAA700863F60 /* LLSimpleCamera */, + CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */, + CE9C42F01BC1D36000504B69 /* Login */, + CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */, + CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */, + CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */, + CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */, + CE46054B1BC33FAF007A2B7D /* Gallery */, + CEEF5DA11BA8A8BF0077769E /* DishModel.swift */, + CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */, + CEC9F2101B7851B3000A74A9 /* Main.storyboard */, + CEC9F2131B7851B3000A74A9 /* Images.xcassets */, + CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */, + CEC9F20A1B7851B3000A74A9 /* Supporting Files */, + CEB8898F1B78598100B28A90 /* Dindr-Bridging-Header.h */, + ); + path = Dindr; + sourceTree = ""; + }; + CEC9F20A1B7851B3000A74A9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + CEC9F20B1B7851B3000A74A9 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + CEC9F21F1B7851B3000A74A9 /* DindrTests */ = { + isa = PBXGroup; + children = ( + CEC9F2221B7851B3000A74A9 /* DindrTests.swift */, + CEC9F2201B7851B3000A74A9 /* Supporting Files */, + ); + path = DindrTests; + sourceTree = ""; + }; + CEC9F2201B7851B3000A74A9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + CEC9F2211B7851B3000A74A9 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + DDA2E1AC0F8591B8D089FC9A /* Pods */ = { + isa = PBXGroup; + children = ( + A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */, + A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CEC9F2061B7851B3000A74A9 /* Dindr */ = { + isa = PBXNativeTarget; + buildConfigurationList = CEC9F2261B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "Dindr" */; + buildPhases = ( + 94CC3B6E7308AC77FEB8A40C /* Check Pods Manifest.lock */, + CEC9F2031B7851B3000A74A9 /* Sources */, + CEC9F2041B7851B3000A74A9 /* Frameworks */, + CEC9F2051B7851B3000A74A9 /* Resources */, + 93EB0F68B7448BEF1603AA07 /* Copy Pods Resources */, + 5C8D724AC76E44C64B9AE57E /* Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Dindr; + productName = Dindr; + productReference = CEC9F2071B7851B3000A74A9 /* Dindr.app */; + productType = "com.apple.product-type.application"; + }; + CEC9F21B1B7851B3000A74A9 /* DindrTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = CEC9F2291B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "DindrTests" */; + buildPhases = ( + CEC9F2181B7851B3000A74A9 /* Sources */, + CEC9F2191B7851B3000A74A9 /* Frameworks */, + CEC9F21A1B7851B3000A74A9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CEC9F21E1B7851B3000A74A9 /* PBXTargetDependency */, + ); + name = DindrTests; + productName = DindrTests; + productReference = CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CEC9F1FF1B7851B3000A74A9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 0710; + LastSwiftUpdateCheck = 0710; + LastUpgradeCheck = 0640; + ORGANIZATIONNAME = ImagineME; + TargetAttributes = { + CEC9F2061B7851B3000A74A9 = { + CreatedOnToolsVersion = 6.4; + }; + CEC9F21B1B7851B3000A74A9 = { + CreatedOnToolsVersion = 6.4; + TestTargetID = CEC9F2061B7851B3000A74A9; + }; + }; + }; + buildConfigurationList = CEC9F2021B7851B3000A74A9 /* Build configuration list for PBXProject "Dindr" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CEC9F1FE1B7851B3000A74A9; + productRefGroup = CEC9F2081B7851B3000A74A9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CEC9F2061B7851B3000A74A9 /* Dindr */, + CEC9F21B1B7851B3000A74A9 /* DindrTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CEC9F2051B7851B3000A74A9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEC9F2121B7851B3000A74A9 /* Main.storyboard in Resources */, + CEC9F2171B7851B3000A74A9 /* LaunchScreen.xib in Resources */, + CE9C43041BC1D6CD00504B69 /* Images.xcassets in Resources */, + CEC9F2141B7851B3000A74A9 /* Images.xcassets in Resources */, + CE9C43051BC1D6CD00504B69 /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CEC9F21A1B7851B3000A74A9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 5C8D724AC76E44C64B9AE57E /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 93EB0F68B7448BEF1603AA07 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 94CC3B6E7308AC77FEB8A40C /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + CEC9F2031B7851B3000A74A9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CE9C43031BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift in Sources */, + CEEF5DA21BA8A8BF0077769E /* DishModel.swift in Sources */, + CEB40EC81BD6BA3C00863F60 /* ViewUtils.m in Sources */, + CEB40ED51BD6BA9C00863F60 /* LLSimpleCamera.m in Sources */, + CE9C43011BC1D6CD00504B69 /* ImagePickerSheetController.swift in Sources */, + CEB40ECB1BD6BA5D00863F60 /* UIImage+Crop.m in Sources */, + CE9C42FF1BC1D6CD00504B69 /* ImageCollectionViewCell.swift in Sources */, + CE46054A1BC33FA7007A2B7D /* GalleryCell.swift in Sources */, + CE2D49C11BE06D28007DCBE3 /* SpecialsTableViewCell.swift in Sources */, + CE9C43061BC1D6CD00504B69 /* PreviewSupplementaryView.swift in Sources */, + CE9C43021BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift in Sources */, + CE9C42FE1BC1D6CD00504B69 /* ImageAction.swift in Sources */, + CEB40EC11BD6B9EF00863F60 /* ImageViewController.m in Sources */, + CE9F9EEF1B802C1B0060D993 /* RestaurantDataViewController.swift in Sources */, + CEC9F20D1B7851B3000A74A9 /* AppDelegate.swift in Sources */, + CE4605481BC33AB1007A2B7D /* GalleryVC.swift in Sources */, + CEEF5DA41BA8B55F0077769E /* SpecialsTableViewController.swift in Sources */, + CEEF5DA01BA8A7610077769E /* RestCollectionViewCell.swift in Sources */, + CE9C42FD1BC1D6CD00504B69 /* AnimationController.swift in Sources */, + CEBA3B521B7FB261009AE917 /* LoginVC.swift in Sources */, + CEB40ED81BD6BCE700863F60 /* PreviewImageViewController.swift in Sources */, + CEB40ECE1BD6BA6600863F60 /* UIImage+Resize.m in Sources */, + CEB40EC41BD6B9FB00863F60 /* VideoViewController.m in Sources */, + CEB40EBE1BD6B9D500863F60 /* HomeViewController.m in Sources */, + CEB40ED21BD6BA9200863F60 /* UIImage+FixOrientation.m in Sources */, + CE9C43001BC1D6CD00504B69 /* ImagePickerCollectionView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CEC9F2181B7851B3000A74A9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CEC9F2231B7851B3000A74A9 /* DindrTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + CEC9F21E1B7851B3000A74A9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = CEC9F2061B7851B3000A74A9 /* Dindr */; + targetProxy = CEC9F21D1B7851B3000A74A9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + CEC9F2101B7851B3000A74A9 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CEC9F2111B7851B3000A74A9 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + CEC9F2161B7851B3000A74A9 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + CEC9F2241B7851B3000A74A9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + CEC9F2251B7851B3000A74A9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + CEC9F2271B7851B3000A74A9 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = Dindr/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Dindr/Dindr-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + CEC9F2281B7851B3000A74A9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = Dindr/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Dindr/Dindr-Bridging-Header.h"; + }; + name = Release; + }; + CEC9F22A1B7851B3000A74A9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = DindrTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Dindr.app/Dindr"; + }; + name = Debug; + }; + CEC9F22B1B7851B3000A74A9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = DindrTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Dindr.app/Dindr"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CEC9F2021B7851B3000A74A9 /* Build configuration list for PBXProject "Dindr" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CEC9F2241B7851B3000A74A9 /* Debug */, + CEC9F2251B7851B3000A74A9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CEC9F2261B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "Dindr" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CEC9F2271B7851B3000A74A9 /* Debug */, + CEC9F2281B7851B3000A74A9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CEC9F2291B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "DindrTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CEC9F22A1B7851B3000A74A9 /* Debug */, + CEC9F22B1B7851B3000A74A9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = CEC9F1FF1B7851B3000A74A9 /* Project object */; +} diff --git a/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..8f43cb9 --- /dev/null +++ b/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Dindr.xcworkspace/contents.xcworkspacedata b/Dindr.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d00d341 --- /dev/null +++ b/Dindr.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint b/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint new file mode 100644 index 0000000..a4f5da2 --- /dev/null +++ b/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "EACED2723BB5600B88834009D10CCB8CD2946702", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "EACED2723BB5600B88834009D10CCB8CD2946702" : 0, + "3CE173A00AFA646F21499F4BA53E756FEAEB54D6" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "637F2BFC-C9BA-434D-A08A-479B2E1C1C63", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "EACED2723BB5600B88834009D10CCB8CD2946702" : "Dindr\/", + "3CE173A00AFA646F21499F4BA53E756FEAEB54D6" : "Dindr\/Dindr\/" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "Dindr", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Dindr.xcworkspace", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/lsecrease\/Dindr.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3CE173A00AFA646F21499F4BA53E756FEAEB54D6" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JBader89\/RestaurantDindr.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EACED2723BB5600B88834009D10CCB8CD2946702" + } + ] +} \ No newline at end of file diff --git a/DindrTests/DindrTests.swift b/DindrTests/DindrTests.swift new file mode 100644 index 0000000..b691401 --- /dev/null +++ b/DindrTests/DindrTests.swift @@ -0,0 +1,36 @@ +// +// DindrTests.swift +// DindrTests +// +// Created by lsecrease on 8/9/15. +// Copyright (c) 2015 ImagineME. All rights reserved. +// + +import UIKit +import XCTest + +class DindrTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + XCTAssert(true, "Pass") + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measureBlock() { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Info.plist b/DindrTests/Info.plist similarity index 59% rename from Info.plist rename to DindrTests/Info.plist index 4fba926..c84165a 100644 --- a/Info.plist +++ b/DindrTests/Info.plist @@ -13,28 +13,12 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - diff --git a/DishModel.swift b/DishModel.swift deleted file mode 100644 index 6cd0845..0000000 --- a/DishModel.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// DishModel.swift -// Dindr -// -// Created by lsecrease on 9/15/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import Foundation - -struct DishModel { - - var image = UIImage(named: "") - -} \ No newline at end of file diff --git a/GalleryCell.swift b/GalleryCell.swift deleted file mode 100644 index f73c6c8..0000000 --- a/GalleryCell.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// GalleryCell.swift -// Dindr -// -// Created by lsecrease on 10/5/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class GalleryCell: UICollectionViewCell { - - @IBOutlet weak var galImage: UIImageView! -} diff --git a/GalleryVC.swift b/GalleryVC.swift deleted file mode 100644 index 34fc073..0000000 --- a/GalleryVC.swift +++ /dev/null @@ -1,177 +0,0 @@ -// -// GalleryVC.swift -// Dindr -// -// Created by lsecrease on 10/5/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - - -class GalleryVC: UIViewController, UICollectionViewDataSource, - UICollectionViewDelegate, - UICollectionViewDelegateFlowLayout, -UIScrollViewDelegate { - - /* Views */ - @IBOutlet var galleryCollView: UICollectionView! - - @IBOutlet var imagePreviewView: UIView! - @IBOutlet var imgScrollView: UIScrollView! - @IBOutlet var imgPrev: UIImageView! - - - /* Variables */ - var galleryArray = NSMutableArray() - - var collViewCells: CGFloat = 3.0 - - var hudView = UIView(frame: CGRectMake(0, 0, 80, 80)) - var indicatorView = UIActivityIndicatorView(frame: CGRectMake(0, 0, 80, 80)) - - - - - override func viewDidLoad() { - super.viewDidLoad() - - imagePreviewView.frame = CGRectMake(0, 0, 0, 0) - - queryGallery() - - //println("\(galleryArray.count)") - - - - - } - - func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? { - return imgPrev - } - - func queryGallery() { - - // ERROR ALERT VIEW - var errorAlert = UIAlertView(title: "Dindr", - message: "Something went wrong, try again later or check your internet connection", - delegate: nil, - cancelButtonTitle: "OK" ) - - view.showHUD(view) - galleryArray.removeAllObjects() - - var query = PFQuery(className: "Gallery") - query.findObjectsInBackgroundWithBlock { (objects, error)-> Void in - if error == nil { - if let objects = objects as? [PFObject] { - for object in objects { - self.galleryArray.addObject(object) - } } - // Reload Data - self.galleryCollView.reloadData() - self.view.hideHUD() - println("\(self.galleryArray.count)") - - } else { errorAlert.show(); self.view.hideHUD() } - } - } - - - - /* MARK: - COLLECTION VIEW DELEGATES ========================*/ - func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { - return 1 - } - - func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return galleryArray.count - - } - - func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCellWithReuseIdentifier("GalleryCell", forIndexPath: indexPath) as! GalleryCell - - var galleryClass = PFObject(className: "Gallery") - galleryClass = galleryArray[indexPath.row] as! PFObject - - - // Get image - let imageFile = galleryClass["image"] as? PFFile - imageFile?.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in - if error == nil { - if let imageData = imageData { - cell.galImage.image = UIImage(data:imageData) - cell.galImage.layer.borderColor = UIColor.blackColor().CGColor - cell.galImage.layer.borderWidth = 1 - } } } -// - - return cell - } - - func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { - return CGSizeMake(view.frame.size.width / collViewCells, view.frame.size.width / collViewCells) - } - - // IMAGE TAPPED - func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { - - var galleryClass = PFObject(className: "Gallery") - galleryClass = galleryArray[indexPath.row] as! PFObject - - let imageFile = galleryClass["image"] as? PFFile - imageFile?.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in - if error == nil { - if let imageData = imageData { - self.imgPrev.image = UIImage(data:imageData) - self.showImagePrevView() - } } } - } - - - - - // SHOW/HIDE PREVIEW IMAGE VIEW - func showImagePrevView() { - UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { - self.imagePreviewView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) - }, completion: { (finished: Bool) in }) - } - func hideImagePrevView() { - imgPrev.image = nil - UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: { - self.imagePreviewView.frame = CGRectMake(0, 0, 0, 0) - }, completion: { (finished: Bool) in }) - } - - - // TAP ON IMAGE TO CLOSE PREVIEW - @IBAction func tapToClosePreview(sender: UITapGestureRecognizer) { - hideImagePrevView() - } - - -} - -extension UIView { - func showHUD(inView: UIView) { - hudView.center = CGPointMake(inView.frame.size.width/2, inView.frame.size.height/2) - hudView.backgroundColor = UIColor(red: 237.0/255.0, green: 85.0/255.0, blue: 100.0/255.0, alpha: 1.0) - hudView.alpha = 0.9 - hudView.layer.cornerRadius = hudView.bounds.size.width/2 - - indicatorView.center = CGPointMake(hudView.frame.size.width/2, hudView.frame.size.height/2) - indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge - hudView.addSubview(indicatorView) - inView.addSubview(hudView) - indicatorView.startAnimating() - } - - func hideHUD() { hudView.removeFromSuperview() } -} - - - - diff --git a/HomeViewController.h b/HomeViewController.h deleted file mode 100755 index 9df38b4..0000000 --- a/HomeViewController.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// HomeViewController.h -// LLSimpleCameraExample -// -// Created by Ömer Faruk Gül on 29/10/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import -#import "LLSimpleCamera.h" - -@interface HomeViewController : UIViewController - -@end diff --git a/HomeViewController.m b/HomeViewController.m deleted file mode 100755 index 8a0ce6d..0000000 --- a/HomeViewController.m +++ /dev/null @@ -1,292 +0,0 @@ -// -// HomeViewController.m -// LLSimpleCameraExample -// -// Created by Ömer Faruk Gül on 29/10/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import "HomeViewController.h" -#import "ViewUtils.h" -#import "ImageViewController.h" -#import "VideoViewController.h" -#import "Dindr-Swift.h" - - -@interface HomeViewController () -@property (strong, nonatomic) LLSimpleCamera *camera; -@property (strong, nonatomic) UILabel *errorLabel; -@property (strong, nonatomic) UIButton *snapButton; -@property (strong, nonatomic) UIButton *switchButton; -@property (strong, nonatomic) UIButton *flashButton; -@property (strong, nonatomic) UISegmentedControl *segmentedControl; -@end - -@implementation HomeViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [UIColor blackColor]; - [self.navigationController setNavigationBarHidden:YES animated:NO]; - - CGRect screenRect = [[UIScreen mainScreen] bounds]; - - // ----- initialize camera -------- // - - // create camera vc - self.camera = [[LLSimpleCamera alloc] initWithQuality:AVCaptureSessionPresetHigh - position:CameraPositionBack - videoEnabled:YES]; - - // attach to a view controller - [self.camera attachToViewController:self withFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; - - // read: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload - // you probably will want to set this to YES, if you are going view the image outside iOS. - self.camera.fixOrientationAfterCapture = NO; - - // take the required actions on a device change - __weak typeof(self) weakSelf = self; - [self.camera setOnDeviceChange:^(LLSimpleCamera *camera, AVCaptureDevice * device) { - - NSLog(@"Device changed."); - - // device changed, check if flash is available - if([camera isFlashAvailable]) { - weakSelf.flashButton.hidden = NO; - - if(camera.flash == CameraFlashOff) { - weakSelf.flashButton.selected = NO; - } - else { - weakSelf.flashButton.selected = YES; - } - } - else { - weakSelf.flashButton.hidden = YES; - } - }]; - - [self.camera setOnError:^(LLSimpleCamera *camera, NSError *error) { - NSLog(@"Camera error: %@", error); - - if([error.domain isEqualToString:LLSimpleCameraErrorDomain]) { - if(error.code == LLSimpleCameraErrorCodeCameraPermission || - error.code == LLSimpleCameraErrorCodeMicrophonePermission) { - - if(weakSelf.errorLabel) { - [weakSelf.errorLabel removeFromSuperview]; - } - - UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; - label.text = @"We need permission for the camera.\nPlease go to your settings."; - label.numberOfLines = 2; - label.lineBreakMode = NSLineBreakByWordWrapping; - label.backgroundColor = [UIColor clearColor]; - label.font = [UIFont fontWithName:@"AvenirNext-DemiBold" size:13.0f]; - label.textColor = [UIColor whiteColor]; - label.textAlignment = NSTextAlignmentCenter; - [label sizeToFit]; - label.center = CGPointMake(screenRect.size.width / 2.0f, screenRect.size.height / 2.0f); - weakSelf.errorLabel = label; - [weakSelf.view addSubview:weakSelf.errorLabel]; - } - } - }]; - - // ----- camera buttons -------- // - - // snap button to capture image - self.snapButton = [UIButton buttonWithType:UIButtonTypeCustom]; - self.snapButton.frame = CGRectMake(0, 0, 70.0f, 70.0f); - self.snapButton.clipsToBounds = YES; - self.snapButton.layer.cornerRadius = self.snapButton.width / 2.0f; - self.snapButton.layer.borderColor = [UIColor whiteColor].CGColor; - self.snapButton.layer.borderWidth = 2.0f; - self.snapButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; - self.snapButton.layer.rasterizationScale = [UIScreen mainScreen].scale; - self.snapButton.layer.shouldRasterize = YES; - [self.snapButton addTarget:self action:@selector(snapButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.view addSubview:self.snapButton]; - - // button to toggle flash - self.flashButton = [UIButton buttonWithType:UIButtonTypeSystem]; - self.flashButton.frame = CGRectMake(0, 0, 16.0f + 20.0f, 24.0f + 20.0f); - self.flashButton.tintColor = [UIColor whiteColor]; - [self.flashButton setImage:[UIImage imageNamed:@"camera-flash.png"] forState:UIControlStateNormal]; - self.flashButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f); - [self.flashButton addTarget:self action:@selector(flashButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.view addSubview:self.flashButton]; - - // button to toggle camera positions - self.switchButton = [UIButton buttonWithType:UIButtonTypeSystem]; - self.switchButton.frame = CGRectMake(0, 0, 29.0f + 20.0f, 22.0f + 20.0f); - self.switchButton.tintColor = [UIColor whiteColor]; - [self.switchButton setImage:[UIImage imageNamed:@"camera-switch.png"] forState:UIControlStateNormal]; - self.switchButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f); - [self.switchButton addTarget:self action:@selector(switchButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self.view addSubview:self.switchButton]; - - - self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Picture",@"Video"]]; - self.segmentedControl.frame = CGRectMake(12.0f, screenRect.size.height - 67.0f, 120.0f, 32.0f); - self.segmentedControl.selectedSegmentIndex = 0; - self.segmentedControl.tintColor = [UIColor whiteColor]; - [self.segmentedControl addTarget:self action:@selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged]; - [self.view addSubview:self.segmentedControl]; -} - -- (void)segmentedControlValueChanged:(UISegmentedControl *)control { - NSLog(@"Segment value changed!"); -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - // start the camera - [self.camera start]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - // stop the camera - [self.camera stop]; -} - -/* camera button methods */ - -- (void)switchButtonPressed:(UIButton *)button { - [self.camera togglePosition]; -} - -- (NSURL *)applicationDocumentsDirectory { - return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask] lastObject]; -} - -- (void)flashButtonPressed:(UIButton *)button { - - if(self.camera.flash == CameraFlashOff) { - BOOL done = [self.camera updateFlashMode:CameraFlashOn]; - if(done) { - self.flashButton.selected = YES; - self.flashButton.tintColor = [UIColor yellowColor]; - } - } - else { - BOOL done = [self.camera updateFlashMode:CameraFlashOff]; - if(done) { - self.flashButton.selected = NO; - self.flashButton.tintColor = [UIColor whiteColor]; - } - } -} - -- (void)snapButtonPressed:(UIButton *)button { - - if(self.segmentedControl.selectedSegmentIndex == 0) { - // capture - [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) { - if(!error) { - - // we should stop the camera, since we don't need it anymore. We will open a new vc. - // this very important, otherwise you may experience memory crashes - [camera stop]; - - // show the image - - [self performSegueWithIdentifier:@"Show Image Preview" sender:image]; - } - else { - NSLog(@"An error has occured: %@", error); - } - } exactSeenImage:YES]; - } - else { - - if(!self.camera.isRecording) { - self.segmentedControl.hidden = YES; - self.flashButton.hidden = YES; - self.switchButton.hidden = YES; - - self.snapButton.layer.borderColor = [UIColor redColor].CGColor; - self.snapButton.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5]; - - // start recording - NSURL *outputURL = [[[self applicationDocumentsDirectory] - URLByAppendingPathComponent:@"test1"] URLByAppendingPathExtension:@"mov"]; - [self.camera startRecordingWithOutputUrl:outputURL]; - } - else { - self.segmentedControl.hidden = NO; - self.flashButton.hidden = NO; - self.switchButton.hidden = NO; - - self.snapButton.layer.borderColor = [UIColor whiteColor].CGColor; - self.snapButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; - - [self.camera stopRecording:^(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error) { - VideoViewController *vc = [[VideoViewController alloc] initWithVideoUrl:outputFileUrl]; - [self.navigationController pushViewController:vc animated:YES]; - }]; - } - } -} - -/* other lifecycle methods */ -- (void)viewWillLayoutSubviews { - [super viewWillLayoutSubviews]; - - self.camera.view.frame = self.view.contentBounds; - - self.snapButton.center = self.view.contentCenter; - self.snapButton.bottom = self.view.height - 15; - - self.flashButton.center = self.view.contentCenter; - self.flashButton.top = 5.0f; - - self.switchButton.top = 5.0f; - self.switchButton.right = self.view.width - 5.0f; -} - -- (BOOL)prefersStatusBarHidden { - return YES; -} - -- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation { - return UIInterfaceOrientationPortrait; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; -} - -#pragma mark - Navigation - -//#warning - Change your according image view controller here after taking the photo - -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender -{ - if ([segue.identifier isEqualToString:@"Show Image Preview"]) { - PreviewImageViewController *pivc = segue.destinationViewController; - pivc.image = (UIImage *)sender; - } -} - -@end - - - - - - - - - - - - - - diff --git a/ImagePickerSheet6.4/AnimationController.swift b/ImagePickerSheet6.4/AnimationController.swift new file mode 100755 index 0000000..3abc0bd --- /dev/null +++ b/ImagePickerSheet6.4/AnimationController.swift @@ -0,0 +1,75 @@ +// +// AnimationController.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 25/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import UIKit + +class AnimationController: NSObject, UIViewControllerAnimatedTransitioning { + + let imagePickerSheetController: ImagePickerSheetController + let presenting: Bool + + // MARK: - Initialization + + init(imagePickerSheetController: ImagePickerSheetController, presenting: Bool) { + self.imagePickerSheetController = imagePickerSheetController + self.presenting = presenting + } + + // MARK: - UIViewControllerAnimatedTransitioning + + func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { + return 0.3 + } + + func animateTransition(transitionContext: UIViewControllerContextTransitioning) { + if presenting { + animatePresentation(transitionContext) + } + else { + animateDismissal(transitionContext) + } + } + + // MARK: - Animation + + private func animatePresentation(context: UIViewControllerContextTransitioning) { + guard let containerView = context.containerView() else { + print ("ERROR: container view does not exist") + return + } + + containerView.addSubview(imagePickerSheetController.view) + + let tableViewOriginY = imagePickerSheetController.tableView.frame.origin.y + imagePickerSheetController.tableView.frame.origin.y = containerView.bounds.maxY + imagePickerSheetController.backgroundView.alpha = 0 + + UIView.animateWithDuration(transitionDuration(context), animations: { + self.imagePickerSheetController.tableView.frame.origin.y = tableViewOriginY + self.imagePickerSheetController.backgroundView.alpha = 1 + }, completion: { _ in + context.completeTransition(true) + }) + } + + private func animateDismissal(context: UIViewControllerContextTransitioning) { + guard let containerView = context.containerView() else { + print ("ERROR: container view does not exist") + return + } + + UIView.animateWithDuration(transitionDuration(context), animations: { + self.imagePickerSheetController.tableView.frame.origin.y = containerView.bounds.maxY + self.imagePickerSheetController.backgroundView.alpha = 0 + }, completion: { _ in + self.imagePickerSheetController.view.removeFromSuperview() + context.completeTransition(true) + }) + } + +} diff --git a/ImagePickerSheet6.4/ImageAction.swift b/ImagePickerSheet6.4/ImageAction.swift new file mode 100755 index 0000000..c13fe5f --- /dev/null +++ b/ImagePickerSheet6.4/ImageAction.swift @@ -0,0 +1,66 @@ +// +// ImageAction.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 24/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import Foundation + +public enum ImageActionStyle { + case Default + case Cancel +} + +public typealias Title = Int -> String + +public class ImageAction { + + public typealias Handler = (ImageAction) -> () + public typealias SecondaryHandler = (ImageAction, Int) -> () + + let title: String + let secondaryTitle: Title + + let style: ImageActionStyle + + let handler: Handler? + let secondaryHandler: SecondaryHandler? + + public convenience init(title: String, secondaryTitle: String? = nil, style: ImageActionStyle = .Default, handler: Handler? = nil, secondaryHandler: SecondaryHandler? = nil) { + self.init(title: title, secondaryTitle: secondaryTitle.map { string in { _ in string }}, style: style, handler: handler, secondaryHandler: secondaryHandler) + } + + public init(title: String, secondaryTitle: Title?, style: ImageActionStyle = .Default, handler: Handler? = nil, var secondaryHandler: SecondaryHandler? = nil) { + if let handler = handler where secondaryTitle == nil && secondaryHandler == nil { + secondaryHandler = { action, _ in + handler(action) + } + } + + self.title = title + self.secondaryTitle = secondaryTitle ?? { _ in title } + self.style = style + self.handler = handler + self.secondaryHandler = secondaryHandler + } + + func handle(numberOfPhotos: Int = 0) { + if numberOfPhotos > 0 { + secondaryHandler?(self, numberOfPhotos) + } + else { + handler?(self) + } + } + +} + +func ?? (left: Title?, right: Title) -> Title { + if let left = left { + return left + } + + return right +} \ No newline at end of file diff --git a/ImagePickerSheet6.4/ImageCollectionViewCell.swift b/ImagePickerSheet6.4/ImageCollectionViewCell.swift new file mode 100755 index 0000000..5e773d0 --- /dev/null +++ b/ImagePickerSheet6.4/ImageCollectionViewCell.swift @@ -0,0 +1,53 @@ +// +// ImageCollectionViewCell.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class ImageCollectionViewCell : UICollectionViewCell { + + let imageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .ScaleAspectFill + + return imageView + }() + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + addSubview(imageView) + } + + // MARK: - Other Methods + + override func prepareForReuse() { + super.prepareForReuse() + + imageView.image = nil + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + imageView.frame = bounds + } +} diff --git a/ImagePickerSheet6.4/ImagePickerCollectionView.swift b/ImagePickerSheet6.4/ImagePickerCollectionView.swift new file mode 100755 index 0000000..cde76b6 --- /dev/null +++ b/ImagePickerSheet6.4/ImagePickerCollectionView.swift @@ -0,0 +1,56 @@ +// +// ImagePickerCollectionView.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 07/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class ImagePickerCollectionView: UICollectionView { + + var bouncing: Bool { + return contentOffset.x < -contentInset.left || contentOffset.x + frame.width > contentSize.width + contentInset.right + } + + var imagePreviewLayout: ImagePreviewFlowLayout { + return collectionViewLayout as! ImagePreviewFlowLayout + } + + // MARK: - Initialization + + init() { + super.init(frame: CGRectZero, collectionViewLayout: ImagePreviewFlowLayout()) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + panGestureRecognizer.addTarget(self, action: "handlePanGesture:") + } + + // MARK: - Panning + + @objc private func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) { + if gestureRecognizer.state == .Ended { + let translation = gestureRecognizer.translationInView(self) + if translation == CGPointZero { + if !bouncing { + let possibleIndexPath = indexPathForItemAtPoint(gestureRecognizer.locationInView(self)) + if let indexPath = possibleIndexPath { + selectItemAtIndexPath(indexPath, animated: false, scrollPosition: .None) + delegate?.collectionView?(self, didSelectItemAtIndexPath: indexPath) + } + } + } + } + } + +} diff --git a/ImagePickerSheet6.4/ImagePickerSheetController.h b/ImagePickerSheet6.4/ImagePickerSheetController.h new file mode 100755 index 0000000..a9f351d --- /dev/null +++ b/ImagePickerSheet6.4/ImagePickerSheetController.h @@ -0,0 +1,19 @@ +// +// ImagePickerSheetController.h +// ImagePickerSheetController +// +// Created by Laurin Brandner on 26/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +#import + +//! Project version number for ImagePickerSheetController. +FOUNDATION_EXPORT double ImagePickerSheetControllerVersionNumber; + +//! Project version string for ImagePickerSheetController. +FOUNDATION_EXPORT const unsigned char ImagePickerSheetControllerVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/ImagePickerSheet6.4/ImagePickerSheetController.swift b/ImagePickerSheet6.4/ImagePickerSheetController.swift new file mode 100755 index 0000000..c59e6b6 --- /dev/null +++ b/ImagePickerSheet6.4/ImagePickerSheetController.swift @@ -0,0 +1,399 @@ +// +// ImagePickerController.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 24/05/15. +// Copyright (c) 2015 Laurin Brandner. All rights reserved. +// + +import Foundation +import Photos + +private let enlargementAnimationDuration = 0.3 +private let tableViewRowHeight: CGFloat = 50.0 +private let tableViewPreviewRowHeight: CGFloat = 140.0 +private let tableViewEnlargedPreviewRowHeight: CGFloat = 243.0 +private let collectionViewInset: CGFloat = 5.0 +private let collectionViewCheckmarkInset: CGFloat = 3.5 + +public class ImagePickerSheetController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIViewControllerTransitioningDelegate { + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.dataSource = self + tableView.delegate = self + tableView.alwaysBounceVertical = false + tableView.layoutMargins = UIEdgeInsetsZero + tableView.separatorInset = UIEdgeInsetsZero + tableView.registerClass(ImagePreviewTableViewCell.self, forCellReuseIdentifier: NSStringFromClass(ImagePreviewTableViewCell.self)) + tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: NSStringFromClass(UITableViewCell.self)) + + return tableView + }() + + private lazy var collectionView: ImagePickerCollectionView = { + let collectionView = ImagePickerCollectionView() + collectionView.backgroundColor = .clearColor() + collectionView.imagePreviewLayout.sectionInset = UIEdgeInsetsMake(collectionViewInset, collectionViewInset, collectionViewInset, collectionViewInset) + collectionView.imagePreviewLayout.showsSupplementaryViews = false + collectionView.dataSource = self + collectionView.delegate = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.alwaysBounceHorizontal = true + collectionView.registerClass(ImageCollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(ImageCollectionViewCell.self)) + collectionView.registerClass(PreviewSupplementaryView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self)) + + return collectionView + }() + + lazy var backgroundView: UIView = { + let view = UIView() + view.backgroundColor = UIColor(white: 0.0, alpha: 0.3961) + view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "cancel")) + + return view + }() + + private(set) var actions = [ImageAction]() + private var assets = [PHAsset]() + private var selectedPhotoIndices = [Int]() + private(set) var enlargedPreviews = false + + private var supplementaryViews = [Int: PreviewSupplementaryView]() + + private let imageManager = PHCachingImageManager() + + // MARK: - Initialization + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + initialize() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialize() + } + + private func initialize() { + modalPresentationStyle = .Custom + transitioningDelegate = self + } + + // MARK: - View Lifecycle + + override public func loadView() { + super.loadView() + + view.addSubview(backgroundView) + view.addSubview(tableView) + } + + public override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + + fetchAssets() + } + + // MARK: - UITableViewDataSource + + public func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 2 + } + + public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return 1 + } + + return actions.count + } + + public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + if indexPath.section == 0 { + if assets.count > 0 { + return enlargedPreviews ? tableViewEnlargedPreviewRowHeight : tableViewPreviewRowHeight + } + + return 0 + } + + return tableViewRowHeight + } + + public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + if indexPath.section == 0 { + let cell = tableView.dequeueReusableCellWithIdentifier(NSStringFromClass(ImagePreviewTableViewCell.self), forIndexPath: indexPath) as! ImagePreviewTableViewCell + cell.collectionView = collectionView + cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) + + return cell + } + + let action = actions[indexPath.row] + + let cell = tableView.dequeueReusableCellWithIdentifier(NSStringFromClass(UITableViewCell.self), forIndexPath: indexPath) + cell.textLabel?.textAlignment = .Center + cell.textLabel?.textColor = tableView.tintColor + cell.textLabel?.font = UIFont.systemFontOfSize(21) + cell.textLabel?.text = selectedPhotoIndices.count > 0 ? action.secondaryTitle(selectedPhotoIndices.count) : action.title + cell.layoutMargins = UIEdgeInsetsZero + + return cell + } + + // MARK: - UITableViewDelegate + + public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool { + return indexPath.section != 0 + } + + public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + tableView.deselectRowAtIndexPath(indexPath, animated: true) + + presentingViewController?.dismissViewControllerAnimated(true, completion: nil) + + actions[indexPath.row].handle(selectedPhotoIndices.count) + } + + // MARK: - UICollectionViewDataSource + + public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + return assets.count + } + + public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 1 + } + + public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCellWithReuseIdentifier(NSStringFromClass(ImageCollectionViewCell.self), forIndexPath: indexPath) as! ImageCollectionViewCell + + let asset = assets[indexPath.section] + let size = sizeForAsset(asset) + + requestImageForAsset(asset, size: size) { image in + cell.imageView.image = image + } + + return cell + } + + public func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { + let view = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self), forIndexPath: indexPath) as! PreviewSupplementaryView + view.userInteractionEnabled = false + view.buttonInset = UIEdgeInsetsMake(0.0, collectionViewCheckmarkInset, collectionViewCheckmarkInset, 0.0) + view.selected = selectedPhotoIndices.contains(indexPath.section) + + supplementaryViews[indexPath.section] = view + + return view + } + + // MARK: - UICollectionViewDelegateFlowLayout + + public func collectionView(collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { + let asset = assets[indexPath.section] + + return sizeForAsset(asset) + } + + public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + let inset = 2.0 * collectionViewCheckmarkInset + let size = self.collectionView(collectionView, layout: collectionViewLayout, sizeForItemAtIndexPath: NSIndexPath(forRow: 0, inSection: section)) + let imageWidth = PreviewSupplementaryView.checkmarkImage?.size.width ?? 0 + + return CGSizeMake(imageWidth + inset, size.height) + } + + // MARK: - UICollectionViewDelegate + + public func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { + let nextIndex = indexPath.row+1 + if nextIndex < assets.count { + let asset = assets[nextIndex] + let size = sizeForAsset(asset) + + self.prefetchImagesForAsset(asset, size: size) + } + } + + public func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { + let selected = selectedPhotoIndices.contains(indexPath.section) + + if !selected { + selectedPhotoIndices.append(indexPath.section) + + if !enlargedPreviews { + enlargedPreviews = true + + self.collectionView.imagePreviewLayout.invalidationCenteredIndexPath = indexPath + + view.setNeedsLayout() + UIView.animateWithDuration(enlargementAnimationDuration, animations: { + self.tableView.beginUpdates() + self.tableView.endUpdates() + self.view.layoutIfNeeded() + }, completion: { finished in + self.reloadButtonTitles() + self.collectionView.imagePreviewLayout.showsSupplementaryViews = true + }) + } + else { + if let cell = collectionView.cellForItemAtIndexPath(indexPath) { + var contentOffset = CGPointMake(cell.frame.midX - collectionView.frame.width / 2.0, 0.0) + contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left) + contentOffset.x = min(contentOffset.x, collectionView.contentSize.width - collectionView.frame.width + collectionView.contentInset.right) + + collectionView.setContentOffset(contentOffset, animated: true) + } + + reloadButtonTitles() + } + } + else { + selectedPhotoIndices.removeAtIndex(selectedPhotoIndices.indexOf(indexPath.section)!) + reloadButtonTitles() + } + + if let sectionView = supplementaryViews[indexPath.section] { + sectionView.selected = !selected + } + } + + // MARK: - Actions + + public func addAction(action: ImageAction) { + let cancelActions = actions.filter { $0.style == ImageActionStyle.Cancel } + if action.style == .Cancel && cancelActions.count > 0 { + // precondition() would be more swifty here, but that's not really testable as of now + NSException(name: NSInternalInconsistencyException, reason: "ImagePickerSheetController can only have one action with a style of .Cancel", userInfo: nil).raise() + } + + actions.append(action) + } + + // MARK: - Photos + + private func sizeForAsset(asset: PHAsset) -> CGSize { + let proportion = CGFloat(asset.pixelWidth)/CGFloat(asset.pixelHeight) + + let height: CGFloat = { + let rowHeight = self.enlargedPreviews ? tableViewEnlargedPreviewRowHeight : tableViewPreviewRowHeight + return rowHeight-2.0*collectionViewInset + }() + + return CGSize(width: CGFloat(floorf(Float(proportion*height))), height: height) + } + + private func targetSizeForAssetOfSize(size: CGSize) -> CGSize { + let scale = UIScreen.mainScreen().scale + return CGSize(width: scale*size.width, height: scale*size.height) + } + + private func fetchAssets() { + let options = PHFetchOptions() + options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] + let result = PHAsset.fetchAssetsWithMediaType(.Image, options: options) + + result.enumerateObjectsUsingBlock { obj, _, _ in + if let asset = obj as? PHAsset where self.assets.count < 50 { + self.assets.append(asset) + } + } + } + + private func requestImageForAsset(asset: PHAsset, size: CGSize? = nil, deliveryMode: PHImageRequestOptionsDeliveryMode = .Opportunistic, completion: (image: UIImage?) -> Void) { + var targetSize = PHImageManagerMaximumSize + if let size = size { + targetSize = targetSizeForAssetOfSize(size) + } + + let options = PHImageRequestOptions() + options.deliveryMode = deliveryMode; + + // Workaround because PHImageManager.requestImageForAsset doesn't work for burst images + if asset.representsBurst { + imageManager.requestImageDataForAsset(asset, options: options) { data, _, _, _ in + guard let safeData = data else { + completion(image: nil) + return + } + + let image = UIImage(data: safeData) + completion(image: image) + } + } + else { + imageManager.requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options) { image, _ in + completion(image: image) + } + } + } + + private func prefetchImagesForAsset(asset: PHAsset, size: CGSize) { + // Not necessary to cache image because PHImageManager won't return burst images + if !asset.representsBurst { + let targetSize = targetSizeForAssetOfSize(size) + imageManager.startCachingImagesForAssets([asset], targetSize: targetSize, contentMode: .AspectFill, options: nil) + } + } + + public func getSelectedImagesWithCompletion(completion: (images:[UIImage?]) -> Void) { + var images = [UIImage?]() + var counter = selectedPhotoIndices.count + + for index in selectedPhotoIndices { + let asset = assets[index] + + requestImageForAsset(asset, deliveryMode: .HighQualityFormat) { image in + images.append(image) + counter-- + + if counter <= 0 { + completion(images: images) + } + } + } + } + + // MARK: - Buttons + + private func reloadButtonTitles() { + tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .None) + } + + @objc private func cancel() { + presentingViewController?.dismissViewControllerAnimated(true, completion: nil) + + let cancelActions = actions.filter { $0.style == ImageActionStyle.Cancel } + if let cancelAction = cancelActions.first { + cancelAction.handle(selectedPhotoIndices.count) + } + } + + // MARK: - Layout + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + backgroundView.frame = view.bounds + + let tableViewHeight = Array(0.. UIViewControllerAnimatedTransitioning? { + return AnimationController(imagePickerSheetController: self, presenting: true) + } + + public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + return AnimationController(imagePickerSheetController: self, presenting: false) + } + +} diff --git a/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift b/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift new file mode 100755 index 0000000..e08cbbc --- /dev/null +++ b/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift @@ -0,0 +1,153 @@ +// +// ImagePreviewFlowLayout.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class ImagePreviewFlowLayout: UICollectionViewFlowLayout { + + var invalidationCenteredIndexPath: NSIndexPath? + + var showsSupplementaryViews: Bool = true { + didSet { + invalidateLayout() + } + } + + private var layoutAttributes = [UICollectionViewLayoutAttributes]() + private var contentSize = CGSizeZero + + // MARK: - Initialization + + override init() { + super.init() + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + scrollDirection = .Horizontal + } + + // MARK: - Layout + + override func prepareLayout() { + super.prepareLayout() + + layoutAttributes.removeAll(keepCapacity: false) + contentSize = CGSizeZero + + if let collectionView = collectionView, + dataSource = collectionView.dataSource, + delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout { + var origin = CGPoint(x: sectionInset.left, y: sectionInset.top) + let numberOfSections = dataSource.numberOfSectionsInCollectionView?(collectionView) ?? 0 + + for s in 0 ..< numberOfSections { + let indexPath = NSIndexPath(forRow: 0, inSection: s) + let size = delegate.collectionView?(collectionView, layout: self, sizeForItemAtIndexPath: indexPath) ?? CGSizeZero + + let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) + attributes.frame = CGRect(origin: origin, size: size) + attributes.zIndex = 0 + + layoutAttributes.append(attributes) + + origin.x = attributes.frame.maxX + sectionInset.right + } + + contentSize = CGSize(width: origin.x, height: collectionView.frame.height) + } + } + + override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool { + return true + } + + override func collectionViewContentSize() -> CGSize { + return contentSize + } + + override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint { + var contentOffset = proposedContentOffset + if let indexPath = invalidationCenteredIndexPath { + if let collectionView = collectionView { + let frame = layoutAttributes[indexPath.section].frame + contentOffset.x = frame.midX - collectionView.frame.width / 2.0 + + contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left) + contentOffset.x = min(contentOffset.x, collectionViewContentSize().width - collectionView.frame.width + collectionView.contentInset.right) + } + invalidationCenteredIndexPath = nil + } + + return super.targetContentOffsetForProposedContentOffset(contentOffset) + } + + override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + return layoutAttributes.filter { CGRectIntersectsRect(rect, $0.frame) }.reduce([UICollectionViewLayoutAttributes]()) { memo, attributes in + let supplementaryAttributes = layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: attributes.indexPath) + return memo + [attributes, supplementaryAttributes] + } + } + + override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! { + return layoutAttributes[indexPath.section] + } + + override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! { + if let collectionView = collectionView, + dataSource = collectionView.dataSource, + delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout { + let itemAttributes = layoutAttributesForItemAtIndexPath(indexPath) + + let inset = collectionView.contentInset + let bounds = collectionView.bounds + let contentOffset: CGPoint = { + var contentOffset = collectionView.contentOffset + contentOffset.x += inset.left + contentOffset.y += inset.top + + return contentOffset + }() + let visibleSize: CGSize = { + var size = bounds.size + size.width -= (inset.left+inset.right) + + return size + }() + let visibleFrame = CGRect(origin: contentOffset, size: visibleSize) + + let size = delegate.collectionView?(collectionView, layout: self, referenceSizeForHeaderInSection: indexPath.section) ?? CGSizeZero + let originX = max(itemAttributes.frame.minX, min(itemAttributes.frame.maxX - size.width, visibleFrame.maxX - size.width)) + + let attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath) + attributes.zIndex = 1 + attributes.hidden = !showsSupplementaryViews + attributes.frame = CGRect(origin: CGPoint(x: originX, y: itemAttributes.frame.minY), size: size) + + return attributes + } + + return nil + } + + override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(itemIndexPath) + } + + override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + return layoutAttributesForItemAtIndexPath(itemIndexPath) + } + +} diff --git a/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift b/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift new file mode 100755 index 0000000..a67d120 --- /dev/null +++ b/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift @@ -0,0 +1,44 @@ +// +// ImagePreviewTableViewCell.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class ImagePreviewTableViewCell : UITableViewCell { + + var collectionView: ImagePickerCollectionView? { + willSet { + if let collectionView = collectionView { + collectionView.removeFromSuperview() + } + + if let collectionView = newValue { + addSubview(collectionView) + } + } + } + + // MARK: - Other Methods + + override func prepareForReuse() { + collectionView = nil + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + // Setting the frame of the collectionView this large avoids a small animation glitch when resizing the previews. You'll get a beer from @larcus94 if you'll get it to work without this workaround :) + + if let collectionView = collectionView { + collectionView.frame = CGRect(x: -bounds.width, y: bounds.minY, width: bounds.width*3, height: bounds.height) + collectionView.contentInset = UIEdgeInsetsMake(0.0, bounds.width, 0.0, bounds.width) + } + } + +} diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json new file mode 100755 index 0000000..3abba0e --- /dev/null +++ b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "PreviewSupplementaryView-Checkmark-Selected@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png new file mode 100755 index 0000000..8d3d970 Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png differ diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png new file mode 100755 index 0000000..4a09d61 Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png differ diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png new file mode 100755 index 0000000..2f42084 Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png differ diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json new file mode 100755 index 0000000..ae5d3ab --- /dev/null +++ b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "PreviewSupplementaryView-Checkmark.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "PreviewSupplementaryView-Checkmark@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "PreviewSupplementaryView-Checkmark@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png new file mode 100755 index 0000000..0106c9d Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png differ diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png new file mode 100755 index 0000000..020f970 Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png differ diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png new file mode 100755 index 0000000..99021d7 Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png differ diff --git a/Spring/Info.plist b/ImagePickerSheet6.4/Info.plist similarity index 91% rename from Spring/Info.plist rename to ImagePickerSheet6.4/Info.plist index bd4db03..17ad904 100755 --- a/Spring/Info.plist +++ b/ImagePickerSheet6.4/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - designcode.$(PRODUCT_NAME:rfc1034identifier) + ch.laurinbrandner.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/ImagePickerSheet6.4/PreviewSupplementaryView.swift b/ImagePickerSheet6.4/PreviewSupplementaryView.swift new file mode 100755 index 0000000..6d82e7e --- /dev/null +++ b/ImagePickerSheet6.4/PreviewSupplementaryView.swift @@ -0,0 +1,92 @@ +// +// PreviewSupplementaryView.swift +// ImagePickerSheet +// +// Created by Laurin Brandner on 06/09/14. +// Copyright (c) 2014 Laurin Brandner. All rights reserved. +// + +import UIKit + +class PreviewSupplementaryView : UICollectionReusableView { + + private let button: UIButton = { + let button = UIButton() + button.tintColor = .whiteColor() + button.userInteractionEnabled = false + button.setImage(PreviewSupplementaryView.checkmarkImage, forState: .Normal) + button.setImage(PreviewSupplementaryView.selectedCheckmarkImage, forState: .Selected) + + return button + }() + + var buttonInset = UIEdgeInsetsZero + + var selected: Bool = false { + didSet { + button.selected = selected + reloadButtonBackgroundColor() + } + } + + class var checkmarkImage: UIImage? { + let bundle = NSBundle(forClass: ImagePickerSheetController.self) + let image = UIImage(named: "PreviewSupplementaryView-Checkmark", inBundle: bundle, compatibleWithTraitCollection: nil) + + return image?.imageWithRenderingMode(.AlwaysTemplate) + } + + class var selectedCheckmarkImage: UIImage? { + let bundle = NSBundle(forClass: ImagePickerSheetController.self) + let image = UIImage(named: "PreviewSupplementaryView-Checkmark-Selected", inBundle: bundle, compatibleWithTraitCollection: nil) + + return image?.imageWithRenderingMode(.AlwaysTemplate) + } + + // MARK: - Initialization + + override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + private func initialize() { + addSubview(button) + } + + // MARK: - Other Methods + + override func prepareForReuse() { + super.prepareForReuse() + + selected = false + } + + override func tintColorDidChange() { + super.tintColorDidChange() + + reloadButtonBackgroundColor() + } + + private func reloadButtonBackgroundColor() { + button.backgroundColor = (selected) ? tintColor : nil + } + + // MARK: - Layout + + override func layoutSubviews() { + super.layoutSubviews() + + button.sizeToFit() + button.frame.origin = CGPointMake(buttonInset.left, CGRectGetHeight(bounds)-CGRectGetHeight(button.frame)-buttonInset.bottom) + button.layer.cornerRadius = CGRectGetHeight(button.frame) / 2.0 + } + +} diff --git a/ImageViewController.h b/ImageViewController.h deleted file mode 100755 index c31948f..0000000 --- a/ImageViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// ImageViewController.h -// LLSimpleCameraExample -// -// Created by Ömer Faruk Gül on 15/11/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import - -@interface ImageViewController : UIViewController -- (instancetype)initWithImage:(UIImage *)image; -@end diff --git a/ImageViewController.m b/ImageViewController.m deleted file mode 100755 index 4d3ff5c..0000000 --- a/ImageViewController.m +++ /dev/null @@ -1,83 +0,0 @@ -// -// ImageViewController.m -// LLSimpleCameraExample -// -// Created by Ömer Faruk Gül on 15/11/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import "ImageViewController.h" -#import "ViewUtils.h" -#import "UIImage+Crop.h" - - -@interface ImageViewController () -@property (strong, nonatomic) UIImage *image; -@property (strong, nonatomic) UIImageView *imageView; -@property (strong, nonatomic) UILabel *infoLabel; -@property (strong, nonatomic) UIButton *cancelButton; -@end - -@implementation ImageViewController - -- (instancetype)initWithImage:(UIImage *)image { - self = [super initWithNibName:nil bundle:nil]; - if(self) { - _image = image; - } - - return self; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.imageView.backgroundColor = [UIColor blackColor]; - - CGRect screenRect = [[UIScreen mainScreen] bounds]; - - self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; - self.imageView.contentMode = UIViewContentModeScaleAspectFit; - self.imageView.backgroundColor = [UIColor clearColor]; - self.imageView.image = self.image; - [self.view addSubview:self.imageView]; - - NSString *info = [NSString stringWithFormat:@"Size: %@ - Orientation: %ld", NSStringFromCGSize(self.image.size), (long)self.image.imageOrientation]; - - self.infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)]; - self.infoLabel.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.7]; - self.infoLabel.textColor = [UIColor whiteColor]; - self.infoLabel.font = [UIFont fontWithName:@"AvenirNext-Regular" size:13]; - self.infoLabel.textAlignment = NSTextAlignmentCenter; - self.infoLabel.text = info; -// [self.view addSubview:self.infoLabel]; - - UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapped:)]; - [self.view addGestureRecognizer:tapGesture]; -} - -- (void)viewTapped:(UIGestureRecognizer *)gesture { - [self dismissViewControllerAnimated:NO completion:nil]; -} - -- (BOOL)prefersStatusBarHidden { - return YES; -} - -- (void)viewWillLayoutSubviews { - [super viewWillLayoutSubviews]; - - self.imageView.frame = self.view.contentBounds; - - [self.infoLabel sizeToFit]; - self.infoLabel.width = self.view.contentBounds.size.width; - self.infoLabel.top = 0; - self.infoLabel.left = 0; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end diff --git a/Images.xcassets/AppIcon.appiconset/Contents.json b/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 118c98f..0000000 --- a/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/cam-1.imageset/Contents.json b/Images.xcassets/cam-1.imageset/Contents.json deleted file mode 100644 index 09a1b42..0000000 --- a/Images.xcassets/cam-1.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "cam.png" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/cam-1.imageset/cam.png b/Images.xcassets/cam-1.imageset/cam.png deleted file mode 100644 index bcf63b7..0000000 Binary files a/Images.xcassets/cam-1.imageset/cam.png and /dev/null differ diff --git a/Images.xcassets/f1.imageset/Contents.json b/Images.xcassets/f1.imageset/Contents.json deleted file mode 100644 index 766304b..0000000 --- a/Images.xcassets/f1.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "f1.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/f1.imageset/f1.jpg b/Images.xcassets/f1.imageset/f1.jpg deleted file mode 100644 index 945c656..0000000 Binary files a/Images.xcassets/f1.imageset/f1.jpg and /dev/null differ diff --git a/Images.xcassets/f2.imageset/Contents.json b/Images.xcassets/f2.imageset/Contents.json deleted file mode 100644 index 5ee66fd..0000000 --- a/Images.xcassets/f2.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "f2.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/f2.imageset/f2.jpg b/Images.xcassets/f2.imageset/f2.jpg deleted file mode 100644 index 548895e..0000000 Binary files a/Images.xcassets/f2.imageset/f2.jpg and /dev/null differ diff --git a/Images.xcassets/f4.imageset/Contents.json b/Images.xcassets/f4.imageset/Contents.json deleted file mode 100644 index bbe3524..0000000 --- a/Images.xcassets/f4.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "f4.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/f4.imageset/f4.jpg b/Images.xcassets/f4.imageset/f4.jpg deleted file mode 100644 index 6332dfd..0000000 Binary files a/Images.xcassets/f4.imageset/f4.jpg and /dev/null differ diff --git a/Images.xcassets/f5.imageset/Contents.json b/Images.xcassets/f5.imageset/Contents.json deleted file mode 100644 index 702a676..0000000 --- a/Images.xcassets/f5.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "f5.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/f5.imageset/f5.jpg b/Images.xcassets/f5.imageset/f5.jpg deleted file mode 100644 index 7aede3f..0000000 Binary files a/Images.xcassets/f5.imageset/f5.jpg and /dev/null differ diff --git a/Images.xcassets/f6.imageset/Contents.json b/Images.xcassets/f6.imageset/Contents.json deleted file mode 100644 index 9c77fb3..0000000 --- a/Images.xcassets/f6.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "f6.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/f6.imageset/f6.jpg b/Images.xcassets/f6.imageset/f6.jpg deleted file mode 100644 index 307f9d0..0000000 Binary files a/Images.xcassets/f6.imageset/f6.jpg and /dev/null differ diff --git a/Images.xcassets/resticon.imageset/Contents.json b/Images.xcassets/resticon.imageset/Contents.json deleted file mode 100644 index d5c6709..0000000 --- a/Images.xcassets/resticon.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "resticon.png" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/resticon.imageset/resticon.png b/Images.xcassets/resticon.imageset/resticon.png deleted file mode 100644 index 231020f..0000000 Binary files a/Images.xcassets/resticon.imageset/resticon.png and /dev/null differ diff --git a/Images.xcassets/resticon2.imageset/Contents.json b/Images.xcassets/resticon2.imageset/Contents.json deleted file mode 100644 index fea817f..0000000 --- a/Images.xcassets/resticon2.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "resticon2.png" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/resticon2.imageset/resticon2.png b/Images.xcassets/resticon2.imageset/resticon2.png deleted file mode 100644 index 3850998..0000000 Binary files a/Images.xcassets/resticon2.imageset/resticon2.png and /dev/null differ diff --git a/Images.xcassets/statbackground.imageset/Contents.json b/Images.xcassets/statbackground.imageset/Contents.json deleted file mode 100644 index 9fe03b0..0000000 --- a/Images.xcassets/statbackground.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "statbackground.png" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/statbackground.imageset/statbackground.png b/Images.xcassets/statbackground.imageset/statbackground.png deleted file mode 100644 index 37fd8e9..0000000 Binary files a/Images.xcassets/statbackground.imageset/statbackground.png and /dev/null differ diff --git a/LLSimpleCamera.h b/LLSimpleCamera.h deleted file mode 100755 index c145c5b..0000000 --- a/LLSimpleCamera.h +++ /dev/null @@ -1,177 +0,0 @@ -// -// CameraViewController.h -// LLSimpleCamera -// -// Created by Ömer Faruk Gül on 24/10/14. -// Copyright (c) 2014 Ömer Farul Gül. All rights reserved. -// - -#import -#import - -typedef enum : NSUInteger { - CameraPositionBack, - CameraPositionFront -} CameraPosition; - -typedef enum : NSUInteger { - // The default state has to be off - CameraFlashOff, - CameraFlashOn, - CameraFlashAuto -} CameraFlash; - -extern NSString *const LLSimpleCameraErrorDomain; -typedef enum : NSUInteger { - LLSimpleCameraErrorCodeCameraPermission = 10, - LLSimpleCameraErrorCodeMicrophonePermission = 11, - LLSimpleCameraErrorCodeSession = 12, - LLSimpleCameraErrorCodeVideoNotEnabled = 13 -} LLSimpleCameraErrorCode; - -@interface LLSimpleCamera : UIViewController - -/** - * Triggered on device change. - */ -@property (nonatomic, copy) void (^onDeviceChange)(LLSimpleCamera *camera, AVCaptureDevice *device); - -/** - * Triggered on any kind of error. - */ -@property (nonatomic, copy) void (^onError)(LLSimpleCamera *camera, NSError *error); - -/** - * Camera quality, set a constants prefixed with AVCaptureSessionPreset. - * Make sure to call before calling -(void)initialize method, otherwise it would be late. - */ -@property (copy, nonatomic) NSString *cameraQuality; - -/** - * Camera flash mode. - */ -@property (nonatomic, readonly) CameraFlash flash; - -/** - * Position of the camera. - */ -@property (nonatomic) CameraPosition position; - -/** - * Boolean value to indicate if the video is enabled. - */ -@property (nonatomic, getter=isVideoEnabled) BOOL videoEnabled; - -/** - * Boolean value to indicate if the camera is recording a video at the current moment. - */ -@property (nonatomic, getter=isRecording) BOOL recording; - -/** - * Fixess the orientation after the image is captured is set to Yes. - * see: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload - */ -@property (nonatomic) BOOL fixOrientationAfterCapture; - -/** - * Set NO if you don't want ot enable user triggered focusing. Enabled by default. - */ -@property (nonatomic) BOOL tapToFocus; - -/** - * Set YES if you your view controller does not allow autorotation, - * however you want to take the device rotation into account no matter what. Disabled by default. - */ -@property (nonatomic) BOOL useDeviceOrientation; - -/** - * Use this method to request camera permission before initalizing LLSimpleCamera. - */ -+ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock; - -/** - * Use this method to request microphone permission before initalizing LLSimpleCamera. - */ -+ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock; - -/** - * Returns an instance of LLSimpleCamera with the given quality. - * Quality parameter could be any variable starting with AVCaptureSessionPreset. - */ -- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled; - -/** - * Returns an instance of LLSimpleCamera with quality "AVCaptureSessionPresetHigh" and position "CameraPositionBack". - * @param videEnabled: Set to YES to enable video recording. - */ -- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled; - -/** - * Starts running the camera session. - */ -- (void)start; - -/** - * Stops the running camera session. Needs to be called when the app doesn't show the view. - */ -- (void)stop; - -/** - * Capture an image. - * @param onCapture a block triggered after the capturing the photo. - * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see. - */ --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage; - -/** - * Capture an image. - * @param onCapture a block triggered after the capturing the photo. - */ --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture; - -/* - * Start recording a video. Video is saved to the given url. - */ -- (void)startRecordingWithOutputUrl:(NSURL *)url; - -/** - * Stop recording video with a completion block. - */ -- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock; - -/** - * Attaches the LLSimpleCamera to another view controller with a frame. It basically adds the LLSimpleCamera as a - * child vc to the given vc. - * @param vc A view controller. - * @param frame The frame of the camera. - */ -- (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame; - -/** - * Changes the posiition of the camera (either back or front) and returns the final position. - */ -- (CameraPosition)togglePosition; - -/** - * Update the flash mode of the camera. Returns true if it is successful. Otherwise false. - */ -- (BOOL)updateFlashMode:(CameraFlash)cameraFlash; - -/** - * Checks if flash is avilable for the currently active device. - */ -- (BOOL)isFlashAvailable; - -/** - * Checks if torch (flash for video) is avilable for the currently active device. - */ -- (BOOL)isTorchAvailable; - -/** - * Alter the layer and the animation displayed when the user taps on screen. - * @param layer Layer to be displayed - * @param animation to be applied after the layer is shown - */ -- (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; - -@end diff --git a/LLSimpleCamera.m b/LLSimpleCamera.m deleted file mode 100755 index 20c902b..0000000 --- a/LLSimpleCamera.m +++ /dev/null @@ -1,756 +0,0 @@ -// -// CameraViewController.m -// LLSimpleCamera -// -// Created by Ömer Faruk Gül on 24/10/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import "LLSimpleCamera.h" -#import -#import "UIImage+FixOrientation.h" - -@interface LLSimpleCamera () -@property (strong, nonatomic) UIView *preview; -@property (strong, nonatomic) AVCaptureStillImageOutput *stillImageOutput; -@property (strong, nonatomic) AVCaptureSession *session; -@property (strong, nonatomic) AVCaptureDevice *videoCaptureDevice; -@property (strong, nonatomic) AVCaptureDevice *audioCaptureDevice; -@property (strong, nonatomic) AVCaptureDeviceInput *videoDeviceInput; -@property (strong, nonatomic) AVCaptureDeviceInput *audioDeviceInput; -@property (strong, nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; -@property (strong, nonatomic) UITapGestureRecognizer *tapGesture; -@property (strong, nonatomic) CALayer *focusBoxLayer; -@property (strong, nonatomic) CAAnimation *focusBoxAnimation; -@property (strong, nonatomic) AVCaptureMovieFileOutput *movieFileOutput; -@property (nonatomic, copy) void (^didRecord)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error); -@end - -NSString *const LLSimpleCameraErrorDomain = @"LLSimpleCameraErrorDomain"; - -@implementation LLSimpleCamera - -- (instancetype)init { - self = [self initWithVideoEnabled:NO]; - if(self) { - } - - return self; -} - -- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled { - self = [self initWithQuality:AVCaptureSessionPresetHigh position:CameraPositionBack videoEnabled:videoEnabled]; - if(self) { - } - - return self; -} - -- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled { - self = [super initWithNibName:nil bundle:nil]; - if(self) { - _cameraQuality = quality; - _position = position; - _fixOrientationAfterCapture = NO; - _tapToFocus = YES; - _useDeviceOrientation = NO; - _flash = CameraFlashOff; - _videoEnabled = videoEnabled; - _recording = NO; - } - - return self; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [UIColor clearColor]; - self.view.autoresizingMask = UIViewAutoresizingNone; - - self.preview = [[UIView alloc] initWithFrame:CGRectZero]; - self.preview.backgroundColor = [UIColor clearColor]; - [self.view addSubview:self.preview]; - - // tap to focus - self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(previewTapped:)]; - self.tapGesture.numberOfTapsRequired = 1; - [self.tapGesture setDelaysTouchesEnded:NO]; - [self.preview addGestureRecognizer:self.tapGesture]; - - // add focus box to view - [self addDefaultFocusBox]; -} - -- (void)addDefaultFocusBox { - - CALayer *focusBox = [[CALayer alloc] init]; - focusBox.cornerRadius = 5.0f; - focusBox.bounds = CGRectMake(0.0f, 0.0f, 70, 60); - focusBox.borderWidth = 3.0f; - focusBox.borderColor = [[UIColor yellowColor] CGColor]; - focusBox.opacity = 0.0f; - [self.view.layer addSublayer:focusBox]; - - CABasicAnimation *focusBoxAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; - focusBoxAnimation.duration = 0.75; - focusBoxAnimation.autoreverses = NO; - focusBoxAnimation.repeatCount = 0.0; - focusBoxAnimation.fromValue = [NSNumber numberWithFloat:1.0]; - focusBoxAnimation.toValue = [NSNumber numberWithFloat:0.0]; - - [self alterFocusBox:focusBox animation:focusBoxAnimation]; -} - -- (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation { - self.focusBoxLayer = layer; - self.focusBoxAnimation = animation; -} - -- (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame { - [vc.view addSubview:self.view]; - [vc addChildViewController:self]; - [self didMoveToParentViewController:vc]; - - vc.view.frame = frame; -} - -# pragma mark Touch Delegate - -- (void) previewTapped: (UIGestureRecognizer *) gestureRecognizer -{ - if(!self.tapToFocus) { - return; - } - - CGPoint touchedPoint = (CGPoint) [gestureRecognizer locationInView:self.preview]; - - // focus - CGPoint pointOfInterest = [self convertToPointOfInterestFromViewCoordinates:touchedPoint]; - [self focusAtPoint:pointOfInterest]; - - // show the box - [self showFocusBox:touchedPoint]; -} - -#pragma mark Camera Actions - -- (void)start { - [LLSimpleCamera requestCameraPermission:^(BOOL granted) { - if(granted) { - // request microphone permission if video is enabled - if(self.videoEnabled) { - [LLSimpleCamera requestMicrophonePermission:^(BOOL granted) { - if(granted) { - [self initialize]; - } - else { - NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain - code:LLSimpleCameraErrorCodeMicrophonePermission - userInfo:nil]; - if(self.onError) { - self.onError(self, error); - } - } - }]; - } - else { - [self initialize]; - } - } - else { - NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain - code:LLSimpleCameraErrorCodeCameraPermission - userInfo:nil]; - if(self.onError) { - self.onError(self, error); - } - } - }]; -} - -- (void)initialize { - if(!_session) { - _session = [[AVCaptureSession alloc] init]; - _session.sessionPreset = self.cameraQuality; - - // preview layer - CGRect bounds = self.preview.layer.bounds; - _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; - _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - _captureVideoPreviewLayer.bounds = bounds; - _captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); - [self.preview.layer addSublayer:_captureVideoPreviewLayer]; - - AVCaptureDevicePosition devicePosition; - switch (self.position) { - case CameraPositionBack: - devicePosition = AVCaptureDevicePositionBack; - break; - case CameraPositionFront: - devicePosition = AVCaptureDevicePositionFront; - break; - default: - devicePosition = AVCaptureDevicePositionUnspecified; - break; - } - - if(devicePosition == AVCaptureDevicePositionUnspecified) { - _videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - } - else { - _videoCaptureDevice = [self cameraWithPosition:devicePosition]; - } - - NSError *error = nil; - _videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoCaptureDevice error:&error]; - - if (!_videoDeviceInput) { - if(self.onError) { - self.onError(self, error); - } - return; - } - - if([self.session canAddInput:_videoDeviceInput]) { - [self.session addInput:_videoDeviceInput]; - } - - // add audio if video is enabled - if(self.videoEnabled) { - _audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; - _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_audioCaptureDevice error:&error]; - if (!_audioDeviceInput) { - if(self.onError) { - self.onError(self, error); - } - } - - if([self.session canAddInput:_audioDeviceInput]) { - [self.session addInput:_audioDeviceInput]; - } - - _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; - if([self.session canAddOutput:_movieFileOutput]) { - [self.session addOutput:_movieFileOutput]; - } - } - - - self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; - NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil]; - [self.stillImageOutput setOutputSettings:outputSettings]; - [self.session addOutput:self.stillImageOutput]; - } - - //if we had disabled the connection on capture, re-enable it - if (![self.captureVideoPreviewLayer.connection isEnabled]) { - [self.captureVideoPreviewLayer.connection setEnabled:YES]; - } - - [self.session startRunning]; -} - -- (void)stop { - [self.session stopRunning]; -} - - -#pragma mark Image Methods - --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage { - - if(!self.session) { - NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain - code:LLSimpleCameraErrorCodeSession - userInfo:nil]; - onCapture(self, nil, nil, error); - return; - } - - // get connection and set orientation - AVCaptureConnection *videoConnection = [self captureConnection]; - videoConnection.videoOrientation = [self orientationForConnection]; - - // freeze the screen - [self.captureVideoPreviewLayer.connection setEnabled:NO]; - - [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { - - UIImage *image = nil; - NSDictionary *metadata = nil; - - // check if we got the image buffer - if (imageSampleBuffer != NULL) { - CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL); - if(exifAttachments) { - metadata = (__bridge NSDictionary*)exifAttachments; - } - - NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; - image = [[UIImage alloc] initWithData:imageData]; - - if(exactSeenImage) { - image = [self cropImageUsingPreviewBounds:image]; - } - - if(self.fixOrientationAfterCapture) { - image = [image fixOrientation]; - } - } - - // trigger the block - if(onCapture) { - onCapture(self, image, metadata, error); - } - }]; -} - --(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture { - [self capture:onCapture exactSeenImage:NO]; -} - -#pragma mark Video Methods - -- (void)startRecordingWithOutputUrl:(NSURL *)url { - - // check if video is enabled - if(!self.videoEnabled) { - NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain - code:LLSimpleCameraErrorCodeVideoNotEnabled - userInfo:nil]; - if(self.onError) { - self.onError(self, error); - } - - return; - } - - if(self.flash == CameraFlashOn) { - [self enableTorch:YES]; - } - [self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self]; -} - -- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock { - - if(!self.videoEnabled) { - return; - } - - self.didRecord = completionBlock; - [self.movieFileOutput stopRecording]; -} - -- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections { - self.recording = YES; -} - -- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { - - self.recording = NO; - [self enableTorch:NO]; - - if(self.didRecord) { - self.didRecord(self, outputFileURL, error); - } -} - -- (void)enableTorch:(BOOL)enabled { - // check if the device has a toch, otherwise don't even bother to take any action. - if([self isTorchAvailable]) { - [self.session beginConfiguration]; - [self.videoCaptureDevice lockForConfiguration:nil]; - if (enabled) { - [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOn]; - } else { - [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOff]; - } - [self.videoCaptureDevice unlockForConfiguration]; - [self.session commitConfiguration]; - } -} - -#pragma mark Helper Methods - -- (UIImage *)cropImageUsingPreviewBounds:(UIImage *)image { - - CGRect previewBounds = self.captureVideoPreviewLayer.bounds; - CGRect outputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:previewBounds]; - - CGImageRef takenCGImage = image.CGImage; - size_t width = CGImageGetWidth(takenCGImage); - size_t height = CGImageGetHeight(takenCGImage); - CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, - outputRect.size.width * width, outputRect.size.height * height); - - CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect); - image = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:image.imageOrientation]; - CGImageRelease(cropCGImage); - - return image; -} - -- (AVCaptureConnection *)captureConnection { - - AVCaptureConnection *videoConnection = nil; - for (AVCaptureConnection *connection in self.stillImageOutput.connections) { - for (AVCaptureInputPort *port in [connection inputPorts]) { - if ([[port mediaType] isEqual:AVMediaTypeVideo]) { - videoConnection = connection; - break; - } - } - if (videoConnection) { - break; - } - } - - return videoConnection; -} - -- (void)setVideoCaptureDevice:(AVCaptureDevice *)videoCaptureDevice { - _videoCaptureDevice = videoCaptureDevice; - - if(videoCaptureDevice.flashMode == AVCaptureFlashModeAuto) { - _flash = CameraFlashAuto; - } - else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOn) { - _flash = CameraFlashOn; - } - else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOff) { - _flash = CameraFlashOff; - } - else { - _flash = CameraFlashOff; - } - - // trigger block - if(self.onDeviceChange) { - self.onDeviceChange(self, videoCaptureDevice); - } -} - -- (BOOL)isFlashAvailable { - return self.videoCaptureDevice.hasFlash && self.videoCaptureDevice.isFlashAvailable; -} - -- (BOOL)isTorchAvailable { - return self.videoCaptureDevice.hasTorch && self.videoCaptureDevice.isTorchAvailable; -} - -- (BOOL)updateFlashMode:(CameraFlash)cameraFlash { - if(!self.session) - return NO; - - AVCaptureFlashMode flashMode; - - if(cameraFlash == CameraFlashOn) { - flashMode = AVCaptureFlashModeOn; - } - else if(cameraFlash == CameraFlashAuto) { - flashMode = AVCaptureFlashModeAuto; - } - else { - flashMode = AVCaptureFlashModeOff; - } - - - if([self.videoCaptureDevice isFlashModeSupported:flashMode]) { - NSError *error; - if([self.videoCaptureDevice lockForConfiguration:&error]) { - self.videoCaptureDevice.flashMode = flashMode; - [self.videoCaptureDevice unlockForConfiguration]; - - _flash = cameraFlash; - return YES; - } - else { - if(self.onError) { - self.onError(self, error); - } - return NO; - } - } - else { - return NO; - } -} - -- (CameraPosition)togglePosition { - if(!self.session) { - return self.position; - } - - if(self.position == CameraPositionBack) { - self.cameraPosition = CameraPositionFront; - } - else { - self.cameraPosition = CameraPositionBack; - } - - return self.position; -} - -- (void)setCameraPosition:(CameraPosition)cameraPosition -{ - if(_position == cameraPosition || !self.session) { - return; - } - - [self.session beginConfiguration]; - - // remove existing input - [self.session removeInput:self.videoDeviceInput]; - - // get new input - AVCaptureDevice *device = nil; - if(self.videoDeviceInput.device.position == AVCaptureDevicePositionBack) { - device = [self cameraWithPosition:AVCaptureDevicePositionFront]; - } - else { - device = [self cameraWithPosition:AVCaptureDevicePositionBack]; - } - - if(!device) { - return; - } - - // add input to session - NSError *error = nil; - AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; - if(error) { - if(self.onError) { - self.onError(self, error); - } - [self.session commitConfiguration]; - return; - } - - _position = cameraPosition; - - [self.session addInput:videoInput]; - [self.session commitConfiguration]; - - self.videoCaptureDevice = device; - self.videoDeviceInput = videoInput; -} - - -// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found -- (AVCaptureDevice *) cameraWithPosition:(AVCaptureDevicePosition) position -{ - NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - for (AVCaptureDevice *device in devices) { - if (device.position == position) return device; - } - return nil; -} - -#pragma mark Focus - -- (void) focusAtPoint:(CGPoint)point -{ - //NSLog(@"Focusing at point %@", NSStringFromCGPoint(point)); - - AVCaptureDevice *device = self.videoCaptureDevice; - if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { - NSError *error; - if ([device lockForConfiguration:&error]) { - device.focusPointOfInterest = point; - device.focusMode = AVCaptureFocusModeAutoFocus; - [device unlockForConfiguration]; - } - - if(error && self.onError) { - self.onError(self, error); - } - } -} - -- (void)showFocusBox:(CGPoint)point { - - if(self.focusBoxLayer) { - // clear animations - [self.focusBoxLayer removeAllAnimations]; - - // move layer to the touc point - [CATransaction begin]; - [CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions]; - self.focusBoxLayer.position = point; - [CATransaction commit]; - } - - if(self.focusBoxAnimation) { - // run the animation - [self.focusBoxLayer addAnimation:self.focusBoxAnimation forKey:@"animateOpacity"]; - } -} - -- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates -{ - AVCaptureVideoPreviewLayer *previewLayer = self.captureVideoPreviewLayer; - - CGPoint pointOfInterest = CGPointMake(.5f, .5f); - CGSize frameSize = previewLayer.frame.size; - - if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResize] ) { - pointOfInterest = CGPointMake(viewCoordinates.y / frameSize.height, 1.f - (viewCoordinates.x / frameSize.width)); - } else { - CGRect cleanAperture; - for (AVCaptureInputPort *port in [self.videoDeviceInput ports]) { - if (port.mediaType == AVMediaTypeVideo) { - cleanAperture = CMVideoFormatDescriptionGetCleanAperture([port formatDescription], YES); - CGSize apertureSize = cleanAperture.size; - CGPoint point = viewCoordinates; - - CGFloat apertureRatio = apertureSize.height / apertureSize.width; - CGFloat viewRatio = frameSize.width / frameSize.height; - CGFloat xc = .5f; - CGFloat yc = .5f; - - if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspect] ) { - if (viewRatio > apertureRatio) { - CGFloat y2 = frameSize.height; - CGFloat x2 = frameSize.height * apertureRatio; - CGFloat x1 = frameSize.width; - CGFloat blackBar = (x1 - x2) / 2; - if (point.x >= blackBar && point.x <= blackBar + x2) { - xc = point.y / y2; - yc = 1.f - ((point.x - blackBar) / x2); - } - } else { - CGFloat y2 = frameSize.width / apertureRatio; - CGFloat y1 = frameSize.height; - CGFloat x2 = frameSize.width; - CGFloat blackBar = (y1 - y2) / 2; - if (point.y >= blackBar && point.y <= blackBar + y2) { - xc = ((point.y - blackBar) / y2); - yc = 1.f - (point.x / x2); - } - } - } else if ([previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspectFill]) { - if (viewRatio > apertureRatio) { - CGFloat y2 = apertureSize.width * (frameSize.width / apertureSize.height); - xc = (point.y + ((y2 - frameSize.height) / 2.f)) / y2; - yc = (frameSize.width - point.x) / frameSize.width; - } else { - CGFloat x2 = apertureSize.height * (frameSize.height / apertureSize.width); - yc = 1.f - ((point.x + ((x2 - frameSize.width) / 2)) / x2); - xc = point.y / frameSize.height; - } - } - - pointOfInterest = CGPointMake(xc, yc); - break; - } - } - } - - return pointOfInterest; -} - - -#pragma mark - Controller Lifecycle - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; -} - -- (void)viewWillLayoutSubviews { - [super viewWillLayoutSubviews]; - -// NSLog(@"layout cameraVC : %d", self.interfaceOrientation); - - self.preview.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); - - CGRect bounds = self.preview.bounds; - self.captureVideoPreviewLayer.bounds = bounds; - self.captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); - - self.captureVideoPreviewLayer.connection.videoOrientation = [self orientationForConnection]; -} - -- (AVCaptureVideoOrientation)orientationForConnection -{ - AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait; - - if(self.useDeviceOrientation) { - switch ([UIDevice currentDevice].orientation) { - case UIDeviceOrientationLandscapeLeft: - // yes we to the right, this is not bug! - videoOrientation = AVCaptureVideoOrientationLandscapeRight; - break; - case UIDeviceOrientationLandscapeRight: - videoOrientation = AVCaptureVideoOrientationLandscapeLeft; - break; - case UIDeviceOrientationPortraitUpsideDown: - videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; - break; - default: - videoOrientation = AVCaptureVideoOrientationPortrait; - break; - } - } - else { - switch (self.interfaceOrientation) { - case UIInterfaceOrientationLandscapeLeft: - videoOrientation = AVCaptureVideoOrientationLandscapeLeft; - break; - case UIInterfaceOrientationLandscapeRight: - videoOrientation = AVCaptureVideoOrientationLandscapeRight; - break; - case UIInterfaceOrientationPortraitUpsideDown: - videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; - break; - default: - videoOrientation = AVCaptureVideoOrientationPortrait; - break; - } - } - - return videoOrientation; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - - -#pragma mark static methods - -+ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock { - if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) { - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { - // return to main thread - dispatch_async(dispatch_get_main_queue(), ^{ - if(completionBlock) { - completionBlock(granted); - } - }); - }]; - } else { - completionBlock(YES); - } - -} - -+ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock { - if([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) { - [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) { - // return to main thread - dispatch_async(dispatch_get_main_queue(), ^{ - if(completionBlock) { - completionBlock(granted); - } - }); - }]; - } -} - -@end \ No newline at end of file diff --git a/LoginVC.swift b/LoginVC.swift deleted file mode 100644 index 11c95f0..0000000 --- a/LoginVC.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// LoginVC.swift -// Dindr -// -// Created by lsecrease on 8/15/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class LoginVC: UIViewController, UITextFieldDelegate, UIAlertViewDelegate { - - @IBOutlet weak var usernameTextField: UITextField! - @IBOutlet weak var passwordTextField: UITextField! - - @IBOutlet weak var loginButton: DesignableButton! - - override func viewWillAppear(animated: Bool) { - if PFUser.currentUser() != nil { - dismissViewControllerAnimated(true, completion: nil) - } - } - - override func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - } - - @IBAction func loginButtonPressed(sender: AnyObject) { - println("Login Button Pressed") - loginButton.animation = "pop" - loginButton.animate() - - var username = usernameTextField.text - var password = passwordTextField.text - - passwordTextField.resignFirstResponder() - - view.showHUD(view) - - PFUser.logInWithUsernameInBackground(usernameTextField.text, password:passwordTextField.text) { - (user, error) -> Void in - - if user != nil { // Login successfull - self.dismissViewControllerAnimated(true, completion: nil) - hudView.removeFromSuperview() - println("Successful Login") - - } else { // Login failed. Try again or SignUp - let alert = UIAlertView(title: "Dindr", - message: "\(error!.localizedDescription)", - delegate: self, - cancelButtonTitle: "Retry", - otherButtonTitles: "Sign Up") - alert.show() - - hudView.removeFromSuperview() - } - } - - } - - - - - - /* MARK - TEXTFIELD DELEGATES */ - func textFieldShouldReturn(textField: UITextField) -> Bool { - if textField == usernameTextField { - passwordTextField.becomeFirstResponder() - } - if textField == passwordTextField { - loginButtonPressed(self) - passwordTextField.resignFirstResponder() - } - return true - } - - // TAP TO DISMISS KEYBOARD - @IBAction func tapToDismissKeyboard(sender: UITapGestureRecognizer) { - usernameTextField.resignFirstResponder() - passwordTextField.resignFirstResponder() - } - - - -} - -let hudView = UIView(frame: CGRectMake(0, 0, 80, 80)) -let indicatorView = UIActivityIndicatorView(frame: CGRectMake(0, 0, 80, 80)) -let spinImage = UIImageView(frame: CGRectMake(0, 0, 80, 80)) - - -//extension UIView { -// func showHUD(view: UIView) { -// hudView.center = CGPointMake(view.frame.size.width/2, view.frame.size.height/2) -// hudView.backgroundColor = UIColor.darkGrayColor() -// hudView.alpha = 0.9 -// hudView.layer.cornerRadius = hudView.bounds.size.width/2 -// -// indicatorView.center = CGPointMake(hudView.frame.size.width/2, hudView.frame.size.height/2) -// indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge -// hudView.addSubview(indicatorView) -// indicatorView.startAnimating() -// view.addSubview(hudView) -// } -//} diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..8675e2f --- /dev/null +++ b/Podfile @@ -0,0 +1,6 @@ +platform :ios, '8.4' + +use_frameworks! + +pod 'Parse' +pod 'Spring', :git => 'https://github.com/MengTo/Spring.git', :branch => 'swift2' diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..381bd7e --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,26 @@ +PODS: + - Bolts/Tasks (1.2.0) + - Parse (1.7.5.3): + - Bolts/Tasks (>= 1.2.0) + - Spring (1.0.3) + +DEPENDENCIES: + - Parse + - Spring (from `https://github.com/MengTo/Spring.git`, branch `swift2`) + +EXTERNAL SOURCES: + Spring: + :branch: swift2 + :git: https://github.com/MengTo/Spring.git + +CHECKOUT OPTIONS: + Spring: + :commit: 18d5c7b74489de8044e34767f856d1e574f0820e + :git: https://github.com/MengTo/Spring.git + +SPEC CHECKSUMS: + Bolts: d176cb1e0012175589e389a9db49b85e27787576 + Parse: 373adbb1ad2e34d383542c3b28f678c49ebe4881 + Spring: 3f02b5dc3308572ef177b3cad0fa7bbc4b0706f7 + +COCOAPODS: 0.39.0 diff --git a/Pods/Bolts/Bolts/Common/BFCancellationToken.h b/Pods/Bolts/Bolts/Common/BFCancellationToken.h new file mode 100644 index 0000000..90a20d7 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationToken.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import + +/*! + A block that will be called when a token is cancelled. + */ +typedef void(^BFCancellationBlock)(); + +/*! + The consumer view of a CancellationToken. + Propagates notification that operations should be canceled. + A BFCancellationToken has methods to inspect whether the token has been cancelled. + */ +@interface BFCancellationToken : NSObject + +/*! + Whether cancellation has been requested for this token source. + */ +@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested; + +/*! + Register a block to be notified when the token is cancelled. + If the token is already cancelled the delegate will be notified immediately. + */ +- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFCancellationToken.m b/Pods/Bolts/Bolts/Common/BFCancellationToken.m new file mode 100644 index 0000000..0d91795 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationToken.m @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFCancellationToken.h" +#import "BFCancellationTokenRegistration.h" + +@interface BFCancellationToken () + +@property (atomic, assign, getter=isCancellationRequested) BOOL cancellationRequested; +@property (nonatomic, strong) NSMutableArray *registrations; +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic) BOOL disposed; + +@end + +@interface BFCancellationTokenRegistration (BFCancellationToken) + ++ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate; + +- (void)notifyDelegate; + +@end + +@implementation BFCancellationToken + +#pragma mark - Initializer + +- (instancetype)init { + if (self = [super init]) { + _registrations = [NSMutableArray array]; + _lock = [NSObject new]; + } + return self; +} + +#pragma mark - Custom Setters/Getters + +- (BOOL)isCancellationRequested { + @synchronized(self.lock) { + [self throwIfDisposed]; + return _cancellationRequested; + } +} + +- (void)cancel { + NSArray *registrations; + @synchronized(self.lock) { + [self throwIfDisposed]; + if (_cancellationRequested) { + return; + } + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; + _cancellationRequested = YES; + registrations = [self.registrations copy]; + } + + [self notifyCancellation:registrations]; +} + +- (void)notifyCancellation:(NSArray *)registrations { + for (BFCancellationTokenRegistration *registration in registrations) { + [registration notifyDelegate]; + } +} + +- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block { + @synchronized(self.lock) { + BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration registrationWithToken:self delegate:[block copy]]; + [self.registrations addObject:registration]; + + return registration; + } +} + +- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration { + @synchronized(self.lock) { + [self throwIfDisposed]; + [self.registrations removeObject:registration]; + } +} + +// Delay on a non-public method to prevent interference with a user calling performSelector or +// cancelPreviousPerformRequestsWithTarget on the public method +- (void)cancelPrivate { + [self cancel]; +} + +- (void)cancelAfterDelay:(int)millis { + [self throwIfDisposed]; + NSAssert(millis >= -1, @"Delay must be >= -1"); + + if (millis == 0) { + [self cancel]; + return; + } + + @synchronized(self.lock) { + [self throwIfDisposed]; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil]; + if (self.cancellationRequested) { + return; + } + + if (millis != -1) { + double delay = (double)millis / 1000; + [self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay]; + } + } +} + +- (void)dispose { + @synchronized(self.lock) { + if (self.disposed) { + return; + } + self.disposed = YES; + for (BFCancellationTokenRegistration *registration in self.registrations) { + [registration dispose]; + } + [self.registrations removeAllObjects]; + } +} + +- (void)throwIfDisposed { + NSAssert(!self.disposed, @"Object already disposed"); +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h new file mode 100644 index 0000000..3e7b711 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! + Represents the registration of a cancellation observer with a cancellation token. + Can be used to unregister the observer at a later time. + */ +@interface BFCancellationTokenRegistration : NSObject + +/*! + Removes the cancellation observer registered with the token + and releases all resources associated with this registration. + */ +- (void)dispose; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m new file mode 100644 index 0000000..9c8a7ae --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFCancellationTokenRegistration.h" + +#import "BFCancellationToken.h" + +@interface BFCancellationTokenRegistration () + +@property (nonatomic, weak) BFCancellationToken *token; +@property (nonatomic, strong) BFCancellationBlock cancellationObserverBlock; +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic) BOOL disposed; + +@end + +@interface BFCancellationToken (BFCancellationTokenRegistration) + +- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration; + +@end + +@implementation BFCancellationTokenRegistration + ++ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate { + BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration new]; + registration.token = token; + registration.cancellationObserverBlock = delegate; + return registration; +} + +- (instancetype)init { + if (self = [super init]) { + _lock = [NSObject new]; + } + return self; +} + +- (void)dispose { + @synchronized(self.lock) { + if (self.disposed) { + return; + } + self.disposed = YES; + } + + BFCancellationToken *token = self.token; + if (token != nil) { + [token unregisterRegistration:self]; + self.token = nil; + } + self.cancellationObserverBlock = nil; +} + +- (void)notifyDelegate { + @synchronized(self.lock) { + [self throwIfDisposed]; + self.cancellationObserverBlock(); + } +} + +- (void)throwIfDisposed { + NSAssert(!self.disposed, @"Object already disposed"); +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h new file mode 100644 index 0000000..bd6e7a1 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +@class BFCancellationToken; + +/*! + BFCancellationTokenSource represents the producer side of a CancellationToken. + Signals to a CancellationToken that it should be canceled. + It is a cancellation token that also has methods + for changing the state of a token by cancelling it. + */ +@interface BFCancellationTokenSource : NSObject + +/*! + Creates a new cancellation token source. + */ ++ (instancetype)cancellationTokenSource; + +/*! + The cancellation token associated with this CancellationTokenSource. + */ +@property (nonatomic, strong, readonly) BFCancellationToken *token; + +/*! + Whether cancellation has been requested for this token source. + */ +@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested; + +/*! + Cancels the token if it has not already been cancelled. + */ +- (void)cancel; + +/*! + Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds. + @param millis The number of milliseconds to wait before completing the returned task. + If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped. + */ +- (void)cancelAfterDelay:(int)millis; + +/*! + Releases all resources associated with this token source, + including disposing of all registrations. + */ +- (void)dispose; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m new file mode 100644 index 0000000..676b13b --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFCancellationTokenSource.h" + +#import "BFCancellationToken.h" + +@interface BFCancellationTokenSource () + +@property (nonatomic, strong, readwrite) BFCancellationToken *token; +@property (atomic, assign, readwrite, getter=isCancellationRequested) BOOL cancellationRequested; +@property (atomic, assign) BOOL disposed; +@property (nonatomic, strong) NSObject *lock; + +@end + +@interface BFCancellationToken (BFCancellationTokenSource) + +- (void)cancel; + +- (void)cancelAfterDelay:(int)millis; + +- (void)dispose; + +- (void)throwIfDisposed; + +@end + +@implementation BFCancellationTokenSource + +#pragma mark - Initializer + ++ (instancetype)cancellationTokenSource { + return [BFCancellationTokenSource new]; +} + +- (instancetype)init { + if (self = [super init]) { + _token = [BFCancellationToken new]; + _lock = [NSObject new]; + } + return self; +} + +#pragma mark - Custom Setters/Getters + +- (BOOL)isCancellationRequested { + return _token.isCancellationRequested; +} + +- (void)cancel { + [_token cancel]; +} + +- (void)cancelAfterDelay:(int)millis { + [_token cancelAfterDelay:millis]; +} + +- (void)dispose { + [_token dispose]; +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BFExecutor.h b/Pods/Bolts/Bolts/Common/BFExecutor.h new file mode 100644 index 0000000..02af9ba --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFExecutor.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! + An object that can run a given block. + */ +@interface BFExecutor : NSObject + +/*! + Returns a default executor, which runs continuations immediately until the call stack gets too + deep, then dispatches to a new GCD queue. + */ ++ (instancetype)defaultExecutor; + +/*! + Returns an executor that runs continuations on the thread where the previous task was completed. + */ ++ (instancetype)immediateExecutor; + +/*! + Returns an executor that runs continuations on the main thread. + */ ++ (instancetype)mainThreadExecutor; + +/*! + Returns a new executor that uses the given block to execute continuations. + @param block The block to use. + */ ++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `dispatch_queue_t` to dispatch all continuations onto. + */ ++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `NSOperationQueue` to run all continuations on. + */ ++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue; + +/*! + Runs the given block using this executor's particular strategy. + @param block The block to execute. + */ +- (void)execute:(void(^)())block; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFExecutor.m b/Pods/Bolts/Bolts/Common/BFExecutor.m new file mode 100644 index 0000000..292e27c --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFExecutor.m @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFExecutor.h" + +@interface BFExecutor () + +@property (nonatomic, copy) void(^block)(void(^block)()); + +@end + +@implementation BFExecutor + +#pragma mark - Executor methods + ++ (instancetype)defaultExecutor { + static BFExecutor *defaultExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultExecutor = [self executorWithBlock:^void(void(^block)()) { + static const NSString *BFTaskDepthKey = @"BFTaskDepth"; + static const int BFTaskDefaultExecutorMaxDepth = 20; + + // We prefer to run everything possible immediately, so that there is callstack information + // when debugging. However, we don't want the stack to get too deep, so if the number of + // recursive calls to this method exceeds a certain depth, we dispatch to another GCD queue. + NSMutableDictionary *threadLocal = [[NSThread currentThread] threadDictionary]; + NSNumber *depth = threadLocal[BFTaskDepthKey]; + if (!depth) { + depth = @0; + } + if (depth.intValue > BFTaskDefaultExecutorMaxDepth) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); + } else { + NSNumber *previousDepth = depth; + threadLocal[BFTaskDepthKey] = @(previousDepth.intValue + 1); + @try { + block(); + } @finally { + threadLocal[BFTaskDepthKey] = previousDepth; + } + } + }]; + }); + return defaultExecutor; +} + ++ (instancetype)immediateExecutor { + static BFExecutor *immediateExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + immediateExecutor = [self executorWithBlock:^void(void(^block)()) { + block(); + }]; + }); + return immediateExecutor; +} + ++ (instancetype)mainThreadExecutor { + static BFExecutor *mainThreadExecutor = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + mainThreadExecutor = [self executorWithBlock:^void(void(^block)()) { + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), block); + } else { + block(); + } + }]; + }); + return mainThreadExecutor; +} + ++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block { + return [[self alloc] initWithBlock:block]; +} + ++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue { + return [self executorWithBlock:^void(void(^block)()) { + dispatch_async(queue, block); + }]; +} + ++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue { + return [self executorWithBlock:^void(void(^block)()) { + [queue addOperation:[NSBlockOperation blockOperationWithBlock:block]]; + }]; +} + +#pragma mark - Initializer + +- (instancetype)initWithBlock:(void(^)(void(^block)()))block { + if (self = [super init]) { + _block = block; + } + return self; +} + +#pragma mark - Execution + +- (void)execute:(void(^)())block { + self.block(block); +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BFTask.h b/Pods/Bolts/Bolts/Common/BFTask.h new file mode 100644 index 0000000..dee1137 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFTask.h @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import + +/*! + Error domain used if there was multiple errors on . + */ +extern NSString *const BFTaskErrorDomain; + +/*! + An exception that is thrown if there was multiple exceptions on . + */ +extern NSString *const BFTaskMultipleExceptionsException; + +@class BFExecutor; +@class BFTask; + +/*! + A block that can act as a continuation for a task. + */ +typedef id(^BFContinuationBlock)(BFTask *task); + +/*! + The consumer view of a Task. A BFTask has methods to + inspect the state of the task, and to add continuations to + be run once the task is complete. + */ +@interface BFTask : NSObject + +/*! + Creates a task that is already completed with the given result. + @param result The result for the task. + */ ++ (instancetype)taskWithResult:(id)result; + +/*! + Creates a task that is already completed with the given error. + @param error The error for the task. + */ ++ (instancetype)taskWithError:(NSError *)error; + +/*! + Creates a task that is already completed with the given exception. + @param exception The exception for the task. + */ ++ (instancetype)taskWithException:(NSException *)exception; + +/*! + Creates a task that is already cancelled. + */ ++ (instancetype)cancelledTask; + +/*! + Returns a task that will be completed (with result == nil) once + all of the input tasks have completed. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasks:(NSArray *)tasks; + +/*! + Returns a task that will be completed once all of the input tasks have completed. + If all tasks complete successfully without being faulted or cancelled the result will be + an `NSArray` of all task results in the order they were provided. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasksWithResults:(NSArray *)tasks; + +/*! + Returns a task that will be completed a certain amount of time in the future. + @param millis The approximate number of milliseconds to wait before the + task will be finished (with result == nil). + */ ++ (instancetype)taskWithDelay:(int)millis; + +/*! + Returns a task that will be completed a certain amount of time in the future. + @param millis The approximate number of milliseconds to wait before the + task will be finished (with result == nil). + @param token The cancellation token (optional). + */ ++ (instancetype)taskWithDelay:(int)millis + cancellationToken:(BFCancellationToken *)token; + +/*! + Returns a task that will be completed after the given block completes with + the specified executor. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to immediately schedule to run with the given executor. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ ++ (instancetype)taskFromExecutor:(BFExecutor *)executor + withBlock:(id (^)())block; + +// Properties that will be set on the task once it is completed. + +/*! + The result of a successful task. + */ +@property (nonatomic, strong, readonly) id result; + +/*! + The error of a failed task. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/*! + The exception of a failed task. + */ +@property (nonatomic, strong, readonly) NSException *exception; + +/*! + Whether this task has been cancelled. + */ +@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled; + +/*! + Whether this task has completed due to an error or exception. + */ +@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted; + +/*! + Whether this task has completed. + */ +@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed; + +/*! + Enqueues the given block to be run once this task is complete. + This method uses a default execution strategy. The block will be + run on the thread where the previous task completes, unless the + the stack depth is too deep, in which case it will be run on a + dispatch queue with default priority. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithBlock:(BFContinuationBlock)block; + +/*! + Enqueues the given block to be run once this task is complete. + This method uses a default execution strategy. The block will be + run on the thread where the previous task completes, unless the + the stack depth is too deep, in which case it will be run on a + dispatch queue with default priority. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken; + +/*! + Enqueues the given block to be run once this task is complete. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withBlock:(BFContinuationBlock)block; +/*! + Enqueues the given block to be run once this task is complete. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + his method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + block:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken; + +/*! + Identical to continueWithBlock:, except that the block is only run + if this task did not produce a cancellation, error, or exception. + If it did, then the failure will be propagated to the returned + task. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block; + +/*! + Identical to continueWithBlock:, except that the block is only run + if this task did not produce a cancellation, error, or exception. + If it did, then the failure will be propagated to the returned + task. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken; + +/*! + Identical to continueWithExecutor:withBlock:, except that the block + is only run if this task did not produce a cancellation, error, or + exception. If it did, then the failure will be propagated to the + returned task. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withSuccessBlock:(BFContinuationBlock)block; + +/*! + Identical to continueWithExecutor:withBlock:, except that the block + is only run if this task did not produce a cancellation, error, or + exception. If it did, then the failure will be propagated to the + returned task. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @param cancellationToken The cancellation token (optional). + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + successBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken; + +/*! + Waits until this operation is completed. + This method is inefficient and consumes a thread resource while + it's running. It should be avoided. This method logs a warning + message if it is used on the main thread. + */ +- (void)waitUntilFinished; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFTask.m b/Pods/Bolts/Bolts/Common/BFTask.m new file mode 100644 index 0000000..58f89cf --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFTask.m @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFTask.h" + +#import + +#import "Bolts.h" + +__attribute__ ((noinline)) void warnBlockingOperationOnMainThread() { + NSLog(@"Warning: A long-running operation is being executed on the main thread. \n" + " Break on warnBlockingOperationOnMainThread() to debug."); +} + +NSString *const BFTaskErrorDomain = @"bolts"; +NSString *const BFTaskMultipleExceptionsException = @"BFMultipleExceptionsException"; + +@interface BFTask () { + id _result; + NSError *_error; + NSException *_exception; +} + +@property (atomic, assign, readwrite, getter=isCancelled) BOOL cancelled; +@property (atomic, assign, readwrite, getter=isFaulted) BOOL faulted; +@property (atomic, assign, readwrite, getter=isCompleted) BOOL completed; + +@property (nonatomic, strong) NSObject *lock; +@property (nonatomic, strong) NSCondition *condition; +@property (nonatomic, strong) NSMutableArray *callbacks; + +@end + +@implementation BFTask + +#pragma mark - Initializer + +- (instancetype)init { + if (self = [super init]) { + _lock = [[NSObject alloc] init]; + _condition = [[NSCondition alloc] init]; + _callbacks = [NSMutableArray array]; + } + return self; +} + +#pragma mark - Task Class methods + ++ (instancetype)taskWithResult:(id)result { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + tcs.result = result; + return tcs.task; +} + ++ (instancetype)taskWithError:(NSError *)error { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + tcs.error = error; + return tcs.task; +} + ++ (instancetype)taskWithException:(NSException *)exception { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + tcs.exception = exception; + return tcs.task; +} + ++ (instancetype)cancelledTask { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + [tcs cancel]; + return tcs.task; +} + ++ (instancetype)taskForCompletionOfAllTasks:(NSArray *)tasks { + __block int32_t total = (int32_t)tasks.count; + if (total == 0) { + return [self taskWithResult:nil]; + } + + __block int32_t cancelled = 0; + NSObject *lock = [[NSObject alloc] init]; + NSMutableArray *errors = [NSMutableArray array]; + NSMutableArray *exceptions = [NSMutableArray array]; + + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + for (BFTask *task in tasks) { + [task continueWithBlock:^id(BFTask *task) { + if (task.exception) { + @synchronized (lock) { + [exceptions addObject:task.exception]; + } + } else if (task.error) { + @synchronized (lock) { + [errors addObject:task.error]; + } + } else if (task.cancelled) { + OSAtomicIncrement32(&cancelled); + } + + if (OSAtomicDecrement32(&total) == 0) { + if (exceptions.count > 0) { + if (exceptions.count == 1) { + tcs.exception = [exceptions firstObject]; + } else { + NSException *exception = + [NSException exceptionWithName:BFTaskMultipleExceptionsException + reason:@"There were multiple exceptions." + userInfo:@{ @"exceptions": exceptions }]; + tcs.exception = exception; + } + } else if (errors.count > 0) { + if (errors.count == 1) { + tcs.error = [errors firstObject]; + } else { + NSError *error = [NSError errorWithDomain:BFTaskErrorDomain + code:kBFMultipleErrorsError + userInfo:@{ @"errors": errors }]; + tcs.error = error; + } + } else if (cancelled > 0) { + [tcs cancel]; + } else { + tcs.result = nil; + } + } + return nil; + }]; + } + return tcs.task; +} + ++ (instancetype)taskForCompletionOfAllTasksWithResults:(NSArray *)tasks { + return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(BFTask *task) { + return [tasks valueForKey:@"result"]; + }]; +} + ++ (instancetype)taskWithDelay:(int)millis { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); + dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + tcs.result = nil; + }); + return tcs.task; +} + ++ (instancetype)taskWithDelay:(int)millis + cancellationToken:(BFCancellationToken *)token { + if (token.cancellationRequested) { + return [BFTask cancelledTask]; + } + + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC); + dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + if (token.cancellationRequested) { + [tcs cancel]; + return; + } + tcs.result = nil; + }); + return tcs.task; +} + ++ (instancetype)taskFromExecutor:(BFExecutor *)executor + withBlock:(id (^)())block { + return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:block]; +} + +#pragma mark - Custom Setters/Getters + +- (id)result { + @synchronized(self.lock) { + return _result; + } +} + +- (void)setResult:(id)result { + if (![self trySetResult:result]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot set the result on a completed task."]; + } +} + +- (BOOL)trySetResult:(id)result { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + _result = result; + [self runContinuations]; + return YES; + } +} + +- (NSError *)error { + @synchronized(self.lock) { + return _error; + } +} + +- (void)setError:(NSError *)error { + if (![self trySetError:error]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot set the error on a completed task."]; + } +} + +- (BOOL)trySetError:(NSError *)error { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + self.faulted = YES; + _error = error; + [self runContinuations]; + return YES; + } +} + +- (NSException *)exception { + @synchronized(self.lock) { + return _exception; + } +} + +- (void)setException:(NSException *)exception { + if (![self trySetException:exception]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot set the exception on a completed task."]; + } +} + +- (BOOL)trySetException:(NSException *)exception { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + self.faulted = YES; + _exception = exception; + [self runContinuations]; + return YES; + } +} + +- (BOOL)isCancelled { + @synchronized(self.lock) { + return _cancelled; + } +} + +- (BOOL)isFaulted { + @synchronized(self.lock) { + return _faulted; + } +} + +- (void)cancel { + @synchronized(self.lock) { + if (![self trySetCancelled]) { + [NSException raise:NSInternalInconsistencyException + format:@"Cannot cancel a completed task."]; + } + } +} + +- (BOOL)trySetCancelled { + @synchronized(self.lock) { + if (self.completed) { + return NO; + } + self.completed = YES; + self.cancelled = YES; + [self runContinuations]; + return YES; + } +} + +- (BOOL)isCompleted { + @synchronized(self.lock) { + return _completed; + } +} + +- (void)setCompleted { + @synchronized(self.lock) { + _completed = YES; + } +} + +- (void)runContinuations { + @synchronized(self.lock) { + [self.condition lock]; + [self.condition broadcast]; + [self.condition unlock]; + for (void (^callback)() in self.callbacks) { + callback(); + } + [self.callbacks removeAllObjects]; + } +} + +#pragma mark - Chaining methods + +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:executor block:block cancellationToken:nil]; +} + +- (instancetype)continueWithExecutor:(BFExecutor *)executor + block:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken { + BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]; + + // Capture all of the state that needs to used when the continuation is complete. + void (^wrappedBlock)() = ^() { + [executor execute:^{ + if (cancellationToken.cancellationRequested) { + [tcs cancel]; + return; + } + + id result = nil; + @try { + result = block(self); + } @catch (NSException *exception) { + tcs.exception = exception; + return; + } + + if ([result isKindOfClass:[BFTask class]]) { + + id (^setupWithTask) (BFTask *) = ^id(BFTask *task) { + if (task.cancelled) { + [tcs cancel]; + } else if (task.exception) { + tcs.exception = task.exception; + } else if (task.error) { + tcs.error = task.error; + } else { + tcs.result = task.result; + } + return nil; + }; + + BFTask *resultTask = (BFTask *)result; + + if (resultTask.completed) { + setupWithTask(resultTask); + } else { + [resultTask continueWithBlock:setupWithTask cancellationToken:cancellationToken]; + } + + } else { + tcs.result = result; + } + }]; + }; + + BOOL completed; + @synchronized(self.lock) { + completed = self.completed; + if (!completed) { + [self.callbacks addObject:[wrappedBlock copy]]; + } + } + if (completed) { + wrappedBlock(); + } + + return tcs.task; +} + +- (instancetype)continueWithBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:nil]; +} + +- (instancetype)continueWithBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken { + return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:cancellationToken]; +} + +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withSuccessBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:executor successBlock:block cancellationToken:nil]; +} + +- (instancetype)continueWithExecutor:(BFExecutor *)executor + successBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken { + if (cancellationToken.cancellationRequested) { + return [BFTask cancelledTask]; + } + + return [self continueWithExecutor:executor block:^id(BFTask *task) { + if (task.faulted || task.cancelled) { + return task; + } else { + return block(task); + } + } cancellationToken:cancellationToken]; +} + +- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block { + return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:nil]; +} + +- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block + cancellationToken:(BFCancellationToken *)cancellationToken { + return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken]; +} + +#pragma mark - Syncing Task (Avoid it) + +- (void)warnOperationOnMainThread { + warnBlockingOperationOnMainThread(); +} + +- (void)waitUntilFinished { + if ([NSThread isMainThread]) { + [self warnOperationOnMainThread]; + } + + @synchronized(self.lock) { + if (self.completed) { + return; + } + [self.condition lock]; + } + [self.condition wait]; + [self.condition unlock]; +} + +#pragma mark - NSObject + +- (NSString *)description { + // Acquire the data from the locked properties + BOOL completed; + BOOL cancelled; + BOOL faulted; + + @synchronized(self.lock) { + completed = self.completed; + cancelled = self.cancelled; + faulted = self.faulted; + } + + // Description string includes status information and, if available, the + // result since in some ways this is what a promise actually "is". + return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>", + NSStringFromClass([self class]), + self, + completed ? @"YES" : @"NO", + cancelled ? @"YES" : @"NO", + faulted ? @"YES" : @"NO", + completed ? [NSString stringWithFormat:@" result:%@", _result] : @""]; +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h new file mode 100644 index 0000000..be2fbdb --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +@class BFTask; + +/*! + A BFTaskCompletionSource represents the producer side of tasks. + It is a task that also has methods for changing the state of the + task by settings its completion values. + */ +@interface BFTaskCompletionSource : NSObject + +/*! + Creates a new unfinished task. + */ ++ (instancetype)taskCompletionSource; + +/*! + The task associated with this TaskCompletionSource. + */ +@property (nonatomic, strong, readonly) BFTask *task; + +/*! + Completes the task by setting the result. + Attempting to set this for a completed task will raise an exception. + @param result The result of the task. + */ +- (void)setResult:(id)result; + +/*! + Completes the task by setting the error. + Attempting to set this for a completed task will raise an exception. + @param error The error for the task. + */ +- (void)setError:(NSError *)error; + +/*! + Completes the task by setting an exception. + Attempting to set this for a completed task will raise an exception. + @param exception The exception for the task. + */ +- (void)setException:(NSException *)exception; + +/*! + Completes the task by marking it as cancelled. + Attempting to set this for a completed task will raise an exception. + */ +- (void)cancel; + +/*! + Sets the result of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetResult:(id)result; + +/*! + Sets the error of the task if it wasn't already completed. + @param error The error for the task. + @returns whether the new value was set. + */ +- (BOOL)trySetError:(NSError *)error; + +/*! + Sets the exception of the task if it wasn't already completed. + @param exception The exception for the task. + @returns whether the new value was set. + */ +- (BOOL)trySetException:(NSException *)exception; + +/*! + Sets the cancellation state of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetCancelled; + +@end diff --git a/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m new file mode 100644 index 0000000..bd66835 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "BFTaskCompletionSource.h" + +#import "BFTask.h" + +@interface BFTaskCompletionSource () + +@property (nonatomic, strong, readwrite) BFTask *task; + +@end + +@interface BFTask (BFTaskCompletionSource) + +- (void)setResult:(id)result; +- (void)setError:(NSError *)error; +- (void)setException:(NSException *)exception; +- (void)cancel; +- (BOOL)trySetResult:(id)result; +- (BOOL)trySetError:(NSError *)error; +- (BOOL)trySetException:(NSException *)exception; +- (BOOL)trySetCancelled; + +@end + +@implementation BFTaskCompletionSource + +#pragma mark - Initializer + ++ (instancetype)taskCompletionSource { + return [[self alloc] init]; +} + +- (instancetype)init { + if (self = [super init]) { + _task = [[BFTask alloc] init]; + } + return self; +} + +#pragma mark - Custom Setters/Getters + +- (void)setResult:(id)result { + [self.task setResult:result]; +} + +- (void)setError:(NSError *)error { + [self.task setError:error]; +} + +- (void)setException:(NSException *)exception { + [self.task setException:exception]; +} + +- (void)cancel { + [self.task cancel]; +} + +- (BOOL)trySetResult:(id)result { + return [self.task trySetResult:result]; +} + +- (BOOL)trySetError:(NSError *)error { + return [self.task trySetError:error]; +} + +- (BOOL)trySetException:(NSException *)exception { + return [self.task trySetException:exception]; +} + +- (BOOL)trySetCancelled { + return [self.task trySetCancelled]; +} + +@end diff --git a/Pods/Bolts/Bolts/Common/Bolts.h b/Pods/Bolts/Bolts/Common/Bolts.h new file mode 100644 index 0000000..ca48a16 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/Bolts.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import +#import +#import +#import +#import +#import +#import + +#if __has_include() && TARGET_OS_IPHONE +#import +#import +#import +#import +#import +#import +#import +#import +#import +#endif + +/*! @abstract 80175001: There were multiple errors. */ +extern NSInteger const kBFMultipleErrorsError; + +@interface Bolts : NSObject + +/*! + Returns the version of the Bolts Framework as an NSString. + @returns The NSString representation of the current version. + */ ++ (NSString *)version; + +@end diff --git a/Pods/Bolts/Bolts/Common/Bolts.m b/Pods/Bolts/Bolts/Common/Bolts.m new file mode 100644 index 0000000..9a3e75c --- /dev/null +++ b/Pods/Bolts/Bolts/Common/Bolts.m @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "Bolts.h" + +NSInteger const kBFMultipleErrorsError = 80175001; + +@implementation Bolts + ++ (NSString *)version { + return BOLTS_VERSION; +} + +@end diff --git a/Pods/Bolts/Bolts/Common/BoltsVersion.h b/Pods/Bolts/Bolts/Common/BoltsVersion.h new file mode 100644 index 0000000..08353c4 --- /dev/null +++ b/Pods/Bolts/Bolts/Common/BoltsVersion.h @@ -0,0 +1 @@ +#define BOLTS_VERSION @"1.2.0" diff --git a/Pods/Bolts/LICENSE b/Pods/Bolts/LICENSE new file mode 100644 index 0000000..e1a5831 --- /dev/null +++ b/Pods/Bolts/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Bolts software + +Copyright (c) 2013-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Pods/Bolts/Readme.md b/Pods/Bolts/Readme.md new file mode 100644 index 0000000..b9d7690 --- /dev/null +++ b/Pods/Bolts/Readme.md @@ -0,0 +1,682 @@ +Bolts +============ +[![Build Status](http://img.shields.io/travis/BoltsFramework/Bolts-iOS/master.svg?style=flat)](https://travis-ci.org/BoltsFramework/Bolts-iOS) +[![Coverage Status](https://coveralls.io/repos/BoltsFramework/Bolts-iOS/badge.svg)](https://coveralls.io/r/BoltsFramework/Bolts-iOS) +[![Pod Version](http://img.shields.io/cocoapods/v/Bolts.svg?style=flat)](http://cocoadocs.org/docsets/Bolts/) +[![Pod Platform](http://img.shields.io/cocoapods/p/Bolts.svg?style=flat)](http://cocoadocs.org/docsets/Bolts/) +[![Pod License](http://img.shields.io/cocoapods/l/Bolts.svg?style=flat)](https://github.com/BoltsFramework/Bolts-iOS/blob/master/LICENSE) +[![Dependency Status](https://www.versioneye.com/objective-c/bolts/1.1.1/badge.svg?style=flat)](https://www.versioneye.com/objective-c/bolts) +[![Reference Status](https://www.versioneye.com/objective-c/bolts/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/bolts/references) + +Bolts is a collection of low-level libraries designed to make developing mobile +apps easier. Bolts was designed by Parse and Facebook for our own internal use, +and we have decided to open source these libraries to make them available to +others. Using these libraries does not require using any Parse services. Nor +do they require having a Parse or Facebook developer account. + +Bolts includes: + +* "Tasks", which make organization of complex asynchronous code more manageable. A task is kind of like a JavaScript Promise, but available for iOS and Android. +* An implementation of the [App Links protocol](http://www.applinks.org), helping you link to content in other apps and handle incoming deep-links. + +For more information, see the [Bolts iOS API Reference](http://boltsframework.github.io/docs/ios/). + +# Tasks + +To build a truly responsive iOS application, you must keep long-running operations off of the UI thread, and be careful to avoid blocking anything the UI thread might be waiting on. This means you will need to execute various operations in the background. To make this easier, we've added a class called `BFTask`. A task represents the result of an asynchronous operation. Typically, a `BFTask` is returned from an asynchronous function and gives the ability to continue processing the result of the task. When a task is returned from a function, it's already begun doing its job. A task is not tied to a particular threading model: it represents the work being done, not where it is executing. Tasks have many advantages over other methods of asynchronous programming, such as callbacks. `BFTask` is not a replacement for `NSOperation` or GCD. In fact, they play well together. But tasks do fill in some gaps that those technologies don't address. +* `BFTask` takes care of managing dependencies for you. Unlike using `NSOperation` for dependency management, you don't have to declare all dependencies before starting a `BFTask`. For example, imagine you need to save a set of objects and each one may or may not require saving child objects. With an `NSOperation`, you would normally have to create operations for each of the child saves ahead of time. But you don't always know before you start the work whether that's going to be necessary. That can make managing dependencies with `NSOperation` very painful. Even in the best case, you have to create your dependencies before the operations that depend on them, which results in code that appears in a different order than it executes. With `BFTask`, you can decide during your operation's work whether there will be subtasks and return the other task in just those cases. +* `BFTasks` release their dependencies. `NSOperation` strongly retains its dependencies, so if you have a queue of ordered operations and sequence them using dependencies, you have a leak, because every operation gets retained forever. `BFTasks` release their callbacks as soon as they are run, so everything cleans up after itself. This can reduce memory use, and simplify memory management. +* `BFTasks` keep track of the state of finished tasks: It tracks whether there was a returned value, the task was cancelled, or if an error occurred. It also has convenience methods for propagating errors. With `NSOperation`, you have to build all of this stuff yourself. +* `BFTasks` don't depend on any particular threading model. So it's easy to have some tasks perform their work with an operation queue, while others perform work using blocks with GCD. These tasks can depend on each other seamlessly. +* Performing several tasks in a row will not create nested "pyramid" code as you would get when using only callbacks. +* `BFTasks` are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks. +* You can arrange task-based code in the order that it executes, rather than having to split your logic across scattered callback functions. + +For the examples in this doc, assume there are async versions of some common Parse methods, called `saveAsync:` and `findAsync:` which return a `Task`. In a later section, we'll show how to define these functions yourself. + +## The `continueWithBlock` Method + +Every `BFTask` has a method named `continueWithBlock:` which takes a continuation block. A continuation is a block that will be executed when the task is complete. You can then inspect the task to check if it was successful and to get its result. + +```objective-c +// Objective-C +[[self saveAsync:obj] continueWithBlock:^id(BFTask *task) { + if (task.isCancelled) { + // the save was cancelled. + } else if (task.error) { + // the save failed. + } else { + // the object was saved successfully. + PFObject *object = task.result; + } + return nil; +}]; +``` + +```swift +// Swift +self.saveAsync(obj).continueWithBlock { + (task: BFTask!) -> BFTask in + if task.isCancelled() { + // the save was cancelled. + } else if task.error() { + // the save failed. + } else { + // the object was saved successfully. + var object = task.result() as PFObject + } +} +``` + +BFTasks use Objective-C blocks, so the syntax should be pretty straightforward. Let's look closer at the types involved with an example. + +```objective-c +// Objective-C +/** + * Gets an NSString asynchronously. + */ +- (BFTask *)getStringAsync { + // Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber. + return [[self getNumberAsync] continueWithBlock:^id(BFTask *task) { + // This continuation block takes the NSNumber BFTask as input, + // and provides an NSString as output. + + NSNumber *number = task.result; + return [NSString stringWithFormat:@"%@", number]; + )]; +} +``` + +```swift +// Swift +/** + * Gets an NSString asynchronously. + */ +func getStringAsync() -> BFTask { + //Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber. + return self.getNumberAsync().continueWithBlock { + (task: BFTask!) -> NSString in + // This continuation block takes the NSNumber BFTask as input, + // and provides an NSString as output. + + let number = task.result() as NSNumber + return NSString(format:"%@", number) + } +} +``` + +In many cases, you only want to do more work if the previous task was successful, and propagate any errors or cancellations to be dealt with later. To do this, use the `continueWithSuccessBlock:` method instead of `continueWithBlock:`. + +```objective-c +// Objective-C +[[self saveAsync:obj] continueWithSuccessBlock:^id(BFTask *task) { + // the object was saved successfully. + return nil; +}]; +``` + +```swift +// Swift +self.saveAsync(obj).continueWithSuccessBlock { + (task: BFTask!) -> AnyObject! in + // the object was saved successfully. + return nil +} +``` + +## Chaining Tasks Together + +BFTasks are a little bit magical, in that they let you chain them without nesting. If you return a BFTask from `continueWithBlock:`, then the task returned by `continueWithBlock:` will not be considered finished until the new task returned from the new continuation block. This lets you perform multiple actions without incurring the pyramid code you would get with callbacks. Likewise, you can return a `BFTask` from `continueWithSuccessBlock:`. So, return a `BFTask` to do more asynchronous work. + +```objective-c +// Objective-C +PFQuery *query = [PFQuery queryWithClassName:@"Student"]; +[query orderByDescending:@"gpa"]; +[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *students = task.result; + PFObject *valedictorian = [students objectAtIndex:0]; + [valedictorian setObject:@YES forKey:@"valedictorian"]; + return [self saveAsync:valedictorian]; +}] continueWithSuccessBlock:^id(BFTask *task) { + PFObject *valedictorian = task.result; + return [self findAsync:query]; +}] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *students = task.result; + PFObject *salutatorian = [students objectAtIndex:1]; + [salutatorian setObject:@YES forKey:@"salutatorian"]; + return [self saveAsync:salutatorian]; +}] continueWithSuccessBlock:^id(BFTask *task) { + // Everything is done! + return nil; +}]; +``` + +```swift +// Swift +var query = PFQuery(className:"Student") +query.orderByDescending("gpa") +findAsync(query).continueWithSuccessBlock { + (task: BFTask!) -> BFTask in + let students = task.result() as NSArray + var valedictorian = students.objectAtIndex(0) as PFObject + valedictorian["valedictorian"] = true + return self.saveAsync(valedictorian) +}.continueWithSuccessBlock { + (task: BFTask!) -> BFTask in + var valedictorian = task.result() as PFObject + return self.findAsync(query) +}.continueWithSuccessBlock { + (task: BFTask!) -> BFTask in + let students = task.result() as NSArray + var salutatorian = students.objectAtIndex(1) as PFObject + salutatorian["salutatorian"] = true + return self.saveAsync(salutatorian) +}.continueWithSuccessBlock { + (task: BFTask!) -> AnyObject! in + // Everything is done! + return nil +} +``` + +## Error Handling + +By carefully choosing whether to call `continueWithBlock:` or `continueWithSuccessBlock:`, you can control how errors are propagated in your application. Using `continueWithBlock:` lets you handle errors by transforming them or dealing with them. You can think of failed tasks kind of like throwing an exception. In fact, if you throw an exception inside a continuation, the resulting task will be faulted with that exception. + +```objective-c +// Objective-C +PFQuery *query = [PFQuery queryWithClassName:@"Student"]; +[query orderByDescending:@"gpa"]; +[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) { + NSArray *students = task.result; + PFObject *valedictorian = [students objectAtIndex:0]; + [valedictorian setObject:@YES forKey:@"valedictorian"]; + // Force this callback to fail. + return [BFTask taskWithError:[NSError errorWithDomain:@"example.com" + code:-1 + userInfo:nil]]; +}] continueWithSuccessBlock:^id(BFTask *task) { + // Now this continuation will be skipped. + PFQuery *valedictorian = task.result; + return [self findAsync:query]; +}] continueWithBlock:^id(BFTask *task) { + if (task.error) { + // This error handler WILL be called. + // The error will be the NSError returned above. + // Let's handle the error by returning a new value. + // The task will be completed with nil as its value. + return nil; + } + // This will also be skipped. + NSArray *students = task.result; + PFObject *salutatorian = [students objectAtIndex:1]; + [salutatorian setObject:@YES forKey:@"salutatorian"]; + return [self saveAsync:salutatorian]; +}] continueWithSuccessBlock:^id(BFTask *task) { + // Everything is done! This gets called. + // The task's result is nil. + return nil; +}]; +``` + +```swift +// Swift +var query = PFQuery(className:"Student") +query.orderByDescending("gpa") +findAsync(query).continueWithSuccessBlock { + (task: BFTask!) -> BFTask in + let students = task.result() as NSArray + var valedictorian = students.objectAtIndex(0) as PFObject + valedictorian["valedictorian"] = true + //Force this callback to fail. + return BFTask(error:NSError(domain:"example.com", + code:-1, userInfo: nil)) +}.continueWithSuccessBlock { + (task: BFTask!) -> AnyObject! in + //Now this continuation will be skipped. + var valedictorian = task.result() as PFObject + return self.findAsync(query) +}.continueWithBlock { + (task: BFTask!) -> AnyObject! in + if task.error() { + // This error handler WILL be called. + // The error will be the NSError returned above. + // Let's handle the error by returning a new value. + // The task will be completed with nil as its value. + return nil + } + // This will also be skipped. + let students = task.result() as NSArray + var salutatorian = students.objectAtIndex(1) as PFObject + salutatorian["salutatorian"] = true + return self.saveAsync(salutatorian) +}.continueWithSuccessBlock { + (task: BFTask!) -> AnyObject! in + // Everything is done! This gets called. + // The tasks result is nil. + return nil +} +``` + +It's often convenient to have a long chain of success callbacks with only one error handler at the end. + +## Creating Tasks + +When you're getting started, you can just use the tasks returned from methods like `findAsync:` or `saveAsync:`. However, for more advanced scenarios, you may want to make your own tasks. To do that, you create a `BFTaskCompletionSource`. This object will let you create a new `BFTask`, and control whether it gets marked as finished or cancelled. After you create a `BFTask`, you'll need to call `setResult:`, `setError:`, or `cancel` to trigger its continuations. + +```objective-c +// Objective-C +- (BFTask *)successAsync { + BFTaskCompletionSource *successful = [BFTaskCompletionSource taskCompletionSource]; + [successful setResult:@"The good result."]; + return successful.task; +} + +- (BFTask *)failAsync { + BFTaskCompletionSource *failed = [BFTaskCompletionSource taskCompletionSource]; + [failed setError:[NSError errorWithDomain:@"example.com" code:-1 userInfo:nil]]; + return failed.task; +} +``` + +```swift +// Swift +func successAsync() -> BFTask { + var successful = BFTaskCompletionSource() + successful.setResult("The good result.") + return successful.task +} + +func failAsync() -> BFTask { + var failed = BFTaskCompletionSource() + failed.setError(NSError(domain:"example.com", code:-1, userInfo:nil)) + return failed.task +} +``` + +If you know the result of a task at the time it is created, there are some convenience methods you can use. + +```objective-c +// Objective-C +BFTask *successful = [BFTask taskWithResult:@"The good result."]; + +BFTask *failed = [BFTask taskWithError:anError]; +``` + +```swift +// Swift +let successful = BFTask(result:"The good result") + +let failed = BFTask(error:anError) +``` + +## Creating Async Methods + +With these tools, it's easy to make your own asynchronous functions that return tasks. For example, you can make a task-based version of `fetchAsync:` easily. + +```objective-c +// Objective-C +- (BFTask *) fetchAsync:(PFObject *)object { + BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource]; + [object fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) { + if (!error) { + [task setResult:object]; + } else { + [task setError:error]; + } + }]; + return task.task; +} +``` + +```swift +// Swift +func fetchAsync(object: PFObject) -> BFTask { + var task = BFTaskCompletionSource() + object.fetchInBackgroundWithBlock { + (object: PFObject!, error: NSError!) -> Void in + if error == nil { + task.setResult(object) + } else { + task.setError(error) + } + } + return task.task +} + +``` + +It's similarly easy to create `saveAsync:`, `findAsync:` or `deleteAsync:`. + +## Tasks in Series + +`BFTasks` are convenient when you want to do a series of tasks in a row, each one waiting for the previous to finish. For example, imagine you want to delete all of the comments on your blog. + +```objective-c +// Objective-C +PFQuery *query = [PFQuery queryWithClassName:@"Comments"]; +[query whereKey:@"post" equalTo:@123]; + +[[[self findAsync:query] continueWithBlock:^id(BFTask *task) { + NSArray *results = task.result; + + // Create a trivial completed task as a base case. + BFTask *task = [BFTask taskWithResult:nil]; + for (PFObject *result in results) { + // For each item, extend the task with a function to delete the item. + task = [task continueWithBlock:^id(BFTask *task) { + // Return a task that will be marked as completed when the delete is finished. + return [self deleteAsync:result]; + }]; + } + return task; +}] continueWithBlock:^id(BFTask *task) { + // Every comment was deleted. + return nil; +}]; +``` + +```swift +// Swift +var query = PFQuery(className:"Comments") +query.whereKey("post", equalTo:123) +findAsync(query).continueWithBlock { + (task: BFTask!) -> BFTask in + let results = task.result() as NSArray + + // Create a trivial completed task as a base case. + let task = BFTask(result:nil) + for result : PFObject in results { + // For each item, extend the task with a function to delete the item. + task = task.continueWithBlock { + (task: BFTask!) -> BFTask in + return self.deleteAsync(result) + } + } + return task +}.continueWithBlock { + (task: BFTask!) -> AnyObject! in + // Every comment was deleted. + return nil +} +``` + +## Tasks in Parallel + +You can also perform several tasks in parallel, using the `taskForCompletionOfAllTasks:` method. You can start multiple operations at once, and use `taskForCompletionOfAllTasks:` to create a new task that will be marked as completed when all of its input tasks are completed. The new task will be successful only if all of the passed-in tasks succeed. Performing operations in parallel will be faster than doing them serially, but may consume more system resources and bandwidth. + +```objective-c +// Objective-C +PFQuery *query = [PFQuery queryWithClassName:@"Comments"]; +[query whereKey:@"post" equalTo:@123]; + +[[[self findAsync:query] continueWithBlock:^id(BFTask *results) { + // Collect one task for each delete into an array. + NSMutableArray *tasks = [NSMutableArray array]; + for (PFObject *result in results) { + // Start this delete immediately and add its task to the list. + [tasks addObject:[self deleteAsync:result]]; + } + // Return a new task that will be marked as completed when all of the deletes are + // finished. + return [BFTask taskForCompletionOfAllTasks:tasks]; +}] continueWithBlock:^id(BFTask *task) { + // Every comment was deleted. + return nil; +}]; +``` + +```swift +// Swift +var query = PFQuery(className:"Comments") +query.whereKey("post", equalTo:123) + +findAsync(query).continueWithBlock { + (task: BFTask!) -> BFTask in + // Collect one task for each delete into an array. + var tasks = NSMutableArray.array() + var results = task.result() as NSArray + for result : PFObject! in results { + // Start this delete immediately and add its task to the list. + tasks.addObject(self.deleteAsync(result)) + } + // Return a new task that will be marked as completed when all of the deletes + // are finished. + return BFTask(forCompletionOfAllTasks:tasks) +}.continueWithBlock { + (task: BFTask!) -> AnyObject! in + // Every comment was deleted. + return nil +} +``` + +## Task Executors + +Both `continueWithBlock:` and `continueWithSuccessBlock:` methods have another form that takes an instance of `BFExecutor`. These are `continueWithExecutor:withBlock:` and `continueWithExecutor:withSuccessBlock:`. These methods allow you to control how the continuation is executed. The default executor will dispatch to GCD, but you can provide your own executor to schedule work onto a different thread. For example, if you want to continue with work on the UI thread: + +```objective-c +// Create a BFExecutor that uses the main thread. +BFExecutor *myExecutor = [BFExecutor executorWithBlock:^void(void(^block)()) { + dispatch_async(dispatch_get_main_queue(), block); +}]; + +// And use the Main Thread Executor like this. The executor applies only to the new +// continuation being passed into continueWithBlock. +[[self fetchAsync:object] continueWithExecutor:myExecutor withBlock:^id(BFTask *task) { + myTextView.text = [object objectForKey:@"name"]; +}]; +``` + +For common cases, such as dispatching on the main thread, we have provided default implementations of `BFExecutor`. These include `defaultExecutor`, `immediateExecutor`, `mainThreadExecutor`, `executorWithDispatchQueue:`, and `executorWithOperationQueue:`. For example: + +```objective-c +// Continue on the Main Thread, using a built-in executor. +[[self fetchAsync:object] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) { + myTextView.text = [object objectForKey:@"name"]; +}]; +``` + +## Task Cancellation + +It's generally bad design to keep track of the `BFTaskCompletionSource` for cancellation. A better model is to create a "cancellation token" at the top level, and pass that to each async function that you want to be part of the same "cancelable operation". Then, in your continuation blocks, you can check whether the cancellation token has been cancelled and bail out early by returning a `[BFTask cancelledTask]`. For example: + +```objective-c +- (void)doSomethingComplicatedAsync:(MYCancellationToken *)cancellationToken { + [[self doSomethingAsync:cancellationToken] continueWithBlock:^{ + if (cancellationToken.isCancelled) { + return [BFTask cancelledTask]; + } + // Do something that takes a while. + return result; + }]; +} + +// Somewhere else. +MYCancellationToken *cancellationToken = [[MYCancellationToken alloc] init]; +[obj doSomethingComplicatedAsync:cancellationToken]; + +// When you get bored... +[cancellationToken cancel]; +``` + +**Note:** The cancellation token implementation should be thread-safe. +We are likely to add some concept like this to Bolts at some point in the future. + +# App Links + +[App Links](http://www.applinks.org) provide a cross-platform mechanism that allows a developer to define and publish a deep-linking scheme for their content, allowing other apps to link directly to an experience optimized for the device they are running on. Whether you are building an app that receives incoming links or one that may link out to other apps' content, Bolts provides tools to simplify implementation of the [App Links protocol](http://www.applinks.org/documentation). + +## Handling an App Link + +The most common case will be making your app receive App Links. In-linking will allow your users to quickly access the richest, most native-feeling presentation of linked content on their devices. Bolts makes it easy to handle an inbound App Link (as well as general inbound deep-links) by providing utilities for processing an incoming URL. + +For example, you can use the `BFURL` utility class to parse an incoming URL in your `AppDelegate`: + +```objective-c +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + BFURL *parsedUrl = [BFURL URLWithInboundURL:url sourceApplication:sourceApplication]; + + // Use the target URL from the App Link to locate content. + if ([parsedUrl.targetURL.pathComponents[1] isEqualToString:@"profiles"]) { + // Open a profile viewer. + } + + // You can also check the query string easily. + NSString *query = parsedUrl.targetQueryParameters[@"query"]; + + // Apps that have existing deep-linking support and map their App Links to existing + // deep-linking functionality may instead want to perform these operations on the input URL. + // Use the target URL from the App Link to locate content. + if ([parsedUrl.inputURL.pathComponents[1] isEqualToString:@"profiles"]) { + // Open a profile viewer. + } + + // You can also check the query string easily. + NSString *query = parsedUrl.inputQueryParameters[@"query"]; + + // Apps can easily check the Extras and App Link data from the App Link as well. + NSString *fbAccessToken = parsedUrl.appLinkExtras[@"fb_access_token"]; + NSDictionary *refererData = parsedUrl.appLinkExtras[@"referer"]; +} +``` + +## Navigating to a URL + +Following an App Link allows your app to provide the best user experience (as defined by the receiving app) when a user navigates to a link. Bolts makes this process simple, automating the steps required to follow a link: + +1. Resolve the App Link by getting the App Link metadata from the HTML at the URL specified. +2. Step through App Link targets relevant to the device being used, checking whether the app that can handle the target is present on the device. +3. If an app is present, build a URL with the appropriate al_applink_data specified and navigate to that URL. +4. Otherwise, open the browser with the original URL specified. + +In the simplest case, it takes just one line of code to navigate to a URL that may have an App Link: + +```objective-c +[BFAppLinkNavigation navigateToURLInBackground:url]; +``` + +### Adding App and Navigation Data + +Under most circumstances, the data that will need to be passed along to an app during a navigation will be contained in the URL itself, so that whether or not the app is actually installed on the device, users are taken to the correct content. Occasionally, however, apps will want to pass along data that is relevant for app-to-app navigation, or will want to augment the App Link protocol with information that might be used by the app to adjust how the app should behave (e.g. showing a link back to the referring app). + +If you want to take advantage of these features, you can break apart the navigation process. First, you must have an App Link to which you wish to navigate: + +```objective-c +[[BFAppLinkNavigation resolveAppLinkInBackground:url] continueWithSuccessBlock:^id(BFTask *task) { + BFAppLink *link = task.result; +}]; +``` + +Then, you can build an App Link request with any additional data you would like and navigate: + +```objective-c +BFAppLinkNavigation *navigation = [BFAppLinkNavigation navigationWithAppLink:link + extras:@{ @"access_token": @"t0kEn" } + appLinkData:@{ @"ref": @"12345" }]; +NSError *error = nil; +[navigation navigate:&error]; +``` + +### Resolving App Link Metadata + +Bolts allows for custom App Link resolution, which may be used as a performance optimization (e.g. caching the metadata) or as a mechanism to allow developers to use a centralized index for obtaining App Link metadata. A custom App Link resolver just needs to be able to take a URL and return a `BFAppLink` containing the ordered list of `BFAppLinkTarget`s that are applicable for this device. Bolts provides one of these out of the box that performs this resolution on the device using a hidden UIWebView. + +You can use any resolver that implements the `BFAppLinkResolving` protocol by using one of the overloads on `BFAppLinkNavigation`: + +```objective-c +[BFAppLinkNavigation navigateToURLInBackground:url + resolver:resolver]; +``` + +Alternatively, a you can swap out the default resolver to be used by the built-in APIs: + +```objective-c +[BFAppLinkNavigation setDefaultResolver:resolver]; +[BFAppLinkNavigation navigateToURLInBackground:url]; +``` + +## App Link Return-to-Referer View + +When an application is opened via an App Link, a banner allowing the user to "Touch to return to " should be displayed. The `BFAppLinkReturnToRefererView` provides this functionality. It will take an incoming App Link and parse the referer information to display the appropriate calling app name. + +```objective-c +- (void)viewDidLoad { + [super viewDidLoad]; + + // Perform other view initialization. + + self.returnToRefererController = [[BFAppLinkReturnToRefererController alloc] init]; + + // self.returnToRefererView is a BFAppLinkReturnToRefererView. + // You may initialize the view either by loading it from a NIB or programmatically. + self.returnToRefererController.view = self.returnToRefererView; + + // If you have a UINavigationController in the view, then the bar must be shown above it. + [self.returnToRefererController] +} +``` + +The following code assumes that the view controller has an `openedAppLinkURL` `NSURL` property that has already been populated with the URL used to open the app. You can then do something like this to show the view: + +```objective-c +- (void)viewWillAppear { + [super viewWillAppear]; + + // Show only if you have a back AppLink. + [self.returnToRefererController showViewForRefererURL:self.openedAppLinkURL]; +} +``` + +In a navigaton-controller view hierarchy, the banner should be displayed above the navigation bar, and `BFAppLinkReturnToRefererController` provides an `initForDisplayAboveNavController` method to assist with this. + +## Analytics + +Bolts introduces Measurement Event. App Links posts three different Measurement Event notifications to the application, which can be caught and integrated with existing analytics components in your application. + +* `al_nav_out` — Raised when your app switches out to an App Links URL. +* `al_nav_in` — Raised when your app opens an incoming App Links URL. +* `al_ref_back_out` — Raised when your app returns back the referrer app using the built-in top navigation back bar view. + +### Listen for App Links Measurement Events + +There are other analytics tools that are integrated with Bolts' App Links events, but you can also listen for these events yourself: + +```objective-c +[[NSNotificationCenter defaultCenter] addObserverForName:BFMeasurementEventNotificationName object:nil queue:nil usingBlock:^(NSNotification *note) { + NSDictionary *event = note.userInfo; + NSDictionary *eventData = event[BFMeasurementEventArgsKey]; + // Integrate to your logging/analytics component. +}]; +``` + +### App Links Event Fields + +App Links Measurement Events sends additional information from App Links Intents in flattened string key value pairs. Here are some of the useful fields for the three events. + +* `al_nav_in` + * `inputURL`: the URL that opens the app. + * `inputURLScheme`: the scheme of `inputURL`. + * `refererURL`: the URL that the referrer app added into `al_applink_data`: `referer_app_link`. + * `refererAppName`: the app name that the referrer app added to `al_applink_data`: `referer_app_link`. + * `sourceApplication`: the bundle of referrer application. + * `targetURL`: the `target_url` field in `al_applink_data`. + * `version`: App Links API version. + +* `al_nav_out` / `al_ref_back_out` + * `outputURL`: the URL used to open the other app (or browser). If there is an eligible app to open, this will be the custom scheme url/intent in `al_applink_data`. + * `outputURLScheme`: the scheme of `outputURL`. + * `sourceURL`: the URL of the page hosting App Links meta tags. + * `sourceURLHost`: the hostname of `sourceURL`. + * `success`: `“1”` to indicate success in opening the App Link in another app or browser; `“0”` to indicate failure to open the App Link. + * `type`: `“app”` for open in app, `“web”` for open in browser; `“fail”` when the success field is `“0”`. + * `version`: App Links API version. + +# Installation + +You can download the latest framework files from our [Releases page](https://github.com/BoltsFramework/Bolts-iOS/releases). + +Bolts is also available through [CocoaPods](http://cocoapods.org). To install it simply add the following line to your Podfile: + + pod 'Bolts' diff --git a/Pods/Headers/Private/Bolts/BFCancellationToken.h b/Pods/Headers/Private/Bolts/BFCancellationToken.h new file mode 120000 index 0000000..0b69486 --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFCancellationToken.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationToken.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h b/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h new file mode 120000 index 0000000..c587ca7 --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenRegistration.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h b/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h new file mode 120000 index 0000000..d3d5985 --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFCancellationTokenSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BFExecutor.h b/Pods/Headers/Private/Bolts/BFExecutor.h new file mode 120000 index 0000000..c071e8c --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFExecutor.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFExecutor.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BFTask.h b/Pods/Headers/Private/Bolts/BFTask.h new file mode 120000 index 0000000..5468334 --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFTask.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTask.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h b/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h new file mode 120000 index 0000000..c74760f --- /dev/null +++ b/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BFTaskCompletionSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/Bolts.h b/Pods/Headers/Private/Bolts/Bolts.h new file mode 120000 index 0000000..146ac6e --- /dev/null +++ b/Pods/Headers/Private/Bolts/Bolts.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/Bolts.h \ No newline at end of file diff --git a/Pods/Headers/Private/Bolts/BoltsVersion.h b/Pods/Headers/Private/Bolts/BoltsVersion.h new file mode 120000 index 0000000..0fa0e2d --- /dev/null +++ b/Pods/Headers/Private/Bolts/BoltsVersion.h @@ -0,0 +1 @@ +../../../Bolts/Bolts/Common/BoltsVersion.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFACL.h b/Pods/Headers/Private/Parse/PFACL.h new file mode 120000 index 0000000..105fb99 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFACL.h @@ -0,0 +1 @@ +../../../Parse/PFACL.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFAnalytics.h b/Pods/Headers/Private/Parse/PFAnalytics.h new file mode 120000 index 0000000..7619f13 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFAnalytics.h @@ -0,0 +1 @@ +../../../Parse/PFAnalytics.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFAnonymousUtils.h b/Pods/Headers/Private/Parse/PFAnonymousUtils.h new file mode 120000 index 0000000..95113c8 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFAnonymousUtils.h @@ -0,0 +1 @@ +../../../Parse/PFAnonymousUtils.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFCloud.h b/Pods/Headers/Private/Parse/PFCloud.h new file mode 120000 index 0000000..3eb6eb1 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFCloud.h @@ -0,0 +1 @@ +../../../Parse/PFCloud.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFConfig.h b/Pods/Headers/Private/Parse/PFConfig.h new file mode 120000 index 0000000..4a67069 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFConfig.h @@ -0,0 +1 @@ +../../../Parse/PFConfig.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFConstants.h b/Pods/Headers/Private/Parse/PFConstants.h new file mode 120000 index 0000000..709bfb3 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFConstants.h @@ -0,0 +1 @@ +../../../Parse/PFConstants.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFFile.h b/Pods/Headers/Private/Parse/PFFile.h new file mode 120000 index 0000000..0a4d575 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFFile.h @@ -0,0 +1 @@ +../../../Parse/PFFile.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFGeoPoint.h b/Pods/Headers/Private/Parse/PFGeoPoint.h new file mode 120000 index 0000000..e857843 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFGeoPoint.h @@ -0,0 +1 @@ +../../../Parse/PFGeoPoint.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFInstallation.h b/Pods/Headers/Private/Parse/PFInstallation.h new file mode 120000 index 0000000..3c23cc4 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFInstallation.h @@ -0,0 +1 @@ +../../../Parse/PFInstallation.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h b/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..9fadf46 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../Parse/PFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFNullability.h b/Pods/Headers/Private/Parse/PFNullability.h new file mode 120000 index 0000000..51688f0 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFNullability.h @@ -0,0 +1 @@ +../../../Parse/PFNullability.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFObject+Subclass.h b/Pods/Headers/Private/Parse/PFObject+Subclass.h new file mode 120000 index 0000000..97e0763 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFObject+Subclass.h @@ -0,0 +1 @@ +../../../Parse/PFObject+Subclass.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFObject.h b/Pods/Headers/Private/Parse/PFObject.h new file mode 120000 index 0000000..8f31704 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFObject.h @@ -0,0 +1 @@ +../../../Parse/PFObject.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFProduct.h b/Pods/Headers/Private/Parse/PFProduct.h new file mode 120000 index 0000000..ae4f7a8 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFProduct.h @@ -0,0 +1 @@ +../../../Parse/PFProduct.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFPurchase.h b/Pods/Headers/Private/Parse/PFPurchase.h new file mode 120000 index 0000000..b0e75ab --- /dev/null +++ b/Pods/Headers/Private/Parse/PFPurchase.h @@ -0,0 +1 @@ +../../../Parse/PFPurchase.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFPush.h b/Pods/Headers/Private/Parse/PFPush.h new file mode 120000 index 0000000..77373a0 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFPush.h @@ -0,0 +1 @@ +../../../Parse/PFPush.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFQuery.h b/Pods/Headers/Private/Parse/PFQuery.h new file mode 120000 index 0000000..42848d3 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFQuery.h @@ -0,0 +1 @@ +../../../Parse/PFQuery.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFRelation.h b/Pods/Headers/Private/Parse/PFRelation.h new file mode 120000 index 0000000..5dd6563 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFRelation.h @@ -0,0 +1 @@ +../../../Parse/PFRelation.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFRole.h b/Pods/Headers/Private/Parse/PFRole.h new file mode 120000 index 0000000..76f49d3 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFRole.h @@ -0,0 +1 @@ +../../../Parse/PFRole.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFSession.h b/Pods/Headers/Private/Parse/PFSession.h new file mode 120000 index 0000000..77ed683 --- /dev/null +++ b/Pods/Headers/Private/Parse/PFSession.h @@ -0,0 +1 @@ +../../../Parse/PFSession.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFSubclassing.h b/Pods/Headers/Private/Parse/PFSubclassing.h new file mode 120000 index 0000000..f88565c --- /dev/null +++ b/Pods/Headers/Private/Parse/PFSubclassing.h @@ -0,0 +1 @@ +../../../Parse/PFSubclassing.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFTwitterUtils.h b/Pods/Headers/Private/Parse/PFTwitterUtils.h new file mode 120000 index 0000000..0d76d9e --- /dev/null +++ b/Pods/Headers/Private/Parse/PFTwitterUtils.h @@ -0,0 +1 @@ +../../../Parse/PFTwitterUtils.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PFUser.h b/Pods/Headers/Private/Parse/PFUser.h new file mode 120000 index 0000000..6c1413a --- /dev/null +++ b/Pods/Headers/Private/Parse/PFUser.h @@ -0,0 +1 @@ +../../../Parse/PFUser.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/PF_Twitter.h b/Pods/Headers/Private/Parse/PF_Twitter.h new file mode 120000 index 0000000..64e2955 --- /dev/null +++ b/Pods/Headers/Private/Parse/PF_Twitter.h @@ -0,0 +1 @@ +../../../Parse/PF_Twitter.h \ No newline at end of file diff --git a/Pods/Headers/Private/Parse/Parse.h b/Pods/Headers/Private/Parse/Parse.h new file mode 120000 index 0000000..2adf7e0 --- /dev/null +++ b/Pods/Headers/Private/Parse/Parse.h @@ -0,0 +1 @@ +../../../Parse/Parse.h \ No newline at end of file diff --git a/Pods/Local Podspecs/Spring.podspec.json b/Pods/Local Podspecs/Spring.podspec.json new file mode 100644 index 0000000..51690ce --- /dev/null +++ b/Pods/Local Podspecs/Spring.podspec.json @@ -0,0 +1,23 @@ +{ + "name": "Spring", + "version": "1.0.3", + "license": "MIT", + "summary": "A library to simplify iOS animations in Swift.", + "homepage": "https://github.com/MengTo/Spring", + "authors": { + "Meng To": "meng@designcode.io" + }, + "source": { + "git": "https://github.com/MengTo/Spring.git", + "tag": "1.0.3" + }, + "requires_arc": true, + "platforms": { + "ios": "8.0" + }, + "source_files": "Spring/*.swift", + "resources": [ + "Spring/*.xib", + "SpringApp/*.xcassets" + ] +} diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..381bd7e --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,26 @@ +PODS: + - Bolts/Tasks (1.2.0) + - Parse (1.7.5.3): + - Bolts/Tasks (>= 1.2.0) + - Spring (1.0.3) + +DEPENDENCIES: + - Parse + - Spring (from `https://github.com/MengTo/Spring.git`, branch `swift2`) + +EXTERNAL SOURCES: + Spring: + :branch: swift2 + :git: https://github.com/MengTo/Spring.git + +CHECKOUT OPTIONS: + Spring: + :commit: 18d5c7b74489de8044e34767f856d1e574f0820e + :git: https://github.com/MengTo/Spring.git + +SPEC CHECKSUMS: + Bolts: d176cb1e0012175589e389a9db49b85e27787576 + Parse: 373adbb1ad2e34d383542c3b28f678c49ebe4881 + Spring: 3f02b5dc3308572ef177b3cad0fa7bbc4b0706f7 + +COCOAPODS: 0.39.0 diff --git a/Pods/Parse/Empty.m b/Pods/Parse/Empty.m new file mode 100644 index 0000000..e69de29 diff --git a/Pods/Parse/PFACL.h b/Pods/Parse/PFACL.h new file mode 100644 index 0000000..3582a1e --- /dev/null +++ b/Pods/Parse/PFACL.h @@ -0,0 +1,265 @@ +// +// PFACL.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class PFRole; +@class PFUser; + +/*! + The `PFACL` class is used to control which users can access or modify a particular object. + Each can have its own `PFACL`. You can grant read and write permissions separately to specific users, + to groups of users that belong to roles, or you can grant permissions to "the public" so that, + for example, any user could read a particular object but only a particular set of users could write to that object. + */ +@interface PFACL : NSObject + +///-------------------------------------- +/// @name Creating an ACL +///-------------------------------------- + +/*! + @abstract Creates an ACL with no permissions granted. + + @returns Returns a new `PFACL`. + */ ++ (PFACL *)ACL; + +/*! + @abstract Creates an ACL where only the provided user has access. + + @param user The user to assign access. + */ ++ (PFACL *)ACLWithUser:(PFUser *)user; + +///-------------------------------------- +/// @name Controlling Public Access +///-------------------------------------- + +/*! + @abstract Set whether the public is allowed to read this object. + + @param allowed Whether the public can read this object. + */ +- (void)setPublicReadAccess:(BOOL)allowed; + +/*! + @abstract Gets whether the public is allowed to read this object. + + @returns `YES` if the public read access is enabled, otherwise `NO`. + */ +- (BOOL)getPublicReadAccess; + +/*! + @abstract Set whether the public is allowed to write this object. + + @param allowed Whether the public can write this object. + */ +- (void)setPublicWriteAccess:(BOOL)allowed; + +/*! + @abstract Gets whether the public is allowed to write this object. + + @returns `YES` if the public write access is enabled, otherwise `NO`. + */ +- (BOOL)getPublicWriteAccess; + +///-------------------------------------- +/// @name Controlling Access Per-User +///-------------------------------------- + +/*! + @abstract Set whether the given user id is allowed to read this object. + + @param allowed Whether the given user can write this object. + @param userId The <[PFObject objectId]> of the user to assign access. + */ +- (void)setReadAccess:(BOOL)allowed forUserId:(NSString *)userId; + +/*! + @abstract Gets whether the given user id is *explicitly* allowed to read this object. + Even if this returns `NO`, the user may still be able to access it if returns `YES` + or if the user belongs to a role that has access. + + @param userId The <[PFObject objectId]> of the user for which to retrive access. + + @returns `YES` if the user with this `objectId` has *explicit* read access, otherwise `NO`. + */ +- (BOOL)getReadAccessForUserId:(NSString *)userId; + +/*! + @abstract Set whether the given user id is allowed to write this object. + + @param allowed Whether the given user can read this object. + @param userId The `objectId` of the user to assign access. + */ +- (void)setWriteAccess:(BOOL)allowed forUserId:(NSString *)userId; + +/*! + @abstract Gets whether the given user id is *explicitly* allowed to write this object. + Even if this returns NO, the user may still be able to write it if returns `YES` + or if the user belongs to a role that has access. + + @param userId The <[PFObject objectId]> of the user for which to retrive access. + + @returns `YES` if the user with this `objectId` has *explicit* write access, otherwise `NO`. + */ +- (BOOL)getWriteAccessForUserId:(NSString *)userId; + +/*! + @abstract Set whether the given user is allowed to read this object. + + @param allowed Whether the given user can read this object. + @param user The user to assign access. + */ +- (void)setReadAccess:(BOOL)allowed forUser:(PFUser *)user; + +/*! + @abstract Gets whether the given user is *explicitly* allowed to read this object. + Even if this returns `NO`, the user may still be able to access it if returns `YES` + or if the user belongs to a role that has access. + + @param user The user for which to retrive access. + + @returns `YES` if the user has *explicit* read access, otherwise `NO`. + */ +- (BOOL)getReadAccessForUser:(PFUser *)user; + +/*! + @abstract Set whether the given user is allowed to write this object. + + @param allowed Whether the given user can write this object. + @param user The user to assign access. + */ +- (void)setWriteAccess:(BOOL)allowed forUser:(PFUser *)user; + +/*! + @abstract Gets whether the given user is *explicitly* allowed to write this object. + Even if this returns `NO`, the user may still be able to write it if returns `YES` + or if the user belongs to a role that has access. + + @param user The user for which to retrive access. + + @returns `YES` if the user has *explicit* write access, otherwise `NO`. + */ +- (BOOL)getWriteAccessForUser:(PFUser *)user; + +///-------------------------------------- +/// @name Controlling Access Per-Role +///-------------------------------------- + +/*! + @abstract Get whether users belonging to the role with the given name are allowed to read this object. + Even if this returns `NO`, the role may still be able to read it if a parent role has read access. + + @param name The name of the role. + + @returns `YES` if the role has read access, otherwise `NO`. + */ +- (BOOL)getReadAccessForRoleWithName:(NSString *)name; + +/*! + @abstract Set whether users belonging to the role with the given name are allowed to read this object. + + @param allowed Whether the given role can read this object. + @param name The name of the role. + */ +- (void)setReadAccess:(BOOL)allowed forRoleWithName:(NSString *)name; + +/*! + @abstract Get whether users belonging to the role with the given name are allowed to write this object. + Even if this returns `NO`, the role may still be able to write it if a parent role has write access. + + @param name The name of the role. + + @returns `YES` if the role has read access, otherwise `NO`. + */ +- (BOOL)getWriteAccessForRoleWithName:(NSString *)name; + +/*! + @abstract Set whether users belonging to the role with the given name are allowed to write this object. + + @param allowed Whether the given role can write this object. + @param name The name of the role. + */ +- (void)setWriteAccess:(BOOL)allowed forRoleWithName:(NSString *)name; + +/*! + @abstract Get whether users belonging to the given role are allowed to read this object. + Even if this returns `NO`, the role may still be able to read it if a parent role has read access. + + @discussion The role must already be saved on the server and + it's data must have been fetched in order to use this method. + + @param role The name of the role. + + @returns `YES` if the role has read access, otherwise `NO`. + */ +- (BOOL)getReadAccessForRole:(PFRole *)role; + +/*! + @abstract Set whether users belonging to the given role are allowed to read this object. + + @discussion The role must already be saved on the server and + it's data must have been fetched in order to use this method. + + @param allowed Whether the given role can read this object. + @param role The role to assign access. + */ +- (void)setReadAccess:(BOOL)allowed forRole:(PFRole *)role; + +/*! + @abstract Get whether users belonging to the given role are allowed to write this object. + Even if this returns `NO`, the role may still be able to write it if a parent role has write access. + + @discussion The role must already be saved on the server and + it's data must have been fetched in order to use this method. + + @param role The name of the role. + + @returns `YES` if the role has write access, otherwise `NO`. + */ +- (BOOL)getWriteAccessForRole:(PFRole *)role; + +/*! + @abstract Set whether users belonging to the given role are allowed to write this object. + + @discussion The role must already be saved on the server and + it's data must have been fetched in order to use this method. + + @param allowed Whether the given role can write this object. + @param role The role to assign access. + */ +- (void)setWriteAccess:(BOOL)allowed forRole:(PFRole *)role; + +///-------------------------------------- +/// @name Setting Access Defaults +///-------------------------------------- + +/*! + @abstract Sets a default ACL that will be applied to all instances of when they are created. + + @param acl The ACL to use as a template for all instance of created after this method has been called. + This value will be copied and used as a template for the creation of new ACLs, so changes to the + instance after this method has been called will not be reflected in new instance of . + @param currentUserAccess - If `YES`, the `PFACL` that is applied to newly-created instance of will + provide read and write access to the <[PFUser currentUser]> at the time of creation. + - If `NO`, the provided `acl` will be used without modification. + - If `acl` is `nil`, this value is ignored. + */ ++ (void)setDefaultACL:(PF_NULLABLE PFACL *)acl withAccessForCurrentUser:(BOOL)currentUserAccess; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFAnalytics.h b/Pods/Parse/PFAnalytics.h new file mode 100644 index 0000000..a883453 --- /dev/null +++ b/Pods/Parse/PFAnalytics.h @@ -0,0 +1,167 @@ +// +// PFAnalytics.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + `PFAnalytics` provides an interface to Parse's logging and analytics backend. + + Methods will return immediately and cache the request (+ timestamp) to be + handled "eventually." That is, the request will be sent immediately if possible + or the next time a network connection is available. + */ +@interface PFAnalytics : NSObject + +///-------------------------------------- +/// @name App-Open / Push Analytics +///-------------------------------------- + +/*! + @abstract Tracks this application being launched. If this happened as the result of the + user opening a push notification, this method sends along information to + correlate this open with that push. + + @discussion Pass in `nil` to track a standard "application opened" event. + + @param launchOptions The `NSDictionary` indicating the reason the application was + launched, if any. This value can be found as a parameter to various + `UIApplicationDelegate` methods, and can be empty or `nil`. + + @returns Returns the task encapsulating the work being done. + */ ++ (BFTask *)trackAppOpenedWithLaunchOptions:(PF_NULLABLE NSDictionary *)launchOptions; + +/*! + @abstract Tracks this application being launched. + If this happened as the result of the user opening a push notification, + this method sends along information to correlate this open with that push. + + @discussion Pass in `nil` to track a standard "application opened" event. + + @param launchOptions The dictionary indicating the reason the application was + launched, if any. This value can be found as a parameter to various + `UIApplicationDelegate` methods, and can be empty or `nil`. + @param block The block to execute on server response. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)trackAppOpenedWithLaunchOptionsInBackground:(PF_NULLABLE NSDictionary *)launchOptions + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract Tracks this application being launched. If this happened as the result of the + user opening a push notification, this method sends along information to + correlate this open with that push. + + @param userInfo The Remote Notification payload, if any. This value can be + found either under `UIApplicationLaunchOptionsRemoteNotificationKey` on `launchOptions`, + or as a parameter to `application:didReceiveRemoteNotification:`. + This can be empty or `nil`. + + @returns Returns the task encapsulating the work being done. + */ ++ (BFTask *)trackAppOpenedWithRemoteNotificationPayload:(PF_NULLABLE NSDictionary *)userInfo; + +/*! + @abstract Tracks this application being launched. If this happened as the result of the + user opening a push notification, this method sends along information to + correlate this open with that push. + + @param userInfo The Remote Notification payload, if any. This value can be + found either under `UIApplicationLaunchOptionsRemoteNotificationKey` on `launchOptions`, + or as a parameter to `application:didReceiveRemoteNotification:`. This can be empty or `nil`. + @param block The block to execute on server response. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)trackAppOpenedWithRemoteNotificationPayloadInBackground:(PF_NULLABLE NSDictionary *)userInfo + block:(PF_NULLABLE PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Custom Analytics +///-------------------------------------- + +/*! + @abstract Tracks the occurrence of a custom event. + + @discussion Parse will store a data point at the time of invocation with the given event name. + + @param name The name of the custom event to report to Parse as having happened. + + @returns Returns the task encapsulating the work being done. + */ ++ (BFTask *)trackEvent:(NSString *)name; + +/*! + @abstract Tracks the occurrence of a custom event. Parse will store a data point at the + time of invocation with the given event name. The event will be sent at some + unspecified time in the future, even if Parse is currently inaccessible. + + @param name The name of the custom event to report to Parse as having happened. + @param block The block to execute on server response. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)trackEventInBackground:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract Tracks the occurrence of a custom event with additional dimensions. Parse will + store a data point at the time of invocation with the given event name. + + @discussion Dimensions will allow segmentation of the occurrences of this custom event. + Keys and values should be NSStrings, and will throw otherwise. + + To track a user signup along with additional metadata, consider the following: + + NSDictionary *dimensions = @{ @"gender": @"m", + @"source": @"web", + @"dayType": @"weekend" }; + [PFAnalytics trackEvent:@"signup" dimensions:dimensions]; + + @warning There is a default limit of 8 dimensions per event tracked. + + @param name The name of the custom event to report to Parse as having happened. + @param dimensions The `NSDictionary` of information by which to segment this event. + + @returns Returns the task encapsulating the work being done. + */ ++ (BFTask *)trackEvent:(NSString *)name dimensions:(PF_NULLABLE NSDictionary *)dimensions; + +/*! + @abstract Tracks the occurrence of a custom event with additional dimensions. Parse will + store a data point at the time of invocation with the given event name. The + event will be sent at some unspecified time in the future, even if Parse is currently inaccessible. + + @discussionDimensions will allow segmentation of the occurrences of this custom event. + Keys and values should be NSStrings, and will throw otherwise. + + To track a user signup along with additional metadata, consider the following: + NSDictionary *dimensions = @{ @"gender": @"m", + @"source": @"web", + @"dayType": @"weekend" }; + [PFAnalytics trackEvent:@"signup" dimensions:dimensions]; + + There is a default limit of 8 dimensions per event tracked. + + @param name The name of the custom event to report to Parse as having happened. + @param dimensions The `NSDictionary` of information by which to segment this event. + @param block The block to execute on server response. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)trackEventInBackground:(NSString *)name + dimensions:(PF_NULLABLE NSDictionary *)dimensions + block:(PF_NULLABLE PFBooleanResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFAnonymousUtils.h b/Pods/Parse/PFAnonymousUtils.h new file mode 100644 index 0000000..7a55591 --- /dev/null +++ b/Pods/Parse/PFAnonymousUtils.h @@ -0,0 +1,82 @@ +// +// PFAnonymousUtils.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#else +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + Provides utility functions for working with Anonymously logged-in users. + Anonymous users have some unique characteristics: + + - Anonymous users don't need a user name or password. + - Once logged out, an anonymous user cannot be recovered. + - When the current user is anonymous, the following methods can be used to switch + to a different user or convert the anonymous user into a regular one: + - signUp converts an anonymous user to a standard user with the given username and password. + Data associated with the anonymous user is retained. + - logIn switches users without converting the anonymous user. + Data associated with the anonymous user will be lost. + - Service logIn (e.g. Facebook, Twitter) will attempt to convert + the anonymous user into a standard user by linking it to the service. + If a user already exists that is linked to the service, it will instead switch to the existing user. + - Service linking (e.g. Facebook, Twitter) will convert the anonymous user + into a standard user by linking it to the service. + */ +@interface PFAnonymousUtils : NSObject + +///-------------------------------------- +/// @name Creating an Anonymous User +///-------------------------------------- + +/*! + @abstract Creates an anonymous user asynchronously and sets as a result to `BFTask`. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)logInInBackground; + +/*! + @abstract Creates an anonymous user. + + @param block The block to execute when anonymous user creation is complete. + It should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)logInWithBlock:(PF_NULLABLE PFUserResultBlock)block; + +/* + @abstract Creates an anonymous user. + + @param target Target object for the selector. + @param selector The selector that will be called when the asynchronous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)logInWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Determining Whether a User is Anonymous +///-------------------------------------- + +/*! + @abstract Whether the object is logged in anonymously. + + @param user object to check for anonymity. The user must be logged in on this device. + + @returns `YES` if the user is anonymous. `NO` if the user is not the current user or is not anonymous. + */ ++ (BOOL)isLinkedWithUser:(PF_NULLABLE PFUser *)user; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFCloud.h b/Pods/Parse/PFCloud.h new file mode 100644 index 0000000..f141ade --- /dev/null +++ b/Pods/Parse/PFCloud.h @@ -0,0 +1,91 @@ +// +// PFCloud.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + The `PFCloud` class provides methods for interacting with Parse Cloud Functions. + */ +@interface PFCloud : NSObject + +/*! + @abstract Calls the given cloud function *synchronously* with the parameters provided. + + @param function The function name to call. + @param parameters The parameters to send to the function. + + @returns The response from the cloud function. + */ ++ (PF_NULLABLE_S id)callFunction:(NSString *)function withParameters:(PF_NULLABLE NSDictionary *)parameters; + +/*! + @abstract Calls the given cloud function *synchronously* with the parameters provided and + sets the error if there is one. + + @param function The function name to call. + @param parameters The parameters to send to the function. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The response from the cloud function. + This result could be a `NSDictionary`, an `NSArray`, `NSNumber` or `NSString`. + */ ++ (PF_NULLABLE_S id)callFunction:(NSString *)function + withParameters:(PF_NULLABLE NSDictionary *)parameters + error:(NSError **)error; + +/*! + @abstract Calls the given cloud function *asynchronously* with the parameters provided. + + @param function The function name to call. + @param parameters The parameters to send to the function. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)callFunctionInBackground:(NSString *)function + withParameters:(PF_NULLABLE NSDictionary *)parameters; + +/*! + @abstract Calls the given cloud function *asynchronously* with the parameters provided + and executes the given block when it is done. + + @param function The function name to call. + @param parameters The parameters to send to the function. + @param block The block to execute when the function call finished. + It should have the following argument signature: `^(id result, NSError *error)`. + */ ++ (void)callFunctionInBackground:(NSString *)function + withParameters:(PF_NULLABLE NSDictionary *)parameters + block:(PF_NULLABLE PFIdResultBlock)block; + +/* + @abstract Calls the given cloud function *asynchronously* with the parameters provided + and then executes the given selector when it is done. + + @param function The function name to call. + @param parameters The parameters to send to the function. + @param target The object to call the selector on. + @param selector The selector to call when the function call finished. + It should have the following signature: `(void)callbackWithResult:(id)result error:(NSError *)error`. + Result will be `nil` if error is set and vice versa. + */ ++ (void)callFunctionInBackground:(NSString *)function + withParameters:(PF_NULLABLE NSDictionary *)parameters + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFConfig.h b/Pods/Parse/PFConfig.h new file mode 100644 index 0000000..5eff195 --- /dev/null +++ b/Pods/Parse/PFConfig.h @@ -0,0 +1,105 @@ +// +// PFConfig.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; +@class PFConfig; + +typedef void(^PFConfigResultBlock)(PFConfig *PF_NULLABLE_S config, NSError *PF_NULLABLE_S error); + +/*! + `PFConfig` is a representation of the remote configuration object. + It enables you to add things like feature gating, a/b testing or simple "Message of the day". + */ +@interface PFConfig : NSObject + +///-------------------------------------- +/// @name Current Config +///-------------------------------------- + +/*! + @abstract Returns the most recently fetched config. + + @discussion If there was no config fetched - this method will return an empty instance of `PFConfig`. + + @returns Current, last fetched instance of PFConfig. + */ ++ (PFConfig *)currentConfig; + +///-------------------------------------- +/// @name Retrieving Config +///-------------------------------------- + +/*! + @abstract Gets the `PFConfig` object *synchronously* from the server. + + @returns Instance of `PFConfig` if the operation succeeded, otherwise `nil`. + */ ++ (PF_NULLABLE PFConfig *)getConfig; + +/*! + @abstract Gets the `PFConfig` object *synchronously* from the server and sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Instance of PFConfig if the operation succeeded, otherwise `nil`. + */ ++ (PF_NULLABLE PFConfig *)getConfig:(NSError **)error; + +/*! + @abstract Gets the `PFConfig` *asynchronously* and sets it as a result of a task. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)getConfigInBackground; + +/*! + @abstract Gets the `PFConfig` *asynchronously* and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(PFConfig *config, NSError *error)`. + */ ++ (void)getConfigInBackgroundWithBlock:(PF_NULLABLE PFConfigResultBlock)block; + +///-------------------------------------- +/// @name Parameters +///-------------------------------------- + +/*! + @abstract Returns the object associated with a given key. + + @param key The key for which to return the corresponding configuration value. + + @returns The value associated with `key`, or `nil` if there is no such value. + */ +- (PF_NULLABLE_S id)objectForKey:(NSString *)key; + +/*! + @abstract Returns the object associated with a given key. + + @discussion This method enables usage of literal syntax on `PFConfig`. + E.g. `NSString *value = config[@"key"];` + + @see objectForKey: + + @param keyedSubscript The keyed subscript for which to return the corresponding configuration value. + + @returns The value associated with `key`, or `nil` if there is no such value. + */ +- (PF_NULLABLE_S id)objectForKeyedSubscript:(NSString *)keyedSubscript; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFConstants.h b/Pods/Parse/PFConstants.h new file mode 100644 index 0000000..eaac836 --- /dev/null +++ b/Pods/Parse/PFConstants.h @@ -0,0 +1,423 @@ +// PFConstants.h +// Copyright 2011 Parse, Inc. All rights reserved. + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +@class PFObject; +@class PFUser; + +///-------------------------------------- +/// @name Version +///-------------------------------------- + +#define PARSE_VERSION @"1.7.5" + +extern NSInteger const PARSE_API_VERSION; + +///-------------------------------------- +/// @name Platform +///-------------------------------------- + +#define PARSE_IOS_ONLY (TARGET_OS_IPHONE) +#define PARSE_OSX_ONLY (TARGET_OS_MAC && !(TARGET_OS_IPHONE)) + +extern NSString *const PF_NONNULL_S kPFDeviceType; + +#if PARSE_IOS_ONLY +#import +#else +#import +@compatibility_alias UIImage NSImage; +@compatibility_alias UIColor NSColor; +@compatibility_alias UIView NSView; +#endif + +///-------------------------------------- +/// @name Server +///-------------------------------------- + +extern NSString *const PF_NONNULL_S kPFParseServer; + +///-------------------------------------- +/// @name Cache Policies +///-------------------------------------- + +/*! + `PFCachePolicy` specifies different caching policies that could be used with . + + This lets you show data when the user's device is offline, + or when the app has just started and network requests have not yet had time to complete. + Parse takes care of automatically flushing the cache when it takes up too much space. + + @warning Cache policy could only be set when Local Datastore is not enabled. + + @see PFQuery + */ +typedef NS_ENUM(uint8_t, PFCachePolicy) { + /*! + @abstract The query does not load from the cache or save results to the cache. + This is the default cache policy. + */ + kPFCachePolicyIgnoreCache = 0, + /*! + @abstract The query only loads from the cache, ignoring the network. + If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code. + */ + kPFCachePolicyCacheOnly, + /*! + @abstract The query does not load from the cache, but it will save results to the cache. + */ + kPFCachePolicyNetworkOnly, + /*! + @abstract The query first tries to load from the cache, but if that fails, it loads results from the network. + If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code. + */ + kPFCachePolicyCacheElseNetwork, + /*! + @abstract The query first tries to load from the network, but if that fails, it loads results from the cache. + If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code. + */ + kPFCachePolicyNetworkElseCache, + /*! + @abstract The query first loads from the cache, then loads from the network. + The callback will be called twice - first with the cached results, then with the network results. + Since it returns two results at different times, this cache policy cannot be used with synchronous or task methods. + */ + kPFCachePolicyCacheThenNetwork +}; + +///-------------------------------------- +/// @name Logging Levels +///-------------------------------------- + +/*! + `PFLogLevel` enum specifies different levels of logging that could be used to limit or display more messages in logs. + + @see [Parse setLogLevel:] + @see [Parse logLevel] + */ +typedef NS_ENUM(uint8_t, PFLogLevel) { + /*! + Log level that disables all logging. + */ + PFLogLevelNone = 0, + /*! + Log level that if set is going to output error messages to the log. + */ + PFLogLevelError = 1, + /*! + Log level that if set is going to output the following messages to log: + - Errors + - Warnings + */ + PFLogLevelWarning = 2, + /*! + Log level that if set is going to output the following messages to log: + - Errors + - Warnings + - Informational messages + */ + PFLogLevelInfo = 3, + /*! + Log level that if set is going to output the following messages to log: + - Errors + - Warnings + - Informational messages + - Debug messages + */ + PFLogLevelDebug = 4 +}; + +///-------------------------------------- +/// @name Errors +///-------------------------------------- + +extern NSString *const PF_NONNULL_S PFParseErrorDomain; + +/*! + `PFErrorCode` enum contains all custom error codes that are used as `code` for `NSError` for callbacks on all classes. + + These codes are used when `domain` of `NSError` that you receive is set to `PFParseErrorDomain`. + */ +typedef NS_ENUM(NSInteger, PFErrorCode) { + /*! + @abstract Internal server error. No information available. + */ + kPFErrorInternalServer = 1, + /*! + @abstract The connection to the Parse servers failed. + */ + kPFErrorConnectionFailed = 100, + /*! + @abstract Object doesn't exist, or has an incorrect password. + */ + kPFErrorObjectNotFound = 101, + /*! + @abstract You tried to find values matching a datatype that doesn't + support exact database matching, like an array or a dictionary. + */ + kPFErrorInvalidQuery = 102, + /*! + @abstract Missing or invalid classname. Classnames are case-sensitive. + They must start with a letter, and `a-zA-Z0-9_` are the only valid characters. + */ + kPFErrorInvalidClassName = 103, + /*! + @abstract Missing object id. + */ + kPFErrorMissingObjectId = 104, + /*! + @abstract Invalid key name. Keys are case-sensitive. + They must start with a letter, and `a-zA-Z0-9_` are the only valid characters. + */ + kPFErrorInvalidKeyName = 105, + /*! + @abstract Malformed pointer. Pointers must be arrays of a classname and an object id. + */ + kPFErrorInvalidPointer = 106, + /*! + @abstract Malformed json object. A json dictionary is expected. + */ + kPFErrorInvalidJSON = 107, + /*! + @abstract Tried to access a feature only available internally. + */ + kPFErrorCommandUnavailable = 108, + /*! + @abstract Field set to incorrect type. + */ + kPFErrorIncorrectType = 111, + /*! + @abstract Invalid channel name. A channel name is either an empty string (the broadcast channel) + or contains only `a-zA-Z0-9_` characters and starts with a letter. + */ + kPFErrorInvalidChannelName = 112, + /*! + @abstract Invalid device token. + */ + kPFErrorInvalidDeviceToken = 114, + /*! + @abstract Push is misconfigured. See details to find out how. + */ + kPFErrorPushMisconfigured = 115, + /*! + @abstract The object is too large. + */ + kPFErrorObjectTooLarge = 116, + /*! + @abstract That operation isn't allowed for clients. + */ + kPFErrorOperationForbidden = 119, + /*! + @abstract The results were not found in the cache. + */ + kPFErrorCacheMiss = 120, + /*! + @abstract Keys in `NSDictionary` values may not include `$` or `.`. + */ + kPFErrorInvalidNestedKey = 121, + /*! + @abstract Invalid file name. + A file name can contain only `a-zA-Z0-9_.` characters and should be between 1 and 36 characters. + */ + kPFErrorInvalidFileName = 122, + /*! + @abstract Invalid ACL. An ACL with an invalid format was saved. This should not happen if you use . + */ + kPFErrorInvalidACL = 123, + /*! + @abstract The request timed out on the server. Typically this indicates the request is too expensive. + */ + kPFErrorTimeout = 124, + /*! + @abstract The email address was invalid. + */ + kPFErrorInvalidEmailAddress = 125, + /*! + A unique field was given a value that is already taken. + */ + kPFErrorDuplicateValue = 137, + /*! + @abstract Role's name is invalid. + */ + kPFErrorInvalidRoleName = 139, + /*! + @abstract Exceeded an application quota. Upgrade to resolve. + */ + kPFErrorExceededQuota = 140, + /*! + @abstract Cloud Code script had an error. + */ + kPFScriptError = 141, + /*! + @abstract Cloud Code validation failed. + */ + kPFValidationError = 142, + /*! + @abstract Product purchase receipt is missing. + */ + kPFErrorReceiptMissing = 143, + /*! + @abstract Product purchase receipt is invalid. + */ + kPFErrorInvalidPurchaseReceipt = 144, + /*! + @abstract Payment is disabled on this device. + */ + kPFErrorPaymentDisabled = 145, + /*! + @abstract The product identifier is invalid. + */ + kPFErrorInvalidProductIdentifier = 146, + /*! + @abstract The product is not found in the App Store. + */ + kPFErrorProductNotFoundInAppStore = 147, + /*! + @abstract The Apple server response is not valid. + */ + kPFErrorInvalidServerResponse = 148, + /*! + @abstract Product fails to download due to file system error. + */ + kPFErrorProductDownloadFileSystemFailure = 149, + /*! + @abstract Fail to convert data to image. + */ + kPFErrorInvalidImageData = 150, + /*! + @abstract Unsaved file. + */ + kPFErrorUnsavedFile = 151, + /*! + @abstract Fail to delete file. + */ + kPFErrorFileDeleteFailure = 153, + /*! + @abstract Application has exceeded its request limit. + */ + kPFErrorRequestLimitExceeded = 155, + /*! + @abstract Invalid event name. + */ + kPFErrorInvalidEventName = 160, + /*! + @abstract Username is missing or empty. + */ + kPFErrorUsernameMissing = 200, + /*! + @abstract Password is missing or empty. + */ + kPFErrorUserPasswordMissing = 201, + /*! + @abstract Username has already been taken. + */ + kPFErrorUsernameTaken = 202, + /*! + @abstract Email has already been taken. + */ + kPFErrorUserEmailTaken = 203, + /*! + @abstract The email is missing, and must be specified. + */ + kPFErrorUserEmailMissing = 204, + /*! + @abstract A user with the specified email was not found. + */ + kPFErrorUserWithEmailNotFound = 205, + /*! + @abstract The user cannot be altered by a client without the session. + */ + kPFErrorUserCannotBeAlteredWithoutSession = 206, + /*! + @abstract Users can only be created through sign up. + */ + kPFErrorUserCanOnlyBeCreatedThroughSignUp = 207, + /*! + @abstract An existing Facebook account already linked to another user. + */ + kPFErrorFacebookAccountAlreadyLinked = 208, + /*! + @abstract An existing account already linked to another user. + */ + kPFErrorAccountAlreadyLinked = 208, + /*! + Error code indicating that the current session token is invalid. + */ + kPFErrorInvalidSessionToken = 209, + kPFErrorUserIdMismatch = 209, + /*! + @abstract Facebook id missing from request. + */ + kPFErrorFacebookIdMissing = 250, + /*! + @abstract Linked id missing from request. + */ + kPFErrorLinkedIdMissing = 250, + /*! + @abstract Invalid Facebook session. + */ + kPFErrorFacebookInvalidSession = 251, + /*! + @abstract Invalid linked session. + */ + kPFErrorInvalidLinkedSession = 251, +}; + +///-------------------------------------- +/// @name Blocks +///-------------------------------------- + +typedef void (^PFBooleanResultBlock)(BOOL succeeded, NSError *PF_NULLABLE_S error); +typedef void (^PFIntegerResultBlock)(int number, NSError *PF_NULLABLE_S error); +typedef void (^PFArrayResultBlock)(NSArray *PF_NULLABLE_S objects, NSError *PF_NULLABLE_S error); +typedef void (^PFObjectResultBlock)(PFObject *PF_NULLABLE_S object, NSError *PF_NULLABLE_S error); +typedef void (^PFSetResultBlock)(NSSet *PF_NULLABLE_S channels, NSError *PF_NULLABLE_S error); +typedef void (^PFUserResultBlock)(PFUser *PF_NULLABLE_S user, NSError *PF_NULLABLE_S error); +typedef void (^PFDataResultBlock)(NSData *PF_NULLABLE_S data, NSError *PF_NULLABLE_S error); +typedef void (^PFDataStreamResultBlock)(NSInputStream *PF_NULLABLE_S stream, NSError *PF_NULLABLE_S error); +typedef void (^PFStringResultBlock)(NSString *PF_NULLABLE_S string, NSError *PF_NULLABLE_S error); +typedef void (^PFIdResultBlock)(PF_NULLABLE_S id object, NSError *PF_NULLABLE_S error); +typedef void (^PFProgressBlock)(int percentDone); + +///-------------------------------------- +/// @name Deprecated Macros +///-------------------------------------- + +#ifndef PARSE_DEPRECATED +# ifdef __deprecated_msg +# define PARSE_DEPRECATED(_MSG) __deprecated_msg(_MSG) +# else +# ifdef __deprecated +# define PARSE_DEPRECATED(_MSG) __attribute__((deprecated)) +# else +# define PARSE_DEPRECATED(_MSG) +# endif +# endif +#endif + +///-------------------------------------- +/// @name Extensions Macros +///-------------------------------------- + +#ifndef PF_EXTENSION_UNAVAILABLE +# if PARSE_IOS_ONLY +# ifdef NS_EXTENSION_UNAVAILABLE_IOS +# define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_IOS(_msg) +# else +# define PF_EXTENSION_UNAVAILABLE(_msg) +# endif +# else +# ifdef NS_EXTENSION_UNAVAILABLE_MAC +# define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_MAC(_msg) +# else +# define PF_EXTENSION_UNAVAILABLE(_msg) +# endif +# endif +#endif diff --git a/Pods/Parse/PFFile.h b/Pods/Parse/PFFile.h new file mode 100644 index 0000000..b78e0cb --- /dev/null +++ b/Pods/Parse/PFFile.h @@ -0,0 +1,389 @@ +// +// PFFile.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + `PFFile` representes a file of binary data stored on the Parse servers. + This can be a image, video, or anything else that an application needs to reference in a non-relational way. + */ +@interface PFFile : NSObject + +///-------------------------------------- +/// @name Creating a PFFile +///-------------------------------------- + +/*! + @abstract Creates a file with given data. A name will be assigned to it by the server. + + @param data The contents of the new `PFFile`. + + @returns A new `PFFile`. + */ ++ (instancetype)fileWithData:(NSData *)data; + +/*! + @abstract Creates a file with given data and name. + + @param name The name of the new PFFile. The file name must begin with and + alphanumeric character, and consist of alphanumeric characters, periods, + spaces, underscores, or dashes. + @param data The contents of the new `PFFile`. + + @returns A new `PFFile` object. + */ ++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name data:(NSData *)data; + +/*! + @abstract Creates a file with the contents of another file. + + @warning This method raises an exception if the file at path is not accessible + or if there is not enough disk space left. + + @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character, + and consist of alphanumeric characters, periods, spaces, underscores, or dashes. + @param path The path to the file that will be uploaded to Parse. + + @returns A new `PFFile` instance. + */ ++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name contentsAtPath:(NSString *)path; + +/*! + @abstract Creates a file with the contents of another file. + + @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character, + and consist of alphanumeric characters, periods, spaces, underscores, or dashes. + @param path The path to the file that will be uploaded to Parse. + @param error On input, a pointer to an error object. + If an error occurs, this pointer is set to an actual error object containing the error information. + You may specify `nil` for this parameter if you do not want the error information. + + @returns A new `PFFile` instance or `nil` if the error occured. + */ ++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name contentsAtPath:(NSString *)path error:(NSError **)error; + +/*! + @abstract Creates a file with given data, name and content type. + + @warning This method raises an exception if the data supplied is not accessible or could not be saved. + + @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character, + and consist of alphanumeric characters, periods, spaces, underscores, or dashes. + @param data The contents of the new `PFFile`. + @param contentType Represents MIME type of the data. + + @returns A new `PFFile` instance. + */ ++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name + data:(NSData *)data + contentType:(PF_NULLABLE NSString *)contentType; + +/*! + @abstract Creates a file with given data, name and content type. + + @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character, + and consist of alphanumeric characters, periods, spaces, underscores, or dashes. + @param data The contents of the new `PFFile`. + @param contentType Represents MIME type of the data. + @param error On input, a pointer to an error object. + If an error occurs, this pointer is set to an actual error object containing the error information. + You may specify `nil` for this parameter if you do not want the error information. + + @returns A new `PFFile` instance or `nil` if the error occured. + */ ++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name + data:(NSData *)data + contentType:(PF_NULLABLE NSString *)contentType + error:(NSError **)error; + +/*! + @abstract Creates a file with given data and content type. + + @param data The contents of the new `PFFile`. + @param contentType Represents MIME type of the data. + + @returns A new `PFFile` object. + */ ++ (instancetype)fileWithData:(NSData *)data contentType:(PF_NULLABLE NSString *)contentType; + +/*! + @abstract The name of the file. + + @discussion Before the file is saved, this is the filename given by + the user. After the file is saved, that name gets prefixed with a unique + identifier. + */ +@property (nonatomic, copy, readonly) NSString *name; + +/*! + @abstract The url of the file. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *url; + +///-------------------------------------- +/// @name Storing Data with Parse +///-------------------------------------- + +/*! + @abstract Whether the file has been uploaded for the first time. + */ +@property (nonatomic, assign, readonly) BOOL isDirty; + +/*! + @abstract Saves the file *synchronously*. + + @returns Returns whether the save succeeded. + */ +- (BOOL)save; + +/*! + @abstract Saves the file *synchronously* and sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the save succeeded. + */ +- (BOOL)save:(NSError **)error; + +/*! + @abstract Saves the file *asynchronously*. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)saveInBackground; + +/*! + @abstract Saves the file *asynchronously* + + @param progressBlock The block should have the following argument signature: `^(int percentDone)` + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)saveInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract Saves the file *asynchronously* and executes the given block. + + @param block The block should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract Saves the file *asynchronously* and executes the given block. + + @discussion This method will execute the progressBlock periodically with the percent progress. + `progressBlock` will get called with `100` before `resultBlock` is called. + + @param block The block should have the following argument signature: `^(BOOL succeeded, NSError *error)` + @param progressBlock The block should have the following argument signature: `^(int percentDone)` + */ +- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block + progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/* + @abstract Saves the file *asynchronously* and calls the given callback. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ +- (void)saveInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting Data from Parse +///-------------------------------------- + +/*! + @abstract Whether the data is available in memory or needs to be downloaded. + */ +@property (assign, readonly) BOOL isDataAvailable; + +/*! + @abstract *Synchronously* gets the data from cache if available or fetches its contents from the network. + + @returns The `NSData` object containing file data. Returns `nil` if there was an error in fetching. + */ +- (PF_NULLABLE NSData *)getData; + +/*! + @abstract This method is like but avoids ever holding the entire `PFFile` contents in memory at once. + + @discussion This can help applications with many large files avoid memory warnings. + + @returns A stream containing the data. Returns `nil` if there was an error in fetching. + */ +- (PF_NULLABLE NSInputStream *)getDataStream; + +/*! + @abstract *Synchronously* gets the data from cache if available or fetches its contents from the network. + Sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The `NSData` object containing file data. Returns `nil` if there was an error in fetching. + */ +- (PF_NULLABLE NSData *)getData:(NSError **)error; + +/*! + @abstract This method is like but avoids ever holding the entire `PFFile` contents in memory at once. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns A stream containing the data. Returns nil if there was an error in + fetching. + */ +- (PF_NULLABLE NSInputStream *)getDataStream:(NSError **)error; + +/*! + @abstract This method is like but it fetches asynchronously to avoid blocking the current thread. + + @see getData + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getDataInBackground; + +/*! + @abstract This method is like but it fetches asynchronously to avoid blocking the current thread. + + @discussion This can help applications with many large files avoid memory warnings. + + @see getData + + @param progressBlock The block should have the following argument signature: ^(int percentDone) + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getDataInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract This method is like but avoids + ever holding the entire `PFFile` contents in memory at once. + + @discussion This can help applications with many large files avoid memory warnings. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getDataStreamInBackground; + +/*! + @abstract This method is like , but yields a live-updating stream. + + @discussion Instead of , which yields a stream that can be read from only after the request has + completed, this method gives you a stream directly written to by the HTTP session. As this stream is not pre-buffered, + it is strongly advised to use the `NSStreamDelegate` methods, in combination with a run loop, to consume the data in + the stream, to do proper async file downloading. + + @note You MUST open this stream before reading from it. + @note Do NOT call on this task from the main thread. It may result in a deadlock. + + @returns A task that produces a *live* stream that is being written to with the data from the server. + */ +- (BFTask *)getDataDownloadStreamInBackground; + +/*! + @abstract This method is like but avoids + ever holding the entire `PFFile` contents in memory at once. + + @discussion This can help applications with many large files avoid memory warnings. + @param progressBlock The block should have the following argument signature: ^(int percentDone) + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getDataStreamInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract This method is like , but yields a live-updating stream. + + @discussion Instead of , which yields a stream that can be read from only after the request has + completed, this method gives you a stream directly written to by the HTTP session. As this stream is not pre-buffered, + it is strongly advised to use the `NSStreamDelegate` methods, in combination with a run loop, to consume the data in + the stream, to do proper async file downloading. + + @note You MUST open this stream before reading from it. + @note Do NOT call on this task from the main thread. It may result in a deadlock. + + @param progressBlock The block should have the following argument signature: `^(int percentDone)` + + @returns A task that produces a *live* stream that is being written to with the data from the server. + */ +- (BFTask *)getDataDownloadStreamInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network. + + @param block The block should have the following argument signature: `^(NSData *result, NSError *error)` + */ +- (void)getDataInBackgroundWithBlock:(PF_NULLABLE PFDataResultBlock)block; + +/*! + @abstract This method is like but avoids + ever holding the entire `PFFile` contents in memory at once. + + @discussion This can help applications with many large files avoid memory warnings. + + @param block The block should have the following argument signature: `(NSInputStream *result, NSError *error)` + */ +- (void)getDataStreamInBackgroundWithBlock:(PF_NULLABLE PFDataStreamResultBlock)block; + +/*! + @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network. + + @discussion This method will execute the progressBlock periodically with the percent progress. + `progressBlock` will get called with `100` before `resultBlock` is called. + + @param resultBlock The block should have the following argument signature: ^(NSData *result, NSError *error) + @param progressBlock The block should have the following argument signature: ^(int percentDone) + */ +- (void)getDataInBackgroundWithBlock:(PF_NULLABLE PFDataResultBlock)resultBlock + progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/*! + @abstract This method is like but avoids + ever holding the entire `PFFile` contents in memory at once. + + @discussion This can help applications with many large files avoid memory warnings. + + @param resultBlock The block should have the following argument signature: `^(NSInputStream *result, NSError *error)`. + @param progressBlock The block should have the following argument signature: `^(int percentDone)`. + */ +- (void)getDataStreamInBackgroundWithBlock:(PF_NULLABLE PFDataStreamResultBlock)resultBlock + progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock; + +/* + @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSData *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + */ +- (void)getDataInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Interrupting a Transfer +///-------------------------------------- + +/*! + @abstract Cancels the current request (upload or download of file). + */ +- (void)cancel; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFGeoPoint.h b/Pods/Parse/PFGeoPoint.h new file mode 100644 index 0000000..6861946 --- /dev/null +++ b/Pods/Parse/PFGeoPoint.h @@ -0,0 +1,115 @@ +// +// PFGeoPoint.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class PFGeoPoint; + +typedef void(^PFGeoPointResultBlock)(PFGeoPoint *PF_NULLABLE_S geoPoint, NSError *PF_NULLABLE_S error); + +/*! + `PFGeoPoint` may be used to embed a latitude / longitude point as the value for a key in a . + It could be used to perform queries in a geospatial manner using <[PFQuery whereKey:nearGeoPoint:]>. + + Currently, instances of may only have one key associated with a `PFGeoPoint` type. + */ +@interface PFGeoPoint : NSObject + +///-------------------------------------- +/// @name Creating a Geo Point +///-------------------------------------- + +/*! + @abstract Create a PFGeoPoint object. Latitude and longitude are set to `0.0`. + + @returns Returns a new `PFGeoPoint`. + */ ++ (PFGeoPoint *)geoPoint; + +/*! + @abstract Creates a new `PFGeoPoint` object for the given `CLLocation`, set to the location's coordinates. + + @param location Instace of `CLLocation`, with set latitude and longitude. + + @returns Returns a new PFGeoPoint at specified location. + */ ++ (PFGeoPoint *)geoPointWithLocation:(PF_NULLABLE CLLocation *)location; + +/*! + @abstract Create a new `PFGeoPoint` object with the specified latitude and longitude. + + @param latitude Latitude of point in degrees. + @param longitude Longitude of point in degrees. + + @returns New point object with specified latitude and longitude. + */ ++ (PFGeoPoint *)geoPointWithLatitude:(double)latitude longitude:(double)longitude; + +/*! + @abstract Fetches the current device location and executes a block with a new `PFGeoPoint` object. + + @param resultBlock A block which takes the newly created `PFGeoPoint` as an argument. + It should have the following argument signature: `^(PFGeoPoint *geoPoint, NSError *error)` + */ ++ (void)geoPointForCurrentLocationInBackground:(PF_NULLABLE PFGeoPointResultBlock)resultBlock; + +///-------------------------------------- +/// @name Controlling Position +///-------------------------------------- + +/*! + @abstract Latitude of point in degrees. Valid range is from `-90.0` to `90.0`. + */ +@property (nonatomic, assign) double latitude; + +/*! + @abstract Longitude of point in degrees. Valid range is from `-180.0` to `180.0`. + */ +@property (nonatomic, assign) double longitude; + +///-------------------------------------- +/// @name Calculating Distance +///-------------------------------------- + +/*! + @abstract Get distance in radians from this point to specified point. + + @param point `PFGeoPoint` that represents the location of other point. + + @returns Distance in radians between the receiver and `point`. + */ +- (double)distanceInRadiansTo:(PF_NULLABLE PFGeoPoint *)point; + +/*! + @abstract Get distance in miles from this point to specified point. + + @param point `PFGeoPoint` that represents the location of other point. + + @returns Distance in miles between the receiver and `point`. + */ +- (double)distanceInMilesTo:(PF_NULLABLE PFGeoPoint *)point; + +/*! + @abstract Get distance in kilometers from this point to specified point. + + @param point `PFGeoPoint` that represents the location of other point. + + @returns Distance in kilometers between the receiver and `point`. + */ +- (double)distanceInKilometersTo:(PF_NULLABLE PFGeoPoint *)point; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFInstallation.h b/Pods/Parse/PFInstallation.h new file mode 100644 index 0000000..57e4cee --- /dev/null +++ b/Pods/Parse/PFInstallation.h @@ -0,0 +1,116 @@ +// +// PFInstallation.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + A Parse Framework Installation Object that is a local representation of an + installation persisted to the Parse cloud. This class is a subclass of a + , and retains the same functionality of a PFObject, but also extends + it with installation-specific fields and related immutability and validity + checks. + + A valid `PFInstallation` can only be instantiated via + <[PFInstallation currentInstallation]> because the required identifier fields + are readonly. The and fields are also readonly properties which + are automatically updated to match the device's time zone and application badge + when the `PFInstallation` is saved, thus these fields might not reflect the + latest device state if the installation has not recently been saved. + + `PFInstallation` objects which have a valid and are saved to + the Parse cloud can be used to target push notifications. + */ + +@interface PFInstallation : PFObject + +///-------------------------------------- +/// @name Accessing the Current Installation +///-------------------------------------- + +/*! + @abstract Gets the currently-running installation from disk and returns an instance of it. + + @discussion If this installation is not stored on disk, returns a `PFInstallation` + with and fields set to those of the + current installation. + + @result Returns a `PFInstallation` that represents the currently-running installation. + */ ++ (instancetype)currentInstallation; + +///-------------------------------------- +/// @name Installation Properties +///-------------------------------------- + +/*! + @abstract The device type for the `PFInstallation`. + */ +@property (nonatomic, strong, readonly) NSString *deviceType; + +/*! + @abstract The installationId for the `PFInstallation`. + */ +@property (nonatomic, strong, readonly) NSString *installationId; + +/*! + @abstract The device token for the `PFInstallation`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *deviceToken; + +/*! + @abstract The badge for the `PFInstallation`. + */ +@property (nonatomic, assign) NSInteger badge; + +/*! + @abstract The name of the time zone for the `PFInstallation`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSString *timeZone; + +/*! + @abstract The channels for the `PFInstallation`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSArray *channels; + +/*! + @abstract Sets the device token string property from an `NSData`-encoded token. + + @param deviceTokenData A token that identifies the device. + */ +- (void)setDeviceTokenFromData:(PF_NULLABLE NSData *)deviceTokenData; + +///-------------------------------------- +/// @name Querying for Installations +///-------------------------------------- + +/*! + @abstract Creates a for `PFInstallation` objects. + + @discussion Only the following types of queries are allowed for installations: + + - `[query getObjectWithId:]` + - `[query whereKey:@"installationId" equalTo:]` + - `[query whereKey:@"installationId" matchesKey: inQuery:]` + + You can add additional query conditions, but one of the above must appear as a top-level `AND` clause in the query. + */ ++ (PF_NULLABLE PFQuery *)query; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFNetworkActivityIndicatorManager.h b/Pods/Parse/PFNetworkActivityIndicatorManager.h new file mode 100644 index 0000000..9095271 --- /dev/null +++ b/Pods/Parse/PFNetworkActivityIndicatorManager.h @@ -0,0 +1,67 @@ +// +// PFNetworkActivityIndicatorManager.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import +#import + +#import + +PF_ASSUME_NONNULL_BEGIN + +/*! + `PFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. + When enabled, it will start managing the network activity indicator in the status bar, + according to the network operations that are performed by Parse SDK. + + The number of active requests is incremented or decremented like a stack or a semaphore, + the activity indicator will animate, as long as the number is greater than zero. + */ +@interface PFNetworkActivityIndicatorManager : NSObject + +/*! + A Boolean value indicating whether the manager is enabled. + If `YES` - the manager will start managing the status bar network activity indicator, + according to the network operations that are performed by Parse SDK. + The default value is `YES`. + */ +@property (nonatomic, assign, getter = isEnabled) BOOL enabled; + +/*! + A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. + */ +@property (nonatomic, assign, readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; + +/*! + The value that indicates current network activities count. + */ +@property (nonatomic, assign, readonly) NSUInteger networkActivityCount; + +/*! + @abstract Returns the shared network activity indicator manager object for the system. + + @returns The systemwide network activity indicator manager. + */ ++ (instancetype)sharedManager; + +/*! + @abstract Increments the number of active network requests. + + @discussion If this number was zero before incrementing, + this will start animating network activity indicator in the status bar. + */ +- (void)incrementActivityCount; + +/*! + @abstract Decrements the number of active network requests. + + @discussion If this number becomes zero after decrementing, + this will stop animating network activity indicator in the status bar. + */ +- (void)decrementActivityCount; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFNullability.h b/Pods/Parse/PFNullability.h new file mode 100644 index 0000000..507a91e --- /dev/null +++ b/Pods/Parse/PFNullability.h @@ -0,0 +1,44 @@ +// +// PFNullability.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#ifndef Parse_PFNullability_h +#define Parse_PFNullability_h + +///-------------------------------------- +/// @name Nullability Annotation Support +///-------------------------------------- + +#if __has_feature(nullability) +# define PF_NONNULL nonnull +# define PF_NONNULL_S __nonnull +# define PF_NULLABLE nullable +# define PF_NULLABLE_S __nullable +# define PF_NULLABLE_PROPERTY nullable, +#else +# define PF_NONNULL +# define PF_NONNULL_S +# define PF_NULLABLE +# define PF_NULLABLE_S +# define PF_NULLABLE_PROPERTY +#endif + +#if __has_feature(assume_nonnull) +# ifdef NS_ASSUME_NONNULL_BEGIN +# define PF_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN +# else +# define PF_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +# endif +# ifdef NS_ASSUME_NONNULL_END +# define PF_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END +# else +# define PF_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") +# endif +#else +# define PF_ASSUME_NONNULL_BEGIN +# define PF_ASSUME_NONNULL_END +#endif + +#endif diff --git a/Pods/Parse/PFObject+Subclass.h b/Pods/Parse/PFObject+Subclass.h new file mode 100644 index 0000000..289faeb --- /dev/null +++ b/Pods/Parse/PFObject+Subclass.h @@ -0,0 +1,127 @@ +// +// PFObject+Subclass.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#else +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class PFQuery; + +/*! + ### Subclassing Notes + + Developers can subclass `PFObject` for a more native object-oriented class structure. + Strongly-typed subclasses of `PFObject` must conform to the protocol + and must call before <[Parse setApplicationId:clientKey:]> is called. + After this it will be returned by and other `PFObject` factories. + + All methods in except for <[PFSubclassing parseClassName]> + are already implemented in the `PFObject+Subclass` category. + + Including `PFObject+Subclass.h` in your implementation file provides these implementations automatically. + + Subclasses support simpler initializers, query syntax, and dynamic synthesizers. + The following shows an example subclass: + + \@interface MYGame : PFObject + + // Accessing this property is the same as objectForKey:@"title" + @property (nonatomic, strong) NSString *title; + + + (NSString *)parseClassName; + + @end + + + @implementation MYGame + + @dynamic title; + + + (NSString *)parseClassName { + return @"Game"; + } + + @end + + + MYGame *game = [[MYGame alloc] init]; + game.title = @"Bughouse"; + [game saveInBackground]; + */ +@interface PFObject (Subclass) + +///-------------------------------------- +/// @name Methods for Subclasses +///-------------------------------------- + +/*! + @abstract Creates an instance of the registered subclass with this class's . + + @discussion This helps a subclass ensure that it can be subclassed itself. + For example, `[PFUser object]` will return a `MyUser` object if `MyUser` is a registered subclass of `PFUser`. + For this reason, `[MyClass object]` is preferred to `[[MyClass alloc] init]`. + This method can only be called on subclasses which conform to `PFSubclassing`. + A default implementation is provided by `PFObject` which should always be sufficient. + */ ++ (instancetype)object; + +/*! + @abstract Creates a reference to an existing `PFObject` for use in creating associations between `PFObjects`. + + @discussion Calling on this object will return `NO` until or has been called. + This method can only be called on subclasses which conform to . + A default implementation is provided by `PFObject` which should always be sufficient. + No network request will be made. + + @param objectId The object id for the referenced object. + + @returns An instance of `PFObject` without data. + */ ++ (instancetype)objectWithoutDataWithObjectId:(PF_NULLABLE NSString *)objectId; + +/*! + @abstract Registers an Objective-C class for Parse to use for representing a given Parse class. + + @discussion Once this is called on a `PFObject` subclass, any `PFObject` Parse creates with a class name + that matches `[self parseClassName]` will be an instance of subclass. + This method can only be called on subclasses which conform to . + A default implementation is provided by `PFObject` which should always be sufficient. + */ ++ (void)registerSubclass; + +/*! + @abstract Returns a query for objects of type . + + @discussion This method can only be called on subclasses which conform to . + A default implementation is provided by which should always be sufficient. + */ ++ (PF_NULLABLE PFQuery *)query; + +/*! + @abstract Returns a query for objects of type with a given predicate. + + @discussion A default implementation is provided by which should always be sufficient. + @warning This method can only be called on subclasses which conform to . + + @param predicate The predicate to create conditions from. + + @returns An instance of . + + @see [PFQuery queryWithClassName:predicate:] + */ ++ (PF_NULLABLE PFQuery *)queryWithPredicate:(PF_NULLABLE NSPredicate *)predicate; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFObject.h b/Pods/Parse/PFObject.h new file mode 100644 index 0000000..ab45c91 --- /dev/null +++ b/Pods/Parse/PFObject.h @@ -0,0 +1,1423 @@ +// +// PFObject.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#else +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@protocol PFSubclassing; +@class BFTask; +@class PFRelation; + +/*! + The name of the default pin that for PFObject local data store. + */ +extern NSString *const PFObjectDefaultPin; + +/*! + The `PFObject` class is a local representation of data persisted to the Parse cloud. + This is the main class that is used to interact with objects in your app. + */ +NS_REQUIRES_PROPERTY_DEFINITIONS +@interface PFObject : NSObject { + BOOL dirty; + + // An array of NSDictionary of NSString -> PFFieldOperation. + // Each dictionary has a subset of the object's keys as keys, and the + // changes to the value for that key as its value. + // There is always at least one dictionary of pending operations. + // Every time a save is started, a new dictionary is added to the end. + // Whenever a save completes, the new data is put into fetchedData, and + // a dictionary is removed from the start. + NSMutableArray *PF_NULLABLE_S operationSetQueue; + + // Our best estimate as to what the current data is, based on + // the last fetch from the server, and the set of pending operations. + NSMutableDictionary *PF_NULLABLE_S estimatedData; +} + +///-------------------------------------- +/// @name Creating a PFObject +///-------------------------------------- + +/*! + @abstract Creates a new PFObject with a class name. + + @param className A class name can be any alphanumeric string that begins with a letter. + It represents an object in your app, like a 'User' or a 'Document'. + + @returns Returns the object that is instantiated with the given class name. + */ ++ (instancetype)objectWithClassName:(NSString *)className; + +/*! + @abstract Creates a reference to an existing PFObject for use in creating associations between PFObjects. + + @discussion Calling on this object will return `NO` until has been called. + No network request will be made. + + @param className The object's class. + @param objectId The object id for the referenced object. + + @returns A `PFObject` instance without data. + */ ++ (instancetype)objectWithoutDataWithClassName:(NSString *)className + objectId:(PF_NULLABLE NSString *)objectId; + +/*! + @abstract Creates a new `PFObject` with a class name, initialized with data + constructed from the specified set of objects and keys. + + @param className The object's class. + @param dictionary An `NSDictionary` of keys and objects to set on the new `PFObject`. + + @returns A PFObject with the given class name and set with the given data. + */ ++ (PFObject *)objectWithClassName:(NSString *)className + dictionary:(PF_NULLABLE NSDictionary *)dictionary; + +/*! + @abstract Initializes a new empty `PFObject` instance with a class name. + + @param newClassName A class name can be any alphanumeric string that begins with a letter. + It represents an object in your app, like a 'User' or a 'Document'. + + @returns Returns the object that is instantiated with the given class name. + */ +- (instancetype)initWithClassName:(NSString *)newClassName; + +///-------------------------------------- +/// @name Managing Object Properties +///-------------------------------------- + +/*! + @abstract The class name of the object. + */ +@property (strong, readonly) NSString *parseClassName; + +/*! + @abstract The id of the object. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *objectId; + +/*! + @abstract When the object was last updated. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSDate *updatedAt; + +/*! + @abstract When the object was created. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSDate *createdAt; + +/*! + @abstract The ACL for this object. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) PFACL *ACL; + +/*! + @abstract Returns an array of the keys contained in this object. + + @discussion This does not include `createdAt`, `updatedAt`, `authData`, or `objectId`. + It does include things like username and ACL. + */ +- (NSArray *)allKeys; + +///-------------------------------------- +/// @name Accessors +///-------------------------------------- + +/*! + @abstract Returns the value associated with a given key. + + @param key The key for which to return the corresponding value. + */ +- (PF_NULLABLE_S id)objectForKey:(NSString *)key; + +/*! + @abstract Sets the object associated with a given key. + + @param object The object for `key`. A strong reference to the object is maintaned by PFObject. + Raises an `NSInvalidArgumentException` if `object` is `nil`. + If you need to represent a `nil` value - use `NSNull`. + @param key The key for `object`. + Raises an `NSInvalidArgumentException` if `key` is `nil`. + + @see setObject:forKeyedSubscript: + */ +- (void)setObject:(id)object forKey:(NSString *)key; + +/*! + @abstract Unsets a key on the object. + + @param key The key. + */ +- (void)removeObjectForKey:(NSString *)key; + +/*! + @abstract Returns the value associated with a given key. + + @discussion This method enables usage of literal syntax on `PFObject`. + E.g. `NSString *value = object[@"key"];` + + @param key The key for which to return the corresponding value. + + @see objectForKey: + */ +- (PF_NULLABLE_S id)objectForKeyedSubscript:(NSString *)key; + +/*! + @abstract Returns the value associated with a given key. + + @discussion This method enables usage of literal syntax on `PFObject`. + E.g. `object[@"key"] = @"value";` + + @param object The object for `key`. A strong reference to the object is maintaned by PFObject. + Raises an `NSInvalidArgumentException` if `object` is `nil`. + If you need to represent a `nil` value - use `NSNull`. + @param key The key for `object`. + Raises an `NSInvalidArgumentException` if `key` is `nil`. + + @see setObject:forKey: + */ +- (void)setObject:(PF_NULLABLE_S id)object forKeyedSubscript:(NSString *)key; + +/*! + @abstract Returns the relation object associated with the given key. + + @param key The key that the relation is associated with. + */ +- (PFRelation *)relationForKey:(NSString *)key; + +/*! + @abstract Returns the relation object associated with the given key. + + @param key The key that the relation is associated with. + + @deprecated Please use `[PFObject relationForKey:]` instead. + */ +- (PFRelation *)relationforKey:(NSString *)key PARSE_DEPRECATED("Please use -relationForKey: instead."); + +///-------------------------------------- +/// @name Array Accessors +///-------------------------------------- + +/*! + @abstract Adds an object to the end of the array associated with a given key. + + @param object The object to add. + @param key The key. + */ +- (void)addObject:(id)object forKey:(NSString *)key; + +/*! + @abstract Adds the objects contained in another array to the end of the array associated with a given key. + + @param objects The array of objects to add. + @param key The key. + */ +- (void)addObjectsFromArray:(NSArray *)objects forKey:(NSString *)key; + +/*! + @abstract Adds an object to the array associated with a given key, only if it is not already present in the array. + + @discussion The position of the insert is not guaranteed. + + @param object The object to add. + @param key The key. + */ +- (void)addUniqueObject:(id)object forKey:(NSString *)key; + +/*! + @abstract Adds the objects contained in another array to the array associated with a given key, + only adding elements which are not already present in the array. + + @dicsussion The position of the insert is not guaranteed. + + @param objects The array of objects to add. + @param key The key. + */ +- (void)addUniqueObjectsFromArray:(NSArray *)objects forKey:(NSString *)key; + +/*! + @abstract Removes all occurrences of an object from the array associated with a given key. + + @param object The object to remove. + @param key The key. + */ +- (void)removeObject:(id)object forKey:(NSString *)key; + +/*! + @abstract Removes all occurrences of the objects contained in another array from the array associated with a given key. + + @param objects The array of objects to remove. + @param key The key. + */ +- (void)removeObjectsInArray:(NSArray *)objects forKey:(NSString *)key; + +///-------------------------------------- +/// @name Increment +///-------------------------------------- + +/*! + @abstract Increments the given key by `1`. + + @param key The key. + */ +- (void)incrementKey:(NSString *)key; + +/*! + @abstract Increments the given key by a number. + + @param key The key. + @param amount The amount to increment. + */ +- (void)incrementKey:(NSString *)key byAmount:(NSNumber *)amount; + +///-------------------------------------- +/// @name Saving Objects +///-------------------------------------- + +/*! + @abstract *Synchronously* saves the `PFObject`. + + @returns Returns whether the save succeeded. + */ +- (BOOL)save; + +/*! + @abstract *Synchronously* saves the `PFObject` and sets an error if it occurs. + + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the save succeeded. + */ +- (BOOL)save:(NSError **)error; + +/*! + @abstract Saves the `PFObject` *asynchronously*. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)saveInBackground; + +/*! + @abstract Saves the `PFObject` *asynchronously* and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Saves the `PFObject` asynchronously and calls the given callback. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ +- (void)saveInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Saves this object to the server at some unspecified time in the future, + even if Parse is currently inaccessible. + + @discussion Use this when you may not have a solid network connection, and don't need to know when the save completes. + If there is some problem with the object such that it can't be saved, it will be silently discarded. If the save + completes successfully while the object is still in memory, then callback will be called. + + Objects saved with this method will be stored locally in an on-disk cache until they can be delivered to Parse. + They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection is + available. Objects saved this way will persist even after the app is closed, in which case they will be sent the + next time the app is opened. If more than 10MB of data is waiting to be sent, subsequent calls to + will cause old saves to be silently discarded until the connection can be re-established, and the queued objects + can be saved. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)saveEventually; + +/*! + @abstract Saves this object to the server at some unspecified time in the future, + even if Parse is currently inaccessible. + + @discussion Use this when you may not have a solid network connection, and don't need to know when the save completes. + If there is some problem with the object such that it can't be saved, it will be silently discarded. If the save + completes successfully while the object is still in memory, then callback will be called. + + Objects saved with this method will be stored locally in an on-disk cache until they can be delivered to Parse. + They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection is + available. Objects saved this way will persist even after the app is closed, in which case they will be sent the + next time the app is opened. If more than 10MB of data is waiting to be sent, subsequent calls to + will cause old saves to be silently discarded until the connection can be re-established, and the queued objects + can be saved. + + @param callback The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)saveEventually:(PF_NULLABLE PFBooleanResultBlock)callback; + +///-------------------------------------- +/// @name Saving Many Objects +///-------------------------------------- + +/*! + @abstract Saves a collection of objects *synchronously all at once. + + @param objects The array of objects to save. + + @returns Returns whether the save succeeded. + */ ++ (BOOL)saveAll:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract Saves a collection of objects *synchronously* all at once and sets an error if necessary. + + @param objects The array of objects to save. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the save succeeded. + */ ++ (BOOL)saveAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract Saves a collection of objects all at once *asynchronously*. + + @param objects The array of objects to save. + + @returns The task that encapsulates the work being done. + */ ++ (BFTask *)saveAllInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract Saves a collection of objects all at once `asynchronously` and executes the block when done. + + @param objects The array of objects to save. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)saveAllInBackground:(PF_NULLABLE NSArray *)objects + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Saves a collection of objects all at once *asynchronously* and calls a callback when done. + + @param objects The array of objects to save. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)number error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)saveAllInBackground:(PF_NULLABLE NSArray *)objects + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Deleting Many Objects +///-------------------------------------- + +/*! + @abstract *Synchronously* deletes a collection of objects all at once. + + @param objects The array of objects to delete. + + @returns Returns whether the delete succeeded. + */ ++ (BOOL)deleteAll:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Synchronously* deletes a collection of objects all at once and sets an error if necessary. + + @param objects The array of objects to delete. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the delete succeeded. + */ ++ (BOOL)deleteAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract Deletes a collection of objects all at once asynchronously. + @param objects The array of objects to delete. + @returns The task that encapsulates the work being done. + */ ++ (BFTask *)deleteAllInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract Deletes a collection of objects all at once *asynchronously* and executes the block when done. + + @param objects The array of objects to delete. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)deleteAllInBackground:(PF_NULLABLE NSArray *)objects + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Deletes a collection of objects all at once *asynchronously* and calls a callback when done. + + @param objects The array of objects to delete. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)number error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)deleteAllInBackground:(PF_NULLABLE NSArray *)objects + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting an Object +///-------------------------------------- + +/*! + @abstract Gets whether the `PFObject` has been fetched. + + @returns `YES` if the PFObject is new or has been fetched or refreshed, otherwise `NO`. + */ +- (BOOL)isDataAvailable; + +#if PARSE_IOS_ONLY + +/*! + @abstract Refreshes the PFObject with the current data from the server. + + @deprecated Please use `-fetch` instead. + */ +- (void)refresh PARSE_DEPRECATED("Please use `-fetch` instead."); + +/*! + @abstract *Synchronously* refreshes the `PFObject` with the current data from the server and sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + + @deprecated Please use `-fetch:` instead. + */ +- (void)refresh:(NSError **)error PARSE_DEPRECATED("Please use `-fetch:` instead."); + +/*! + @abstract *Asynchronously* refreshes the `PFObject` and executes the given callback block. + + @param block The block to execute. + The block should have the following argument signature: `^(PFObject *object, NSError *error)` + + @deprecated Please use `-fetchInBackgroundWithBlock:` instead. + */ +- (void)refreshInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block PARSE_DEPRECATED("Please use `-fetchInBackgroundWithBlock:` instead."); + +/* + @abstract *Asynchronously* refreshes the `PFObject` and calls the given callback. + + @param target The target on which the selector will be called. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(PFObject *)refreshedObject error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `refreshedObject` will be the `PFObject` with the refreshed data. + + @deprecated Please use `fetchInBackgroundWithTarget:selector:` instead. + */ +- (void)refreshInBackgroundWithTarget:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector PARSE_DEPRECATED("Please use `fetchInBackgroundWithTarget:selector:` instead."); + +#endif + +/*! + @abstract *Synchronously* fetches the PFObject with the current data from the server. + */ +- (void)fetch; +/*! + @abstract *Synchronously* fetches the PFObject with the current data from the server and sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + */ +- (void)fetch:(NSError **)error; + +/*! + @abstract *Synchronously* fetches the `PFObject` data from the server if is `NO`. + */ +- (PF_NULLABLE PFObject *)fetchIfNeeded; + +/*! + @abstract *Synchronously* fetches the `PFObject` data from the server if is `NO`. + + @param error Pointer to an `NSError` that will be set if necessary. + */ +- (PF_NULLABLE PFObject *)fetchIfNeeded:(NSError **)error; + +/*! + @abstract Fetches the `PFObject` *asynchronously* and sets it as a result for the task. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)fetchInBackground; + +/*! + @abstract Fetches the PFObject *asynchronously* and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(PFObject *object, NSError *error)`. + */ +- (void)fetchInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block; + +/* + @abstract Fetches the `PFObject *asynchronously* and calls the given callback. + + @param target The target on which the selector will be called. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(PFObject *)refreshedObject error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `refreshedObject` will be the `PFObject` with the refreshed data. + */ +- (void)fetchInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Fetches the `PFObject` data *asynchronously* if isDataAvailable is `NO`, + then sets it as a result for the task. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)fetchIfNeededInBackground; + +/*! + @abstract Fetches the `PFObject` data *asynchronously* if is `NO`, then calls the callback block. + + @param block The block to execute. + It should have the following argument signature: `^(PFObject *object, NSError *error)`. + */ +- (void)fetchIfNeededInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block; + +/* + @abstract Fetches the PFObject's data asynchronously if isDataAvailable is false, then calls the callback. + + @param target The target on which the selector will be called. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(PFObject *)fetchedObject error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `refreshedObject` will be the `PFObject` with the refreshed data. + */ +- (void)fetchIfNeededInBackgroundWithTarget:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting Many Objects +///-------------------------------------- + +/*! + @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server. + + @param objects The list of objects to fetch. + */ ++ (void)fetchAll:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server + and sets an error if it occurs. + + @param objects The list of objects to fetch. + @param error Pointer to an `NSError` that will be set if necessary. + */ ++ (void)fetchAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server. + @param objects The list of objects to fetch. + */ ++ (void)fetchAllIfNeeded:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server + and sets an error if it occurs. + + @param objects The list of objects to fetch. + @param error Pointer to an `NSError` that will be set if necessary. + */ ++ (void)fetchAllIfNeeded:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*. + + @param objects The list of objects to fetch. + + @returns The task that encapsulates the work being done. + */ ++ (BFTask *)fetchAllInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously* + and calls the given block. + + @param objects The list of objects to fetch. + @param block The block to execute. + It should have the following argument signature: `^(NSArray *objects, NSError *error)`. + */ ++ (void)fetchAllInBackground:(PF_NULLABLE NSArray *)objects + block:(PF_NULLABLE PFArrayResultBlock)block; + +/* + @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously* + and calls the given callback. + + @param objects The list of objects to fetch. + @param target The target on which the selector will be called. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSArray *)fetchedObjects error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `fetchedObjects` will the array of `PFObject` objects that were fetched. + */ ++ (void)fetchAllInBackground:(PF_NULLABLE NSArray *)objects + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*. + + @param objects The list of objects to fetch. + + @returns The task that encapsulates the work being done. + */ ++ (BFTask *)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract Fetches all of the PFObjects with the current data from the server *asynchronously* + and calls the given block. + + @param objects The list of objects to fetch. + @param block The block to execute. + It should have the following argument signature: `^(NSArray *objects, NSError *error)`. + */ ++ (void)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects + block:(PF_NULLABLE PFArrayResultBlock)block; + +/* + @abstract Fetches all of the PFObjects with the current data from the server *asynchronously* + and calls the given callback. + + @param objects The list of objects to fetch. + @param target The target on which the selector will be called. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSArray *)fetchedObjects error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `fetchedObjects` will the array of `PFObject` objects that were fetched. + */ ++ (void)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Fetching From Local Datastore +///-------------------------------------- + +/*! + @abstract *Synchronously* loads data from the local datastore into this object, + if it has not been fetched from the server already. + */ +- (void)fetchFromLocalDatastore; + +/*! + @abstract *Synchronously* loads data from the local datastore into this object, if it has not been fetched + from the server already. + + @discussion If the object is not stored in the local datastore, this `error` will be set to + return kPFErrorCacheMiss. + + @param error Pointer to an `NSError` that will be set if necessary. + */ +- (void)fetchFromLocalDatastore:(NSError **)error; + +/*! + @abstract *Asynchronously* loads data from the local datastore into this object, + if it has not been fetched from the server already. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)fetchFromLocalDatastoreInBackground; + +/*! + @abstract *Asynchronously* loads data from the local datastore into this object, + if it has not been fetched from the server already. + + @param block The block to execute. + It should have the following argument signature: `^(PFObject *object, NSError *error)`. + */ +- (void)fetchFromLocalDatastoreInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block; + +///-------------------------------------- +/// @name Deleting an Object +///-------------------------------------- + +/*! + @abstract *Synchronously* deletes the `PFObject`. + + @returns Returns whether the delete succeeded. + */ +- (BOOL)delete; + +/*! + @abstract *Synchronously* deletes the `PFObject` and sets an error if it occurs. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the delete succeeded. + */ +- (BOOL)delete:(NSError **)error; + +/*! + @abstract Deletes the `PFObject` *asynchronously*. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)deleteInBackground; + +/*! + @abstract Deletes the `PFObject` *asynchronously* and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)deleteInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Deletes the `PFObject` *asynchronously* and calls the given callback. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ +- (void)deleteInBackgroundWithTarget:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Deletes this object from the server at some unspecified time in the future, + even if Parse is currently inaccessible. + + @discussion Use this when you may not have a solid network connection, + and don't need to know when the delete completes. If there is some problem with the object + such that it can't be deleted, the request will be silently discarded. + + Delete instructions made with this method will be stored locally in an on-disk cache until they can be transmitted + to Parse. They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection + is available. Delete requests will persist even after the app is closed, in which case they will be sent the + next time the app is opened. If more than 10MB of or commands are waiting + to be sent, subsequent calls to or will cause old requests to be silently discarded + until the connection can be re-established, and the queued requests can go through. + + @returns The task that encapsulates the work being done. + */ +- (BFTask *)deleteEventually; + +///-------------------------------------- +/// @name Dirtiness +///-------------------------------------- + +/*! + @abstract Gets whether any key-value pair in this object (or its children) + has been added/updated/removed and not saved yet. + + @returns Returns whether this object has been altered and not saved yet. + */ +- (BOOL)isDirty; + +/*! + @abstract Get whether a value associated with a key has been added/updated/removed and not saved yet. + + @param key The key to check for + + @returns Returns whether this key has been altered and not saved yet. + */ +- (BOOL)isDirtyForKey:(NSString *)key; + + +///-------------------------------------- +/// @name Pinning +///-------------------------------------- + +/*! + @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @returns Returns whether the pin succeeded. + + @see unpin: + @see PFObjectDefaultPin + */ +- (BOOL)pin; + +/*! + @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the pin succeeded. + + @see unpin: + @see PFObjectDefaultPin + */ +- (BOOL)pin:(NSError **)error; + +/*! + @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param name The name of the pin. + + @returns Returns whether the pin succeeded. + + @see unpinWithName: + */ +- (BOOL)pinWithName:(NSString *)name; + +/*! + @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param name The name of the pin. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the pin succeeded. + + @see unpinWithName: + */ +- (BOOL)pinWithName:(NSString *)name + error:(NSError **)error; + +/*! + @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @returns The task that encapsulates the work being done. + + @see unpinInBackground + @see PFObjectDefaultPin + */ +- (BFTask *)pinInBackground; + +/*! + @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see unpinInBackgroundWithBlock: + @see PFObjectDefaultPin + */ +- (void)pinInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param name The name of the pin. + + @returns The task that encapsulates the work being done. + + @see unpinInBackgroundWithName: + */ +- (BFTask *)pinInBackgroundWithName:(NSString *)name; + +/*! + @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it. + + @param name The name of the pin. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see unpinInBackgroundWithName:block: + */ +- (void)pinInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Pinning Many Objects +///-------------------------------------- + +/*! + @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + + @returns Returns whether the pin succeeded. + + @see unpinAll: + @see PFObjectDefaultPin + */ ++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the pin succeeded. + + @see unpinAll:error: + @see PFObjectDefaultPin + */ ++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param name The name of the pin. + + @returns Returns whether the pin succeeded. + + @see unpinAll:withName: + */ ++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects withName:(NSString *)name; + +/*! + @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param name The name of the pin. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the pin succeeded. + + @see unpinAll:withName:error: + */ ++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects + withName:(NSString *)name + error:(NSError **)error; + +/*! + @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + + @returns The task that encapsulates the work being done. + + @see unpinAllInBackground: + @see PFObjectDefaultPin + */ ++ (BFTask *)pinAllInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see unpinAllInBackground:block: + @see PFObjectDefaultPin + */ ++ (void)pinAllInBackground:(PF_NULLABLE NSArray *)objects block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param name The name of the pin. + + @returns The task that encapsulates the work being done. + + @see unpinAllInBackground:withName: + */ ++ (BFTask *)pinAllInBackground:(PF_NULLABLE NSArray *)objects withName:(NSString *)name; + +/*! + @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively. + + @discussion If those other objects have not been fetched from Parse, they will not be stored. However, + if they have changed data, all the changes will be retained. To get the objects back later, you can + use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with + `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it. + + @param objects The objects to be pinned. + @param name The name of the pin. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see unpinAllInBackground:withName:block: + */ ++ (void)pinAllInBackground:(PF_NULLABLE NSArray *)objects + withName:(NSString *)name + block:(PF_NULLABLE PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Unpinning +///-------------------------------------- + +/*! + @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @returns Returns whether the unpin succeeded. + + @see pin: + @see PFObjectDefaultPin + */ +- (BOOL)unpin; + +/*! + @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + + @see pin: + @see PFObjectDefaultPin + */ +- (BOOL)unpin:(NSError **)error; + +/*! + @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively. + + @param name The name of the pin. + + @returns Returns whether the unpin succeeded. + + @see pinWithName: + */ +- (BOOL)unpinWithName:(NSString *)name; + +/*! + @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively. + + @param name The name of the pin. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + + @see pinWithName:error: + */ +- (BOOL)unpinWithName:(NSString *)name + error:(NSError **)error; + +/*! + @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @returns The task that encapsulates the work being done. + + @see pinInBackground + @see PFObjectDefaultPin + */ +- (BFTask *)unpinInBackground; + +/*! + @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see pinInBackgroundWithBlock: + @see PFObjectDefaultPin + */ +- (void)unpinInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively. + + @param name The name of the pin. + + @returns The task that encapsulates the work being done. + + @see pinInBackgroundWithName: + */ +- (BFTask *)unpinInBackgroundWithName:(NSString *)name; + +/*! + @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively. + + @param name The name of the pin. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see pinInBackgroundWithName:block: + */ +- (void)unpinInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Unpinning Many Objects +///-------------------------------------- + +/*! + @abstract *Synchronously* removes all objects in the local datastore + using a default pin name: `PFObjectDefaultPin`. + + @returns Returns whether the unpin succeeded. + + @see PFObjectDefaultPin + */ ++ (BOOL)unpinAllObjects; + +/*! + @abstract *Synchronously* removes all objects in the local datastore + using a default pin name: `PFObjectDefaultPin`. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + + @see PFObjectDefaultPin + */ ++ (BOOL)unpinAllObjects:(NSError **)error; + +/*! + @abstract *Synchronously* removes all objects with the specified pin name. + + @param name The name of the pin. + + @returns Returns whether the unpin succeeded. + */ ++ (BOOL)unpinAllObjectsWithName:(NSString *)name; + +/*! + @abstract *Synchronously* removes all objects with the specified pin name. + + @param name The name of the pin. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + */ ++ (BOOL)unpinAllObjectsWithName:(NSString *)name + error:(NSError **)error; + +/*! + @abstract *Asynchronously* removes all objects in the local datastore + using a default pin name: `PFObjectDefaultPin`. + + @returns The task that encapsulates the work being done. + + @see PFObjectDefaultPin + */ ++ (BFTask *)unpinAllObjectsInBackground; + +/*! + @abstract *Asynchronously* removes all objects in the local datastore + using a default pin name: `PFObjectDefaultPin`. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see PFObjectDefaultPin + */ ++ (void)unpinAllObjectsInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Asynchronously* removes all objects with the specified pin name. + + @param name The name of the pin. + + @returns The task that encapsulates the work being done. + */ ++ (BFTask *)unpinAllObjectsInBackgroundWithName:(NSString *)name; + +/*! + @abstract *Asynchronously* removes all objects with the specified pin name. + + @param name The name of the pin. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)unpinAllObjectsInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param objects The objects. + + @returns Returns whether the unpin succeeded. + + @see pinAll: + @see PFObjectDefaultPin + */ ++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param objects The objects. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + + @see pinAll:error: + @see PFObjectDefaultPin + */ ++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error; + +/*! + @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively. + + @param objects The objects. + @param name The name of the pin. + + @returns Returns whether the unpin succeeded. + + @see pinAll:withName: + */ ++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects withName:(NSString *)name; + +/*! + @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively. + + @param objects The objects. + @param name The name of the pin. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unpin succeeded. + + @see pinAll:withName:error: + */ ++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects + withName:(NSString *)name + error:(NSError **)error; + +/*! + @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param objects The objects. + + @returns The task that encapsulates the work being done. + + @see pinAllInBackground: + @see PFObjectDefaultPin + */ ++ (BFTask *)unpinAllInBackground:(PF_NULLABLE NSArray *)objects; + +/*! + @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively, + using a default pin name: `PFObjectDefaultPin`. + + @param objects The objects. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see pinAllInBackground:block: + @see PFObjectDefaultPin + */ ++ (void)unpinAllInBackground:(PF_NULLABLE NSArray *)objects block:(PF_NULLABLE PFBooleanResultBlock)block; + +/*! + @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively. + + @param objects The objects. + @param name The name of the pin. + + @returns The task that encapsulates the work being done. + + @see pinAllInBackground:withName: + */ ++ (BFTask *)unpinAllInBackground:(PF_NULLABLE NSArray *)objects withName:(NSString *)name; + +/*! + @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively. + + @param objects The objects. + @param name The name of the pin. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + + @see pinAllInBackground:withName:block: + */ ++ (void)unpinAllInBackground:(PF_NULLABLE NSArray *)objects + withName:(NSString *)name + block:(PF_NULLABLE PFBooleanResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFProduct.h b/Pods/Parse/PFProduct.h new file mode 100644 index 0000000..939f136 --- /dev/null +++ b/Pods/Parse/PFProduct.h @@ -0,0 +1,65 @@ +// +// PFProduct.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import +#import +#import +#import + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFProduct` class represents an in-app purchase product on the Parse server. + By default, products can only be created via the Data Browser. Saving a `PFProduct` will result in error. + However, the products' metadata information can be queried and viewed. + + This class is currently for iOS only. + */ +@interface PFProduct : PFObject + +///-------------------------------------- +/// @name Product-specific Properties +///-------------------------------------- + +/*! + @abstract The product identifier of the product. + + @discussion This should match the product identifier in iTunes Connect exactly. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *productIdentifier; + +/*! + @abstract The icon of the product. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) PFFile *icon; + +/*! + @abstract The title of the product. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *title; + +/*! + @abstract The subtitle of the product. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *subtitle; + +/*! + @abstract The order in which the product information is displayed in . + + @discussion The product with a smaller order is displayed earlier in the . + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSNumber *order; + +/*! + @abstract The name of the associated download. + + @discussion If there is no downloadable asset, it should be `nil`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSString *downloadName; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFPurchase.h b/Pods/Parse/PFPurchase.h new file mode 100644 index 0000000..3a8e661 --- /dev/null +++ b/Pods/Parse/PFPurchase.h @@ -0,0 +1,87 @@ +// +// PFPurchase.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import +#import + +#import + +@class PFProduct; + +/*! + `PFPurchase` provides a set of APIs for working with in-app purchases. + + This class is currently for iOS only. + */ +@interface PFPurchase : NSObject + +/*! + @abstract Add application logic block which is run when buying a product. + + @discussion This method should be called once for each product, and should be called before + calling . All invocations to should happen within + the same method, and on the main thread. It is recommended to place all invocations of this method + in `application:didFinishLaunchingWithOptions:`. + + @param productIdentifier the product identifier + @param block The block to be run when buying a product. + */ ++ (void)addObserverForProduct:(NSString *)productIdentifier + block:(void(^)(SKPaymentTransaction *transaction))block; + +/*! + @abstract *Asynchronously* initiates the purchase for the product. + + @param productIdentifier the product identifier + @param block the completion block. + */ ++ (void)buyProduct:(NSString *)productIdentifier block:(void(^)(NSError *error))block; + +/*! + @abstract *Asynchronously* download the purchased asset, which is stored on Parse's server. + + @discussion Parse verifies the receipt with Apple and delivers the content only if the receipt is valid. + + @param transaction the transaction, which contains the receipt. + @param completion the completion block. + */ ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(void(^)(NSString *filePath, NSError *error))completion; + +/*! + @abstract *Asynchronously* download the purchased asset, which is stored on Parse's server. + + @discussion Parse verifies the receipt with Apple and delivers the content only if the receipt is valid. + + @param transaction the transaction, which contains the receipt. + @param completion the completion block. + @param progress the progress block, which is called multiple times to reveal progress of the download. + */ ++ (void)downloadAssetForTransaction:(SKPaymentTransaction *)transaction + completion:(void(^)(NSString *filePath, NSError *error))completion + progress:(PFProgressBlock)progress; + +/*! + @abstract *Asynchronously* restore completed transactions for the current user. + + @discussion Only nonconsumable purchases are restored. If observers for the products have been added before + calling this method, invoking the method reruns the application logic associated with the purchase. + + @warning This method is only important to developers who want to preserve purchase states across + different installations of the same app. + */ ++ (void)restore; + +/* + @abstract Returns a content path of the asset of a product, if it was purchased and downloaded. + + @discussion To download and verify purchases use . + + @warning This method will return `nil`, if the purchase wasn't verified or if the asset was not downloaded. + */ ++ (NSString *)assetContentPathForProduct:(PFProduct *)product; + +@end diff --git a/Pods/Parse/PFPush.h b/Pods/Parse/PFPush.h new file mode 100644 index 0000000..a14eeaf --- /dev/null +++ b/Pods/Parse/PFPush.h @@ -0,0 +1,527 @@ +// +// PFPush.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +@class BFTask; +@class PFQuery; + +/*! + The `PFPush` class defines a push notification that can be sent from a client device. + + The preferred way of modifying or retrieving channel subscriptions is to use + the class, instead of the class methods in `PFPush`. + */ +@interface PFPush : NSObject + +///-------------------------------------- +/// @name Creating a Push Notification +///-------------------------------------- + ++ (instancetype)push; + +///-------------------------------------- +/// @name Configuring a Push Notification +///-------------------------------------- + +/*! + @abstract Sets the channel on which this push notification will be sent. + + @param channel The channel to set for this push. + The channel name must start with a letter and contain only letters, numbers, dashes, and underscores. + */ +- (void)setChannel:(NSString *)channel; + +/*! + @abstract Sets the array of channels on which this push notification will be sent. + + @param channels The array of channels to set for this push. + Each channel name must start with a letter and contain only letters, numbers, dashes, and underscores. + */ +- (void)setChannels:(NSArray *)channels; + +/*! + @abstract Sets an installation query to which this push notification will be sent. + + @discussion The query should be created via <[PFInstallation query]> and should not specify a skip, limit, or order. + + @param query The installation query to set for this push. + */ +- (void)setQuery:(PFQuery *)query; + +/*! + @abstract Sets an alert message for this push notification. + + @warning This will overwrite any data specified in setData. + + @param message The message to send in this push. + */ +- (void)setMessage:(NSString *)message; + +/*! + @abstract Sets an arbitrary data payload for this push notification. + + @discussion See the guide for information about the dictionary structure. + + @warning This will overwrite any data specified in setMessage. + + @param data The data to send in this push. + */ +- (void)setData:(NSDictionary *)data; + +/*! + @abstract Sets whether this push will go to Android devices. + + @param pushToAndroid Whether this push will go to Android devices. + + @deprecated Please use a `[PFInstallation query]` with a constraint on deviceType instead. + */ +- (void)setPushToAndroid:(BOOL)pushToAndroid PARSE_DEPRECATED("Please use a [PFInstallation query] with a constraint on deviceType. This method is deprecated and won't do anything."); + +/*! + @abstract Sets whether this push will go to iOS devices. + + @param pushToIOS Whether this push will go to iOS devices. + + @deprecated Please use a `[PFInstallation query]` with a constraint on deviceType instead. + */ +- (void)setPushToIOS:(BOOL)pushToIOS PARSE_DEPRECATED("Please use a [PFInstallation query] with a constraint on deviceType. This method is deprecated and won't do anything."); + +/*! + @abstract Sets the expiration time for this notification. + + @discussion The notification will be sent to devices which are either online + at the time the notification is sent, or which come online before the expiration time is reached. + Because device clocks are not guaranteed to be accurate, + most applications should instead use . + + @see expireAfterTimeInterval: + + @param date The time at which the notification should expire. + */ +- (void)expireAtDate:(NSDate *)date; + +/*! + @abstract Sets the time interval after which this notification should expire. + + @discussion This notification will be sent to devices which are either online at + the time the notification is sent, or which come online within the given + time interval of the notification being received by Parse's server. + An interval which is less than or equal to zero indicates that the + message should only be sent to devices which are currently online. + + @param timeInterval The interval after which the notification should expire. + */ +- (void)expireAfterTimeInterval:(NSTimeInterval)timeInterval; + +/*! + @abstract Clears both expiration values, indicating that the notification should never expire. + */ +- (void)clearExpiration; + +///-------------------------------------- +/// @name Sending Push Notifications +///-------------------------------------- + +/*! + @abstract *Synchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushMessageToChannel:(NSString *)channel + withMessage:(NSString *)message + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message; + +/*! + @abstract *Asynchronously* sends a push message to a channel and calls the given block. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + block:(PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send a push message to a channel. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param message The message to send. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)sendPushMessageToChannelInBackground:(NSString *)channel + withMessage:(NSString *)message + target:(id)target + selector:(SEL)selector; + +/*! + @abstract Send a push message to a query. + + @param query The query to send to. The query must be a query created with <[PFInstallation query]>. + @param message The message to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushMessageToQuery:(PFQuery *)query + withMessage:(NSString *)message + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message to a query. + + @param query The query to send to. The query must be a query created with <[PFInstallation query]>. + @param message The message to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)sendPushMessageToQueryInBackground:(PFQuery *)query + withMessage:(NSString *)message; + +/*! + @abstract *Asynchronously* sends a push message to a query and calls the given block. + + @param query The query to send to. The query must be a PFInstallation query + created with [PFInstallation query]. + @param message The message to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)sendPushMessageToQueryInBackground:(PFQuery *)query + withMessage:(NSString *)message + block:(PFBooleanResultBlock)block; + +/*! + @abstract *Synchronously* send this push message. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the send succeeded. + */ +- (BOOL)sendPush:(NSError **)error; + +/*! + @abstract *Asynchronously* send this push message. + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)sendPushInBackground; + +/*! + @abstract *Asynchronously* send this push message and executes the given callback block. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)sendPushInBackgroundWithBlock:(PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send this push message and calls the given callback. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ +- (void)sendPushInBackgroundWithTarget:(id)target selector:(SEL)selector; + +/*! + @abstract *Synchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushDataToChannel:(NSString *)channel + withData:(NSDictionary *)data + error:(NSError **)error; + +/*! + @abstract *Asynchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data; + +/*! + @abstract Asynchronously sends a push message with arbitrary data to a channel and calls the given block. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + block:(PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* send a push message with arbitrary data to a channel. + + @discussion See the guide for information about the dictionary structure. + + @param channel The channel to send to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param data The data to send. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)sendPushDataToChannelInBackground:(NSString *)channel + withData:(NSDictionary *)data + target:(id)target + selector:(SEL)selector; + +/*! + @abstract *Synchronously* send a push message with arbitrary data to a query. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + @param error Pointer to an NSError that will be set if necessary. + + @returns Returns whether the send succeeded. + */ ++ (BOOL)sendPushDataToQuery:(PFQuery *)query + withData:(NSDictionary *)data + error:(NSError **)error; + +/*! + @abstract Asynchronously send a push message with arbitrary data to a query. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)sendPushDataToQueryInBackground:(PFQuery *)query + withData:(NSDictionary *)data; + +/*! + @abstract *Asynchronously* sends a push message with arbitrary data to a query and calls the given block. + + @discussion See the guide for information about the dictionary structure. + + @param query The query to send to. The query must be a query + created with <[PFInstallation query]>. + @param data The data to send. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)sendPushDataToQueryInBackground:(PFQuery *)query + withData:(NSDictionary *)data + block:(PFBooleanResultBlock)block; + +///-------------------------------------- +/// @name Handling Notifications +///-------------------------------------- + +/*! + @abstract A default handler for push notifications while the app is active that + could be used to mimic the behavior of iOS push notifications while the app is backgrounded or not running. + + @discussion Call this from `application:didReceiveRemoteNotification:`. + If push has a dictionary containing loc-key and loc-args in the alert, + we support up to 10 items in loc-args (`NSRangeException` if limit exceeded). + + @warning This method is available only on iOS. + + @param userInfo The userInfo dictionary you get in `appplication:didReceiveRemoteNotification:`. + */ ++ (void)handlePush:(NSDictionary *)userInfo NS_AVAILABLE_IOS(3_0); + +///-------------------------------------- +/// @name Managing Channel Subscriptions +///-------------------------------------- + +/*! + @abstract Store the device token locally for push notifications. + + @discussion Usually called from you main app delegate's `didRegisterForRemoteNotificationsWithDeviceToken:`. + + @param deviceToken Either as an `NSData` straight from `application:didRegisterForRemoteNotificationsWithDeviceToken:` + or as an `NSString` if you converted it yourself. + */ ++ (void)storeDeviceToken:(id)deviceToken; + +/*! + @abstract *Synchronously* get all the channels that this device is subscribed to. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns an `NSSet` containing all the channel names this device is subscribed to. + */ ++ (NSSet *)getSubscribedChannels:(NSError **)error; + +/*! + @abstract *Asynchronously* get all the channels that this device is subscribed to. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)getSubscribedChannelsInBackground; + +/*! + @abstract *Asynchronously* get all the channels that this device is subscribed to. + @param block The block to execute. + It should have the following argument signature: `^(NSSet *channels, NSError *error)`. + */ ++ (void)getSubscribedChannelsInBackgroundWithBlock:(PFSetResultBlock)block; + +/* + @abstract *Asynchronously* get all the channels that this device is subscribed to. + + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSSet *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + */ ++ (void)getSubscribedChannelsInBackgroundWithTarget:(id)target + selector:(SEL)selector; + +/*! + @abstract *Synchrnously* subscribes the device to a channel of push notifications. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the subscribe succeeded. + */ ++ (BOOL)subscribeToChannel:(NSString *)channel error:(NSError **)error; + +/*! + @abstract *Asynchronously* subscribes the device to a channel of push notifications. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)subscribeToChannelInBackground:(NSString *)channel; + +/*! + @abstract *Asynchronously* subscribes the device to a channel of push notifications and calls the given block. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)` + */ ++ (void)subscribeToChannelInBackground:(NSString *)channel + block:(PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* subscribes the device to a channel of push notifications and calls the given callback. + + @param channel The channel to subscribe to. The channel name must start with + a letter and contain only letters, numbers, dashes, and underscores. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)subscribeToChannelInBackground:(NSString *)channel + target:(id)target + selector:(SEL)selector; + +/*! + @abstract *Synchronously* unsubscribes the device to a channel of push notifications. + + @param channel The channel to unsubscribe from. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns whether the unsubscribe succeeded. + */ ++ (BOOL)unsubscribeFromChannel:(NSString *)channel error:(NSError **)error; + +/*! + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications. + + @param channel The channel to unsubscribe from. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)unsubscribeFromChannelInBackground:(NSString *)channel; + +/*! + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications and calls the given block. + + @param channel The channel to unsubscribe from. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)unsubscribeFromChannelInBackground:(NSString *)channel + block:(PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* unsubscribes the device from a channel of push notifications and calls the given callback. + + @param channel The channel to unsubscribe from. + @param target The object to call selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)unsubscribeFromChannelInBackground:(NSString *)channel + target:(id)target + selector:(SEL)selector; + +@end diff --git a/Pods/Parse/PFQuery.h b/Pods/Parse/PFQuery.h new file mode 100644 index 0000000..97c0946 --- /dev/null +++ b/Pods/Parse/PFQuery.h @@ -0,0 +1,890 @@ +// +// PFQuery.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#import +#else +#import +#import +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + The `PFQuery` class defines a query that is used to query for s. + */ +@interface PFQuery : NSObject + +///-------------------------------------- +/// @name Creating a Query for a Class +///-------------------------------------- + +/*! + @abstract Initializes the query with a class name. + + @param className The class name. + */ +- (instancetype)initWithClassName:(NSString *)className; + +/*! + @abstract Returns a `PFQuery` for a given class. + + @param className The class to query on. + + @returns A `PFQuery` object. + */ ++ (instancetype)queryWithClassName:(NSString *)className; + +/*! + @abstract Creates a PFQuery with the constraints given by predicate. + + @discussion The following types of predicates are supported: + + - Simple comparisons such as `=`, `!=`, `<`, `>`, `<=`, `>=`, and `BETWEEN` with a key and a constant. + - Containment predicates, such as `x IN {1, 2, 3}`. + - Key-existence predicates, such as `x IN SELF`. + - BEGINSWITH expressions. + - Compound predicates with `AND`, `OR`, and `NOT`. + - SubQueries with `key IN %@`, subquery. + + The following types of predicates are NOT supported: + + - Aggregate operations, such as `ANY`, `SOME`, `ALL`, or `NONE`. + - Regular expressions, such as `LIKE`, `MATCHES`, `CONTAINS`, or `ENDSWITH`. + - Predicates comparing one key to another. + - Complex predicates with many ORed clauses. + + @param className The class to query on. + @param predicate The predicate to create conditions from. + */ ++ (instancetype)queryWithClassName:(NSString *)className predicate:(PF_NULLABLE NSPredicate *)predicate; + +/*! + The class name to query for. + */ +@property (nonatomic, strong) NSString *parseClassName; + +///-------------------------------------- +/// @name Adding Basic Constraints +///-------------------------------------- + +/*! + @abstract Make the query include PFObjects that have a reference stored at the provided key. + + @discussion This has an effect similar to a join. You can use dot notation to specify which fields in + the included object are also fetch. + + @param key The key to load child s for. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)includeKey:(NSString *)key; + +/*! + @abstract Make the query restrict the fields of the returned s to include only the provided keys. + + @discussion If this is called multiple times, then all of the keys specified in each of the calls will be included. + + @param keys The keys to include in the result. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)selectKeys:(NSArray *)keys; + +/*! + @abstract Add a constraint that requires a particular key exists. + + @param key The key that should exist. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKeyExists:(NSString *)key; + +/*! + @abstract Add a constraint that requires a key not exist. + + @param key The key that should not exist. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKeyDoesNotExist:(NSString *)key; + +/*! + @abstract Add a constraint to the query that requires a particular key's object to be equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key equalTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object to be less than the provided object. + + @param key The key to be constrained. + @param object The object that provides an upper bound. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key lessThan:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be less than or equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key lessThanOrEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be greater than the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key greaterThan:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's + object to be greater than or equal to the provided object. + + @param key The key to be constrained. + @param object The object that must be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key greaterThanOrEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be not equal to the provided object. + + @param key The key to be constrained. + @param object The object that must not be equalled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key notEqualTo:(id)object; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + to be contained in the provided array. + + @param key The key to be constrained. + @param array The possible values for the key's object. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containedIn:(NSArray *)array; + +/*! + @abstract Add a constraint to the query that requires a particular key's object + not be contained in the provided array. + + @param key The key to be constrained. + @param array The list of values the key's object should not be. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key notContainedIn:(NSArray *)array; + +/*! + @abstract Add a constraint to the query that requires a particular key's array + contains every element of the provided array. + + @param key The key to be constrained. + @param array The array of values to search for. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containsAllObjectsInArray:(NSArray *)array; + +///-------------------------------------- +/// @name Adding Location Constraints +///-------------------------------------- + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point. + + @discussion Distance is calculated based on angular distance on a sphere. Results will be sorted by distance + from reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key nearGeoPoint:(PFGeoPoint *)geopoint; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point and within the maximum distance specified (in miles). + + @discussion Distance is calculated based on a spherical coordinate system. + Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + @param maxDistance Maximum distance in miles. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinMiles:(double)maxDistance; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) + be near a reference point and within the maximum distance specified (in kilometers). + + @discussion Distance is calculated based on a spherical coordinate system. + Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point represented as a . + @param maxDistance Maximum distance in kilometers. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinKilometers:(double)maxDistance; + +/*! + Add a constraint to the query that requires a particular key's coordinates (specified via ) be near + a reference point and within the maximum distance specified (in radians). Distance is calculated based on + angular distance on a sphere. Results will be sorted by distance (nearest to farthest) from the reference point. + + @param key The key to be constrained. + @param geopoint The reference point as a . + @param maxDistance Maximum distance in radians. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + nearGeoPoint:(PFGeoPoint *)geopoint + withinRadians:(double)maxDistance; + +/*! + @abstract Add a constraint to the query that requires a particular key's coordinates (specified via ) be + contained within a given rectangular geographic bounding box. + + @param key The key to be constrained. + @param southwest The lower-left inclusive corner of the box. + @param northeast The upper-right inclusive corner of the box. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key withinGeoBoxFromSouthwest:(PFGeoPoint *)southwest toNortheast:(PFGeoPoint *)northeast; + +///-------------------------------------- +/// @name Adding String Constraints +///-------------------------------------- + +/*! + @abstract Add a regular expression constraint for finding string values that match the provided regular expression. + + @warning This may be slow for large datasets. + + @param key The key that the string to match is stored in. + @param regex The regular expression pattern to match. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key matchesRegex:(NSString *)regex; + +/*! + @abstract Add a regular expression constraint for finding string values that match the provided regular expression. + + @warning This may be slow for large datasets. + + @param key The key that the string to match is stored in. + @param regex The regular expression pattern to match. + @param modifiers Any of the following supported PCRE modifiers: + - `i` - Case insensitive search + - `m` - Search across multiple lines of input + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + matchesRegex:(NSString *)regex + modifiers:(PF_NULLABLE NSString *)modifiers; + +/*! + @abstract Add a constraint for finding string values that contain a provided substring. + + @warning This will be slow for large datasets. + + @param key The key that the string to match is stored in. + @param substring The substring that the value must contain. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key containsString:(PF_NULLABLE NSString *)substring; + +/*! + @abstract Add a constraint for finding string values that start with a provided prefix. + + @discussion This will use smart indexing, so it will be fast for large datasets. + + @param key The key that the string to match is stored in. + @param prefix The substring that the value must start with. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key hasPrefix:(PF_NULLABLE NSString *)prefix; + +/*! + @abstract Add a constraint for finding string values that end with a provided suffix. + + @warning This will be slow for large datasets. + + @param key The key that the string to match is stored in. + @param suffix The substring that the value must end with. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key hasSuffix:(PF_NULLABLE NSString *)suffix; + +///-------------------------------------- +/// @name Adding Subqueries +///-------------------------------------- + +/*! + Returns a `PFQuery` that is the `or` of the passed in queries. + + @param queries The list of queries to or together. + + @returns An instance of `PFQuery` that is the `or` of the passed in queries. + */ ++ (instancetype)orQueryWithSubqueries:(NSArray *)queries; + +/*! + @abstract Adds a constraint that requires that a key's value matches a value in another key + in objects returned by a sub query. + + @param key The key that the value is stored. + @param otherKey The key in objects in the returned by the sub query whose value should match. + @param query The query to run. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + matchesKey:(NSString *)otherKey + inQuery:(PFQuery *)query; + +/*! + @abstract Adds a constraint that requires that a key's value `NOT` match a value in another key + in objects returned by a sub query. + + @param key The key that the value is stored. + @param otherKey The key in objects in the returned by the sub query whose value should match. + @param query The query to run. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key + doesNotMatchKey:(NSString *)otherKey + inQuery:(PFQuery *)query; + +/*! + @abstract Add a constraint that requires that a key's value matches a `PFQuery` constraint. + + @warning This only works where the key's values are s or arrays of s. + + @param key The key that the value is stored in + @param query The query the value should match + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key matchesQuery:(PFQuery *)query; + +/*! + @abstract Add a constraint that requires that a key's value to not match a `PFQuery` constraint. + + @warning This only works where the key's values are s or arrays of s. + + @param key The key that the value is stored in + @param query The query the value should not match + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key doesNotMatchQuery:(PFQuery *)query; + +///-------------------------------------- +/// @name Sorting +///-------------------------------------- + +/*! + @abstract Sort the results in *ascending* order with the given key. + + @param key The key to order by. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderByAscending:(NSString *)key; + +/*! + @abstract Additionally sort in *ascending* order by the given key. + + @discussion The previous keys provided will precedence over this key. + + @param key The key to order by. + */ +- (instancetype)addAscendingOrder:(NSString *)key; + +/*! + @abstract Sort the results in *descending* order with the given key. + + @param key The key to order by. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderByDescending:(NSString *)key; + +/*! + @abstract Additionally sort in *descending* order by the given key. + + @discussion The previous keys provided will precedence over this key. + + @param key The key to order by. + */ +- (instancetype)addDescendingOrder:(NSString *)key; + +/*! + @abstract Sort the results using a given sort descriptor. + + @warning If a `sortDescriptor` has custom `selector` or `comparator` - they aren't going to be used. + + @param sortDescriptor The `NSSortDescriptor` to use to sort the results of the query. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderBySortDescriptor:(NSSortDescriptor *)sortDescriptor; + +/*! + @abstract Sort the results using a given array of sort descriptors. + + @warning If a `sortDescriptor` has custom `selector` or `comparator` - they aren't going to be used. + + @param sortDescriptors An array of `NSSortDescriptor` objects to use to sort the results of the query. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)orderBySortDescriptors:(PF_NULLABLE NSArray *)sortDescriptors; + +///-------------------------------------- +/// @name Getting Objects by ID +///-------------------------------------- + +/*! + @abstract Returns a with a given class and id. + + @param objectClass The class name for the object that is being requested. + @param objectId The id of the object that is being requested. + + @returns The if found. Returns `nil` if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFObject *)getObjectOfClass:(NSString *)objectClass objectId:(NSString *)objectId; + +/*! + @abstract Returns a with a given class and id and sets an error if necessary. + + @param objectClass The class name for the object that is being requested. + @param objectId The id of the object that is being requested. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The if found. Returns `nil` if the object isn't found, or if there was an `error`. + */ ++ (PF_NULLABLE PFObject *)getObjectOfClass:(NSString *)objectClass + objectId:(NSString *)objectId + error:(NSError **)error; + +/*! + @abstract Returns a with the given id. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + + @returns The if found. Returns nil if the object isn't found, or if there was an error. + */ +- (PF_NULLABLE PFObject *)getObjectWithId:(NSString *)objectId; + +/*! + @abstract Returns a with the given id and sets an error if necessary. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + @param error Pointer to an `NSError` that will be set if necessary. + + @returns The if found. Returns nil if the object isn't found, or if there was an error. + */ +- (PF_NULLABLE PFObject *)getObjectWithId:(NSString *)objectId error:(NSError **)error; + +/*! + @abstract Gets a asynchronously and calls the given block with the result. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getObjectInBackgroundWithId:(NSString *)objectId; + +/*! + @abstract Gets a asynchronously and calls the given block with the result. + + @warning This method mutates the query. + It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object that is being requested. + @param block The block to execute. + The block should have the following argument signature: `^(NSArray *object, NSError *error)` + */ +- (void)getObjectInBackgroundWithId:(NSString *)objectId + block:(PF_NULLABLE PFObjectResultBlock)block; + +/* + @abstract Gets a asynchronously. + + This mutates the PFQuery. It will reset limit to `1`, skip to `0` and remove all conditions, leaving only `objectId`. + + @param objectId The id of the object being requested. + @param target The target for the callback selector. + @param selector The selector for the callback. + It should have the following signature: `(void)callbackWithResult:(id)result error:(NSError *)error`. + Result will be `nil` if error is set and vice versa. + */ +- (void)getObjectInBackgroundWithId:(NSString *)objectId + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting User Objects +///-------------------------------------- + +/*! + @abstract Returns a with a given id. + + @param objectId The id of the object that is being requested. + + @returns The PFUser if found. Returns nil if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFUser *)getUserObjectWithId:(NSString *)objectId; + +/*! + Returns a PFUser with a given class and id and sets an error if necessary. + @param objectId The id of the object that is being requested. + @param error Pointer to an NSError that will be set if necessary. + @result The PFUser if found. Returns nil if the object isn't found, or if there was an error. + */ ++ (PF_NULLABLE PFUser *)getUserObjectWithId:(NSString *)objectId + error:(NSError **)error; + +/*! + @deprecated Please use [PFUser query] instead. + */ ++ (instancetype)queryForUser PARSE_DEPRECATED("Use [PFUser query] instead."); + +///-------------------------------------- +/// @name Getting all Matches for a Query +///-------------------------------------- + +/*! + @abstract Finds objects *synchronously* based on the constructed query. + + @returns Returns an array of objects that were found. + */ +- (PF_NULLABLE NSArray *)findObjects; + +/*! + @abstract Finds objects *synchronously* based on the constructed query and sets an error if there was one. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns an array of objects that were found. + */ +- (PF_NULLABLE NSArray *)findObjects:(NSError **)error; + +/*! + @abstract Finds objects *asynchronously* and sets the `NSArray` of objects as a result of the task. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)findObjectsInBackground; + +/*! + @abstract Finds objects *asynchronously* and calls the given block with the results. + + @param block The block to execute. + It should have the following argument signature: `^(NSArray *objects, NSError *error)` + */ +- (void)findObjectsInBackgroundWithBlock:(PF_NULLABLE PFArrayResultBlock)block; + +/* + @abstract Finds objects *asynchronously* and calls the given callback with the results. + + @param target The object to call the selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(id)result error:(NSError *)error`. + Result will be `nil` if error is set and vice versa. + */ +- (void)findObjectsInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Getting the First Match in a Query +///-------------------------------------- + +/*! + @abstract Gets an object *synchronously* based on the constructed query. + + @warning This method mutates the query. It will reset the limit to `1`. + + @returns Returns a , or `nil` if none was found. + */ +- (PF_NULLABLE PFObject *)getFirstObject; + +/*! + @abstract Gets an object *synchronously* based on the constructed query and sets an error if any occurred. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns a , or `nil` if none was found. + */ +- (PF_NULLABLE PFObject *)getFirstObject:(NSError **)error; + +/*! + @abstract Gets an object *asynchronously* and sets it as a result of the task. + + @warning This method mutates the query. It will reset the limit to `1`. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)getFirstObjectInBackground; + +/*! + @abstract Gets an object *asynchronously* and calls the given block with the result. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param block The block to execute. + It should have the following argument signature: `^(PFObject *object, NSError *error)`. + `result` will be `nil` if `error` is set OR no object was found matching the query. + `error` will be `nil` if `result` is set OR if the query succeeded, but found no results. + */ +- (void)getFirstObjectInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block; + +/* + @abstract Gets an object *asynchronously* and calls the given callback with the results. + + @warning This method mutates the query. It will reset the limit to `1`. + + @param target The object to call the selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(PFObject *)result error:(NSError *)error`. + `result` will be `nil` if `error` is set OR no object was found matching the query. + `error` will be `nil` if `result` is set OR if the query succeeded, but found no results. + */ +- (void)getFirstObjectInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Counting the Matches in a Query +///-------------------------------------- + +/*! + @abstract Counts objects *synchronously* based on the constructed query. + + @returns Returns the number of objects that match the query, or `-1` if there is an error. + */ +- (NSInteger)countObjects; + +/*! + @abstract Counts objects *synchronously* based on the constructed query and sets an error if there was one. + + @param error Pointer to an `NSError` that will be set if necessary. + + @returns Returns the number of objects that match the query, or `-1` if there is an error. + */ +- (NSInteger)countObjects:(NSError **)error; + +/*! + @abstract Counts objects *asynchronously* and sets `NSNumber` with count as a result of the task. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)countObjectsInBackground; + +/*! + @abstract Counts objects *asynchronously* and calls the given block with the counts. + + @param block The block to execute. + It should have the following argument signature: `^(int count, NSError *error)` + */ +- (void)countObjectsInBackgroundWithBlock:(PF_NULLABLE PFIntegerResultBlock)block; + +/* + @abstract Counts objects *asynchronously* and calls the given callback with the count. + + @param target The object to call the selector on. + @param selector The selector to call. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + */ +- (void)countObjectsInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Cancelling a Query +///-------------------------------------- + +/*! + @abstract Cancels the current network request (if any). Ensures that callbacks won't be called. + */ +- (void)cancel; + +///-------------------------------------- +/// @name Paginating Results +///-------------------------------------- + +/*! + @abstract A limit on the number of objects to return. The default limit is `100`, with a + maximum of 1000 results being returned at a time. + + @warning If you are calling `findObjects` with `limit = 1`, you may find it easier to use `getFirst` instead. + */ +@property (nonatomic, assign) NSInteger limit; + +/*! + @abstract The number of objects to skip before returning any. + */ +@property (nonatomic, assign) NSInteger skip; + +///-------------------------------------- +/// @name Controlling Caching Behavior +///-------------------------------------- + +/*! + @abstract The cache policy to use for requests. + + Not allowed when Pinning is enabled. + + @see fromLocalDatastore + @see fromPin + @see fromPinWithName: + */ +@property (assign, readwrite) PFCachePolicy cachePolicy; + +/* ! + @abstract The age after which a cached value will be ignored + */ +@property (assign, readwrite) NSTimeInterval maxCacheAge; + +/*! + @abstract Returns whether there is a cached result for this query. + + @result `YES` if there is a cached result for this query, otherwise `NO`. + */ +- (BOOL)hasCachedResult; + +/*! + @abstract Clears the cached result for this query. If there is no cached result, this is a noop. + */ +- (void)clearCachedResult; + +/*! + @abstract Clears the cached results for all queries. + */ ++ (void)clearAllCachedResults; + +///-------------------------------------- +/// @name Query Source +///-------------------------------------- + +/*! + @abstract Change the source of this query to all pinned objects. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see cachePolicy + */ +- (instancetype)fromLocalDatastore; + +/*! + @abstract Change the source of this query to the default group of pinned objects. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see PFObjectDefaultPin + @see cachePolicy + */ +- (instancetype)fromPin; + +/*! + @abstract Change the source of this query to a specific group of pinned objects. + + @warning Requires Local Datastore to be enabled. + + @param name The pinned group. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + + @see PFObjectDefaultPin + @see cachePolicy + */ +- (instancetype)fromPinWithName:(PF_NULLABLE NSString *)name; + +/*! + @abstract Ignore ACLs when querying from the Local Datastore. + + @discussion This is particularly useful when querying for objects with Role based ACLs set on them. + + @warning Requires Local Datastore to be enabled. + + @returns The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)ignoreACLs; + +///-------------------------------------- +/// @name Advanced Settings +///-------------------------------------- + +/*! + @abstract Whether or not performance tracing should be done on the query. + + @warning This should not be set to `YES` in most cases. + */ +@property (nonatomic, assign) BOOL trace; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFRelation.h b/Pods/Parse/PFRelation.h new file mode 100644 index 0000000..cbc182d --- /dev/null +++ b/Pods/Parse/PFRelation.h @@ -0,0 +1,61 @@ +// +// PFRelation.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFRelation` class that is used to access all of the children of a many-to-many relationship. + Each instance of `PFRelation` is associated with a particular parent object and key. + */ +@interface PFRelation : NSObject + +/*! + @abstract The name of the class of the target child objects. + */ +@property (nonatomic, strong) NSString *targetClass; + +///-------------------------------------- +/// @name Accessing Objects +///-------------------------------------- + +/*! + @abstract Returns a object that can be used to get objects in this relation. + */ +- (PF_NULLABLE PFQuery *)query; + +///-------------------------------------- +/// @name Modifying Relations +///-------------------------------------- + +/*! + @abstract Adds a relation to the passed in object. + + @param object A object to add relation to. + */ +- (void)addObject:(PFObject *)object; + +/*! + @abstract Removes a relation to the passed in object. + + @param object A object to add relation to. + */ +- (void)removeObject:(PFObject *)object; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFRole.h b/Pods/Parse/PFRole.h new file mode 100644 index 0000000..effc7de --- /dev/null +++ b/Pods/Parse/PFRole.h @@ -0,0 +1,103 @@ +// +// PFRole.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `PFRole` class represents a Role on the Parse server. + `PFRoles` represent groupings of objects for the purposes of granting permissions + (e.g. specifying a for a ). + Roles are specified by their sets of child users and child roles, + all of which are granted any permissions that the parent role has. + + Roles must have a name (which cannot be changed after creation of the role), and must specify an ACL. + */ +@interface PFRole : PFObject + +///-------------------------------------- +/// @name Creating a New Role +///-------------------------------------- + +/*! + @abstract Constructs a new `PFRole` with the given name. + If no default ACL has been specified, you must provide an ACL for the role. + + @param name The name of the Role to create. + */ +- (instancetype)initWithName:(NSString *)name; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @param name The name of the Role to create. + @param acl The ACL for this role. Roles must have an ACL. + */ +- (instancetype)initWithName:(NSString *)name acl:(PF_NULLABLE PFACL *)acl; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @discussion If no default ACL has been specified, you must provide an ACL for the role. + + @param name The name of the Role to create. + */ ++ (instancetype)roleWithName:(NSString *)name; + +/*! + @abstract Constructs a new `PFRole` with the given name. + + @param name The name of the Role to create. + @param acl The ACL for this role. Roles must have an ACL. + */ ++ (instancetype)roleWithName:(NSString *)name acl:(PF_NULLABLE PFACL *)acl; + +///-------------------------------------- +/// @name Role-specific Properties +///-------------------------------------- + +/*! + @abstract Gets or sets the name for a role. + + @discussion This value must be set before the role has been saved to the server, + and cannot be set once the role has been saved. + + @warning A role's name can only contain alphanumeric characters, `_`, `-`, and spaces. + */ +@property (nonatomic, copy) NSString *name; + +/*! + @abstract Gets the for the objects that are direct children of this role. + + @discussion These users are granted any privileges that this role has been granted + (e.g. read or write access through ACLs). You can add or remove users from + the role through this relation. + */ +@property (nonatomic, strong, readonly) PFRelation *users; + +/*! + @abstract Gets the for the `PFRole` objects that are direct children of this role. + + @discussion These roles' users are granted any privileges that this role has been granted + (e.g. read or write access through ACLs). You can add or remove child roles + from this role through this relation. + */ +@property (nonatomic, strong, readonly) PFRelation *roles; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFSession.h b/Pods/Parse/PFSession.h new file mode 100644 index 0000000..81247fd --- /dev/null +++ b/Pods/Parse/PFSession.h @@ -0,0 +1,52 @@ +// +// PFSession.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#else +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +@class PFSession; + +typedef void(^PFSessionResultBlock)(PFSession *PF_NULLABLE_S session, NSError *PF_NULLABLE_S error); + +/*! + `PFSession` is a local representation of a session. + This class is a subclass of a , + and retains the same functionality as any other subclass of . + */ +@interface PFSession : PFObject + +/*! + @abstract The session token string for this session. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *sessionToken; + +/*! + *Asynchronously* fetches a `PFSession` object related to the current user. + + @returns A task that is `completed` with an instance of `PFSession` class or is `faulted` if the operation fails. + */ ++ (BFTask *)getCurrentSessionInBackground; + +/*! + *Asynchronously* fetches a `PFSession` object related to the current user. + + @param block The block to execute when the operation completes. + It should have the following argument signature: `^(PFSession *session, NSError *error)`. + */ ++ (void)getCurrentSessionInBackgroundWithBlock:(PF_NULLABLE PFSessionResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFSubclassing.h b/Pods/Parse/PFSubclassing.h new file mode 100644 index 0000000..1c21841 --- /dev/null +++ b/Pods/Parse/PFSubclassing.h @@ -0,0 +1,88 @@ +// +// PFSubclassing.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +@class PFQuery; + +PF_ASSUME_NONNULL_BEGIN + +/*! + If a subclass of conforms to `PFSubclassing` and calls , + Parse framework will be able to use that class as the native class for a Parse cloud object. + + Classes conforming to this protocol should subclass and + include `PFObject+Subclass.h` in their implementation file. + This ensures the methods in the Subclass category of are exposed in its subclasses only. + */ +@protocol PFSubclassing + +/*! + @abstract Constructs an object of the most specific class known to implement . + + @discussion This method takes care to help subclasses be subclassed themselves. + For example, `[PFUser object]` returns a by default but will return an + object of a registered subclass instead if one is known. + A default implementation is provided by which should always be sufficient. + + @returns Returns the object that is instantiated. + */ ++ (instancetype)object; + +/*! + @abstract Creates a reference to an existing PFObject for use in creating associations between PFObjects. + + @discussion Calling <[PFObject isDataAvailable]> on this object will return `NO` + until <[PFObject fetchIfNeeded]> has been called. No network request will be made. + A default implementation is provided by PFObject which should always be sufficient. + + @param objectId The object id for the referenced object. + + @returns A new without data. + */ ++ (instancetype)objectWithoutDataWithObjectId:(PF_NULLABLE NSString *)objectId; + +/*! + @abstract The name of the class as seen in the REST API. + */ ++ (NSString *)parseClassName; + +/*! + @abstract Create a query which returns objects of this type. + + @discussion A default implementation is provided by which should always be sufficient. + */ ++ (PF_NULLABLE PFQuery *)query; + +/*! + @abstract Returns a query for objects of this type with a given predicate. + + @discussion A default implementation is provided by which should always be sufficient. + + @param predicate The predicate to create conditions from. + + @returns An instance of . + + @see [PFQuery queryWithClassName:predicate:] + */ ++ (PF_NULLABLE PFQuery *)queryWithPredicate:(PF_NULLABLE NSPredicate *)predicate; + +/*! + @abstract Lets Parse know this class should be used to instantiate all objects with class type . + + @warning This method must be called before <[Parse setApplicationId:clientKey:]> + */ ++ (void)registerSubclass; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFTwitterUtils.h b/Pods/Parse/PFTwitterUtils.h new file mode 100644 index 0000000..37f4de2 --- /dev/null +++ b/Pods/Parse/PFTwitterUtils.h @@ -0,0 +1,323 @@ +// +// PFTwitterUtils.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#import +#import +#import + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + The `PFTwitterUtils` class provides utility functions for working with Twitter in a Parse application. + + This class is currently for iOS only. + */ +@interface PFTwitterUtils : NSObject + +///-------------------------------------- +/// @name Interacting With Twitter +///-------------------------------------- + +/*! + @abstract Gets the instance of the object that Parse uses. + + @returns An instance of object. + */ ++ (PF_NULLABLE PF_Twitter *)twitter; + +/*! + @abstract Initializes the Twitter singleton. + + @warning You must invoke this in order to use the Twitter functionality in Parse. + + @param consumerKey Your Twitter application's consumer key. + @param consumerSecret Your Twitter application's consumer secret. + */ ++ (void)initializeWithConsumerKey:(NSString *)consumerKey + consumerSecret:(NSString *)consumerSecret; + +/*! + @abstract Whether the user has their account linked to Twitter. + + @param user User to check for a Twitter link. The user must be logged in on this device. + + @returns `YES` if the user has their account linked to Twitter, otherwise `NO`. + */ ++ (BOOL)isLinkedWithUser:(PF_NULLABLE PFUser *)user; + +///-------------------------------------- +/// @name Logging In & Creating Twitter-Linked Users +///-------------------------------------- + +/*! + @abstract *Asynchronously* logs in a user using Twitter. + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically logs in (or creates, in the case where it is a new user) a . + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)logInInBackground; + +/*! + @abstract *Asynchronously* logs in a user using Twitter. + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically logs in (or creates, in the case where it is a new user) . + + @param block The block to execute. + It should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)logInWithBlock:(PF_NULLABLE PFUserResultBlock)block; + +/* + @abstract *Asynchronously* Logs in a user using Twitter. + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically logs in (or creates, in the case where it is a new user) a . + + @param target Target object for the selector + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError **)error`. + */ ++ (void)logInWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract *Asynchronously* logs in a user using Twitter. + + @discussion Allows you to handle user login to Twitter, then provide authentication + data to log in (or create, in the case where it is a new user) the . + + @param twitterId The id of the Twitter user being linked. + @param screenName The screen name of the Twitter user being linked. + @param authToken The auth token for the user's session. + @param authTokenSecret The auth token secret for the user's session. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)logInWithTwitterIdInBackground:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret; + +/*! + @abstract Logs in a user using Twitter. + + @discussion Allows you to handle user login to Twitter, then provide authentication data + to log in (or create, in the case where it is a new user) the . + + @param twitterId The id of the Twitter user being linked + @param screenName The screen name of the Twitter user being linked + @param authToken The auth token for the user's session + @param authTokenSecret The auth token secret for the user's session + @param block The block to execute. + It should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)logInWithTwitterId:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret + block:(PF_NULLABLE PFUserResultBlock)block; + +/* + @abstract Logs in a user using Twitter. + + @discussion Allows you to handle user login to Twitter, then provide authentication data + to log in (or create, in the case where it is a new user) the . + + @param twitterId The id of the Twitter user being linked. + @param screenName The screen name of the Twitter user being linked. + @param authToken The auth token for the user's session. + @param authTokenSecret The auth token secret for the user's session. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchronous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)logInWithTwitterId:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Linking Users with Twitter +///-------------------------------------- + +/*! + @abstract *Asynchronously* links Twitter to an existing PFUser. + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically links the account to the . + + @param user User to link to Twitter. + + @deprecated Please use `[PFTwitterUtils linkUserInBackground:]` instead. + */ ++ (void)linkUser:(PFUser *)user PARSE_DEPRECATED("Please use +linkUserInBackground: instead."); + +/*! + @abstract *Asynchronously* links Twitter to an existing . + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically links the account to the . + + @param user User to link to Twitter. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)linkUserInBackground:(PFUser *)user; + +/*! + @abstract *Asynchronously* links Twitter to an existing . + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically links the account to the . + + @param user User to link to Twitter. + @param block The block to execute. + It should have the following argument signature: `^(BOOL success, NSError *error)`. + */ ++ (void)linkUser:(PFUser *)user block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract *Asynchronously* links Twitter to an existing . + + @discussion This method delegates to Twitter to authenticate the user, + and then automatically links the account to the . + + @param user User to link to Twitter. + @param target Target object for the selector + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + */ ++ (void)linkUser:(PFUser *)user + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract *Asynchronously* links Twitter to an existing PFUser asynchronously. + + @discussion Allows you to handle user login to Twitter, + then provide authentication data to link the account to the . + + @param user User to link to Twitter. + @param twitterId The id of the Twitter user being linked. + @param screenName The screen name of the Twitter user being linked. + @param authToken The auth token for the user's session. + @param authTokenSecret The auth token secret for the user's session. + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)linkUserInBackground:(PFUser *)user + twitterId:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret; + +/*! + @abstract *Asynchronously* links Twitter to an existing . + + @discussionAllows you to handle user login to Twitter, + then provide authentication data to link the account to the . + + @param user User to link to Twitter. + @param twitterId The id of the Twitter user being linked. + @param screenName The screen name of the Twitter user being linked. + @param authToken The auth token for the user's session. + @param authTokenSecret The auth token secret for the user's session. + @param block The block to execute. + It should have the following argument signature: `^(BOOL success, NSError *error)`. + */ ++ (void)linkUser:(PFUser *)user + twitterId:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Links Twitter to an existing . + + @discussion This method allows you to handle user login to Twitter, + then provide authentication data to link the account to the . + + @param user User to link to Twitter. + @param twitterId The id of the Twitter user being linked. + @param screenName The screen name of the Twitter user being linked. + @param authToken The auth token for the user's session. + @param authTokenSecret The auth token secret for the user's session. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchronous request is complete. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + */ ++ (void)linkUser:(PFUser *)user + twitterId:(NSString *)twitterId + screenName:(NSString *)screenName + authToken:(NSString *)authToken + authTokenSecret:(NSString *)authTokenSecret + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Unlinking Users from Twitter +///-------------------------------------- + +/*! + @abstract *Synchronously* unlinks the from a Twitter account. + + @param user User to unlink from Twitter. + + @returns Returns true if the unlink was successful. + */ ++ (BOOL)unlinkUser:(PFUser *)user; + +/*! + @abstract *Synchronously* unlinks the PFUser from a Twitter account. + + @param user User to unlink from Twitter. + @param error Error object to set on error. + + @returns Returns `YES` if the unlink was successful, otherwise `NO`. + */ ++ (BOOL)unlinkUser:(PFUser *)user error:(NSError **)error; + +/*! + @abstract Makes an *asynchronous* request to unlink a user from a Twitter account. + + @param user User to unlink from Twitter. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)unlinkUserInBackground:(PFUser *)user; + +/*! + @abstract Makes an *asynchronous* request to unlink a user from a Twitter account. + + @param user User to unlink from Twitter. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)unlinkUserInBackground:(PFUser *)user + block:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Makes an *asynchronous* request to unlink a user from a Twitter account. + + @param user User to unlink from Twitter + @param target Target object for the selector + @param selector The selector that will be called when the asynchrounous request is complete. + */ ++ (void)unlinkUserInBackground:(PFUser *)user + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PFUser.h b/Pods/Parse/PFUser.h new file mode 100644 index 0000000..0f66b2d --- /dev/null +++ b/Pods/Parse/PFUser.h @@ -0,0 +1,455 @@ +// +// PFUser.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#import +#endif + +PF_ASSUME_NONNULL_BEGIN + +typedef void(^PFUserSessionUpgradeResultBlock)(NSError *PF_NULLABLE_S error); +typedef void(^PFUserLogoutResultBlock)(NSError *PF_NULLABLE_S error); + + +@class PFQuery; + +/*! + The `PFUser` class is a local representation of a user persisted to the Parse Data. + This class is a subclass of a , and retains the same functionality of a , + but also extends it with various user specific methods, like authentication, signing up, and validation uniqueness. + + Many APIs responsible for linking a `PFUser` with Facebook or Twitter have been deprecated in favor of dedicated + utilities for each social network. See , and for more information. + */ + +@interface PFUser : PFObject + +///-------------------------------------- +/// @name Accessing the Current User +///-------------------------------------- + +/*! + @abstract Gets the currently logged in user from disk and returns an instance of it. + + @returns Returns a `PFUser` that is the currently logged in user. If there is none, returns `nil`. + */ ++ (PF_NULLABLE instancetype)currentUser; + +/*! + @abstract The session token for the `PFUser`. + + @discussion This is set by the server upon successful authentication. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *sessionToken; + +/*! + @abstract Whether the `PFUser` was just created from a request. + + @discussion This is only set after a Facebook or Twitter login. + */ +@property (assign, readonly) BOOL isNew; + +/*! + @abstract Whether the user is an authenticated object for the device. + + @discussion An authenticated `PFUser` is one that is obtained via a or method. + An authenticated object is required in order to save (with altered values) or delete it. + + @returns Returns whether the user is authenticated. + */ +- (BOOL)isAuthenticated; + +///-------------------------------------- +/// @name Creating a New User +///-------------------------------------- + +/*! + @abstract Creates a new `PFUser` object. + + @returns Returns a new `PFUser` object. + */ ++ (PFUser *)user; + +/*! + @abstract Enables automatic creation of anonymous users. + + @discussion After calling this method, will always have a value. + The user will only be created on the server once the user has been saved, + or once an object with a relation to that user or an ACL that refers to the user has been saved. + + @warning <[PFObject saveEventually]> will not work on if an item being saved has a relation + to an automatic user that has never been saved. + */ ++ (void)enableAutomaticUser; + +/*! + @abstract The username for the `PFUser`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *username; + +/**! + @abstract The password for the `PFUser`. + + @discussion This will not be filled in from the server with the password. + It is only meant to be set. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *password; + +/*! + @abstract The email for the `PFUser`. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *email; + +/*! + @abstract Signs up the user *synchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @returns Returns `YES` if the sign up was successful, otherwise `NO`. + */ +- (BOOL)signUp; + +/*! + @abstract Signs up the user *synchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param error Error object to set on error. + + @returns Returns whether the sign up was successful. + */ +- (BOOL)signUp:(NSError **)error; + +/*! + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)signUpInBackground; + +/*! + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ +- (void)signUpInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block; + +/* + @abstract Signs up the user *asynchronously*. + + @discussion This will also enforce that the username isn't already taken. + + @warning Make sure that password and username are set before calling this method. + + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ +- (void)signUpInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector; + +///-------------------------------------- +/// @name Logging In +///-------------------------------------- + +/*! + @abstract Makes a *synchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + + @returns Returns an instance of the `PFUser` on success. + If login failed for either wrong password or wrong username, returns `nil`. + */ ++ (PF_NULLABLE instancetype)logInWithUsername:(NSString *)username + password:(NSString *)password; + +/*! + @abstract Makes a *synchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param error The error object to set on error. + + @returns Returns an instance of the `PFUser` on success. + If login failed for either wrong password or wrong username, returns `nil`. + */ ++ (PF_NULLABLE instancetype)logInWithUsername:(NSString *)username + password:(NSString *)password + error:(NSError **)error; + +/*! + @abstract Makes an *asynchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password; + +/* + @abstract Makes an *asynchronous* request to login a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Makes an *asynchronous* request to log in a user with specified credentials. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param username The username of the user. + @param password The password of the user. + @param block The block to execute. + It should have the following argument signature: `^(PFUser *user, NSError *error)`. + */ ++ (void)logInWithUsernameInBackground:(NSString *)username + password:(NSString *)password + block:(PF_NULLABLE PFUserResultBlock)block; + +///-------------------------------------- +/// @name Becoming a User +///-------------------------------------- + +/*! + @abstract Makes a *synchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + + @returns Returns an instance of the `PFUser` on success. + If becoming a user fails due to incorrect token, it returns `nil`. + */ ++ (PF_NULLABLE instancetype)become:(NSString *)sessionToken; + +/*! + @abstract Makes a *synchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This will also cache the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param error The error object to set on error. + + @returns Returns an instance of the `PFUser` on success. + If becoming a user fails due to incorrect token, it returns `nil`. + */ ++ (PF_NULLABLE instancetype)become:(NSString *)sessionToken error:(NSError **)error; + +/*! + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. + This also caches the user locally so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)becomeInBackground:(NSString *)sessionToken; + +/* + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. This also caches the user locally + so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchrounous request is complete. + It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`. + */ ++ (void)becomeInBackground:(NSString *)sessionToken + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Makes an *asynchronous* request to become a user with the given session token. + + @discussion Returns an instance of the successfully logged in `PFUser`. This also caches the user locally + so that calls to will use the latest logged in user. + + @param sessionToken The session token for the user. + @param block The block to execute. The block should have the following argument signature: (PFUser *user, NSError *error) + */ ++ (void)becomeInBackground:(NSString *)sessionToken block:(PF_NULLABLE PFUserResultBlock)block; + +///-------------------------------------- +/// @name Revocable Session +///-------------------------------------- + +/*! + @abstract Enables revocable sessions and migrates the currentUser session token to use revocable session if needed. + + @discussion This method is required if you want to use APIs + and you application's 'Require Revocable Session' setting is turned off on `http://parse.com` app settings. + After returned `BFTask` completes - class and APIs will be available for use. + + @returns An instance of `BFTask` that is completed when + revocable sessions are enabled and currentUser token is migrated. + */ ++ (BFTask *)enableRevocableSessionInBackground; + +/*! + @abstract Enables revocable sessions and upgrades the currentUser session token to use revocable session if needed. + + @discussion This method is required if you want to use APIs + and legacy sessions are enabled in your application settings on `http://parse.com/`. + After returned `BFTask` completes - class and APIs will be available for use. + + @param block Block that will be called when revocable sessions are enabled and currentUser token is migrated. + */ ++ (void)enableRevocableSessionInBackgroundWithBlock:(PF_NULLABLE PFUserSessionUpgradeResultBlock)block; + +///-------------------------------------- +/// @name Logging Out +///-------------------------------------- + +/*! + @abstract *Synchronously* logs out the currently logged in user on disk. + */ ++ (void)logOut; + +/*! + @abstract *Asynchronously* logs out the currenlt logged in user. + + @discussion This will also remove the session from disk, log out of linked services + and all future calls to will return `nil`. This is preferrable to using , + unless your code is already running from a background thread. + + @returns An instance of `BFTask`, that is resolved with `nil` result when logging out completes. + */ ++ (BFTask *)logOutInBackground; + +/*! + @abstract *Asynchronously* logs out the currenlt logged in user. + + @discussion This will also remove the session from disk, log out of linked services + and all future calls to will return `nil`. This is preferrable to using , + unless your code is already running from a background thread. + + @param block A block that will be called when logging out completes or fails. + */ ++ (void)logOutInBackgroundWithBlock:(PF_NULLABLE PFUserLogoutResultBlock)block; + +///-------------------------------------- +/// @name Requesting a Password Reset +///-------------------------------------- + +/*! + @abstract *Synchronously* Send a password reset request for a specified email. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + + @returns Returns `YES` if the reset email request is successful. `NO` - if no account was found for the email address. + */ ++ (BOOL)requestPasswordResetForEmail:(NSString *)email; + +/*! + @abstract *Synchronously* send a password reset request for a specified email and sets an error object. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @param error Error object to set on error. + @returns Returns `YES` if the reset email request is successful. `NO` - if no account was found for the email address. + */ ++ (BOOL)requestPasswordResetForEmail:(NSString *)email + error:(NSError **)error; + +/*! + @abstract Send a password reset request asynchronously for a specified email and sets an + error object. If a user account exists with that email, an email will be sent to + that address with instructions on how to reset their password. + @param email Email of the account to send a reset password request. + @returns The task, that encapsulates the work being done. + */ ++ (BFTask *)requestPasswordResetForEmailInBackground:(NSString *)email; + +/* + @abstract Send a password reset request *asynchronously* for a specified email and sets an error object. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @param target Target object for the selector. + @param selector The selector that will be called when the asynchronous request is complete. + It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`. + `error` will be `nil` on success and set if there was an error. + `[result boolValue]` will tell you whether the call succeeded or not. + */ ++ (void)requestPasswordResetForEmailInBackground:(NSString *)email + target:(PF_NULLABLE_S id)target + selector:(PF_NULLABLE_S SEL)selector; + +/*! + @abstract Send a password reset request *asynchronously* for a specified email. + + @discussion If a user account exists with that email, an email will be sent to that address + with instructions on how to reset their password. + + @param email Email of the account to send a reset password request. + @param block The block to execute. + It should have the following argument signature: `^(BOOL succeeded, NSError *error)`. + */ ++ (void)requestPasswordResetForEmailInBackground:(NSString *)email + block:(PF_NULLABLE PFBooleanResultBlock)block; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/PF_Twitter.h b/Pods/Parse/PF_Twitter.h new file mode 100644 index 0000000..16efbfd --- /dev/null +++ b/Pods/Parse/PF_Twitter.h @@ -0,0 +1,83 @@ +// +// PF_Twitter.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#import + +PF_ASSUME_NONNULL_BEGIN + +@class BFTask; + +/*! + The `PF_Twitter` class is a simple interface for interacting with the Twitter REST API, + automating sign-in and OAuth signing of requests against the API. + */ +@interface PF_Twitter : NSObject + +/*! + @abstract Consumer key of the application that is used to authorize with Twitter. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *consumerKey; + +/*! + @abstract Consumer secret of the application that is used to authorize with Twitter. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *consumerSecret; + +/*! + @abstract Auth token for the current user. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *authToken; + +/*! + @abstract Auth token secret for the current user. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *authTokenSecret; + +/*! + @abstract Twitter user id of the currently signed in user. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *userId; + +/*! + @abstract Twitter screen name of the currently signed in user. + */ +@property (PF_NULLABLE_PROPERTY nonatomic, copy) NSString *screenName; + +/*! + @abstract Displays an auth dialog and populates the authToken, authTokenSecret, userId, and screenName properties + if the Twitter user grants permission to the application. + + @returns The task, that encapsulates the work being done. + */ +- (BFTask *)authorizeInBackground; + +/*! + @abstract Displays an auth dialog and populates the authToken, authTokenSecret, userId, and screenName properties + if the Twitter user grants permission to the application. + + @param success Invoked upon successful authorization. + @param failure Invoked upon an error occurring in the authorization process. + @param cancel Invoked when the user cancels authorization. + */ +- (void)authorizeWithSuccess:(PF_NULLABLE void (^)(void))success + failure:(PF_NULLABLE void (^)(NSError *PF_NULLABLE_S error))failure + cancel:(PF_NULLABLE void (^)(void))cancel; + +/*! + @abstract Adds a 3-legged OAuth signature to an `NSMutableURLRequest` based + upon the properties set for the Twitter object. + + @discussion Use this function to sign requests being made to the Twitter API. + + @param request Request to sign. + */ +- (void)signRequest:(PF_NULLABLE NSMutableURLRequest *)request; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/Parse.framework/Parse b/Pods/Parse/Parse.framework/Parse new file mode 100644 index 0000000..72610a3 Binary files /dev/null and b/Pods/Parse/Parse.framework/Parse differ diff --git a/Pods/Parse/Parse.h b/Pods/Parse/Parse.h new file mode 100644 index 0000000..bed2f48 --- /dev/null +++ b/Pods/Parse/Parse.h @@ -0,0 +1,208 @@ +// +// Parse.h +// +// Copyright 2011-present Parse Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#else + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#endif + +PF_ASSUME_NONNULL_BEGIN + +/*! + The `Parse` class contains static functions that handle global configuration for the Parse framework. + */ +@interface Parse : NSObject + +///-------------------------------------- +/// @name Connecting to Parse +///-------------------------------------- + +/*! + @abstract Sets the applicationId and clientKey of your application. + + @param applicationId The application id of your Parse application. + @param clientKey The client key of your Parse application. + */ ++ (void)setApplicationId:(NSString *)applicationId clientKey:(NSString *)clientKey; + +/*! + @abstract The current application id that was used to configure Parse framework. + */ ++ (NSString *)getApplicationId; + +/*! + @abstract The current client key that was used to configure Parse framework. + */ ++ (NSString *)getClientKey; + +///-------------------------------------- +/// @name Enabling Local Datastore +///-------------------------------------- + +/*! + @abstract Enable pinning in your application. This must be called before your application can use + pinning. The recommended way is to call this method before `setApplicationId:clientKey:`. + */ ++ (void)enableLocalDatastore; + +/*! + @abstract Flag that indicates whether Local Datastore is enabled. + + @returns `YES` if Local Datastore is enabled, otherwise `NO`. + */ ++ (BOOL)isLocalDatastoreEnabled; + +///-------------------------------------- +/// @name Enabling Extensions Data Sharing +///-------------------------------------- + +/*! + @abstract Enables data sharing with an application group identifier. + + @discussion After enabling - Local Datastore, `currentUser`, `currentInstallation` and all eventually commands + are going to be available to every application/extension in a group that have the same Parse applicationId. + + @warning This method is required to be called before . + + @param groupIdentifier Application Group Identifier to share data with. + */ ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier PF_EXTENSION_UNAVAILABLE("Use `enableDataSharingWithApplicationGroupIdentifier:containingApplication:`."); + +/*! + @abstract Enables data sharing with an application group identifier. + + @discussion After enabling - Local Datastore, `currentUser`, `currentInstallation` and all eventually commands + are going to be available to every application/extension in a group that have the same Parse applicationId. + + @warning This method is required to be called before . + This method can only be used by application extensions. + + @param groupIdentifier Application Group Identifier to share data with. + @param bundleIdentifier Bundle identifier of the containing application. + */ ++ (void)enableDataSharingWithApplicationGroupIdentifier:(NSString *)groupIdentifier + containingApplication:(NSString *)bundleIdentifier; + +/*! + @abstract Application Group Identifier for Data Sharing + + @returns `NSString` value if data sharing is enabled, otherwise `nil`. + */ ++ (NSString *)applicationGroupIdentifierForDataSharing; + +/*! + @abstract Containing application bundle identifier. + + @returns `NSString` value if data sharing is enabled, otherwise `nil`. + */ ++ (NSString *)containingApplicationBundleIdentifierForDataSharing; + +#if PARSE_IOS_ONLY + +///-------------------------------------- +/// @name Configuring UI Settings +///-------------------------------------- + +/*! + @abstract Set whether to show offline messages when using a Parse view or view controller related classes. + + @param enabled Whether a `UIAlertView` should be shown when the device is offline + and network access is required from a view or view controller. + + @deprecated This method has no effect. + */ ++ (void)offlineMessagesEnabled:(BOOL)enabled PARSE_DEPRECATED("This method is deprecated and has no effect."); + +/*! + @abstract Set whether to show an error message when using a Parse view or view controller related classes + and a Parse error was generated via a query. + + @param enabled Whether a `UIAlertView` should be shown when an error occurs. + + @deprecated This method has no effect. + */ ++ (void)errorMessagesEnabled:(BOOL)enabled PARSE_DEPRECATED("This method is deprecated and has no effect."); + +#endif + +///-------------------------------------- +/// @name Logging +///-------------------------------------- + +/*! + @abstract Sets the level of logging to display. + + @discussion By default: + - If running inside an app that was downloaded from iOS App Store - it is set to + - All other cases - it is set to + + @param logLevel Log level to set. + @see PFLogLevel + */ ++ (void)setLogLevel:(PFLogLevel)logLevel; + +/*! + @abstract Log level that will be displayed. + + @discussion By default: + - If running inside an app that was downloaded from iOS App Store - it is set to + - All other cases - it is set to + + @returns A value. + @see PFLogLevel + */ ++ (PFLogLevel)logLevel; + +@end + +PF_ASSUME_NONNULL_END diff --git a/Pods/Parse/libParseLib.a b/Pods/Parse/libParseLib.a new file mode 100644 index 0000000..72610a3 Binary files /dev/null and b/Pods/Parse/libParseLib.a differ diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..932dc9a --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1171 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0173657AE1BE4C4A6EF698CFE4A2E871 /* DesignableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BA759A7A8BF5C403B93678ECE6C1F85 /* DesignableView.swift */; }; + 01E464D5C315BAE0E801A4559E89961B /* PFConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FF50EBC927DDAA8BC75A89B508FCB4F /* PFConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 048C182AF8AA3E7F56B0DCE963595E62 /* ImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127D45F6307297F542C2520558EC145 /* ImageLoader.swift */; }; + 07BAB8C0C46E40C8275641B40ECE1738 /* TransitionZoom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742E609FC066E599E0D930001579E130 /* TransitionZoom.swift */; }; + 0BA7E85FCDD2D4FB442F4832501766CC /* UnwindSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBA288AA5A64EBEA9AEB8589F9AE3C52 /* UnwindSegue.swift */; }; + 0BAD11F8633A1D3B0FED08D72098EB03 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */; }; + 0CD486C05BAC3B9E3864298F483CCDF6 /* SpringTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A717BEECD5EEB6190D8C62483DE7FF4 /* SpringTextView.swift */; }; + 0CE318213A7DB28E23158713AC90F18A /* BFTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4D8E04DE46009F0C873B6AAEA84D4C /* BFTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0D8E0DF3427DE55A8EEABBA5587BA965 /* PFAnonymousUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 39AE28BABB5E857D8AD21F886DFA5D59 /* PFAnonymousUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0F97E480AEE9F6B862B53874923A1FD5 /* SpringButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EAE47BD64F3196FA5D6E4BC318D14B9 /* SpringButton.swift */; }; + 0FD335B00E7676E2EDC2E0BF5AC57AA5 /* BFCancellationToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 2103486EB6603BFCC8D73B9809CD1A5C /* BFCancellationToken.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 12023BC59FFD5920814242A925C92856 /* DesignableTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB835673AA76224F4A1385E53C945A52 /* DesignableTabBarController.swift */; }; + 161563B8950E5827BC41EBE5BD6E45A7 /* Spring-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F130FE5E677E2ECD08BD9AF9E6CBAAAC /* Spring-dummy.m */; }; + 18757A3056E96BA4CEF1C5334C739262 /* BFCancellationTokenRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = D5A46486BB91E18B4EFC7C93A720A93C /* BFCancellationTokenRegistration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1A78CB1DA6EF6CF1A54E27064C993B97 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B79E4DF3DA21EBBF9AD0B9588F70E49 /* LoadingView.swift */; }; + 1C2813967EF8AFE6E23C70855A85C9F8 /* Bolts-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = DB00711F1CDEC4ACAA4C4614625A731E /* Bolts-dummy.m */; }; + 1FD82704EA5EA1CE2664DB01E87BE39F /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5578109B2738623953DB9F36FC5DB99 /* CoreLocation.framework */; }; + 2162B43C7759EDCD6E60F61D5A9D1400 /* TransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645D6DAE07B99FBBBD16C2B43BFCEB20 /* TransitionManager.swift */; }; + 243FE11CF582BBBFC9767143930EA658 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 64F5F4F987F63C4FCEF9BB7C475442AC /* Security.framework */; }; + 27DF16D5626EB896AD8DDC2F64206911 /* SpringImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40518C06CAE371BFC0BE82BC3A50C1D7 /* SpringImageView.swift */; }; + 2C651CA3DA49ABA78227D4B754B49C05 /* PFConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F23CB0C11ADCC2693629F2D9903AC68 /* PFConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2FD3E73BAF45B63DBEB732030F7275E8 /* BFTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 347A8D42F308F25ABAEEDD2ED0F05F62 /* BFTask.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 32F3F04EC8F9A3170C25D385A5C8E4E0 /* PFObject.h in Headers */ = {isa = PBXBuildFile; fileRef = ACA8F688C64D21DA3EB587F9D6E390C6 /* PFObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 33158BB89047D7DCFA9159C7E911DBF4 /* BFTaskCompletionSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 79D1487F7AB0A578C19EB63EFBD561BD /* BFTaskCompletionSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 34C41EE6BC98C43CAE565D55866F93E1 /* KeyboardLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4008722D937CB7A2259BDF9722D3185E /* KeyboardLayoutConstraint.swift */; }; + 3CAE2A7FFA706BF057AD210E1B21646D /* DesignableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5561B67A94FA65813851FF7FFA04774 /* DesignableButton.swift */; }; + 3D24E0BB7B049C1B2515A2529E6E4BE4 /* PF_Twitter.h in Headers */ = {isa = PBXBuildFile; fileRef = B7290272D2A75FEF4B6213B80971F2DC /* PF_Twitter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3DA9ECEB4F067C9DC809B6C9BFB2DBD1 /* PFRelation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E3BC1CCD012CFFCDBFF97EE167270D2 /* PFRelation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 402AC683A87471CA3012A2EC3A6CE52E /* Pods-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 894E5DA93A9F359521A89826BE6DA777 /* Pods-dummy.m */; }; + 40A6C2C81777EDAB06DE786ACD638213 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA7DD3BDCFE451B5DB91A9DD652ABF0E /* Images.xcassets */; }; + 45A3A95C90692374E0749620800925FC /* PFInstallation.h in Headers */ = {isa = PBXBuildFile; fileRef = EF492926A41DEB9561310F6779BE8C1D /* PFInstallation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 475731D4AAAAAB8F245ACD705228AA09 /* SpringLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74FBCA8F3B2C2D805E04C07CAF48388A /* SpringLabel.swift */; }; + 4CAF488CD347DD5E69D90B8E65866D89 /* PFRole.h in Headers */ = {isa = PBXBuildFile; fileRef = D21784E1E9542E77762924DD3CF01BC5 /* PFRole.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4FC975C717DC62575D67107C9B8420FC /* PFNullability.h in Headers */ = {isa = PBXBuildFile; fileRef = CC66C9979052D7C2395B1464A2D885A2 /* PFNullability.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 503E50398C46B3ABD259B2D850B9AB60 /* BFTaskCompletionSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 8066D219060145C84E2C8A06F21D8790 /* BFTaskCompletionSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D30593714F4B89F2CE32EA762F33333 /* PFACL.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ACF85AFC7D431567245947285DA85D3 /* PFACL.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 61193CBBF52F5CE7B05778298EE7C844 /* PFCloud.h in Headers */ = {isa = PBXBuildFile; fileRef = 187D76AFF42B7B8616DF54DDB7E97474 /* PFCloud.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 67A6F11D09B28E52149E1B83C62DFAEB /* BFCancellationToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2C7BB70949900F69F4200C2323DCB2 /* BFCancellationToken.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 6871F0F406CA41B381B3219ED97C72D7 /* Bolts.h in Headers */ = {isa = PBXBuildFile; fileRef = 5772FE721171563AA6B29D4ABB4F2DB4 /* Bolts.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69065F716924528B0E88C89CE8FD1E1D /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78F3787C48849A569993B5C48B0DE8D /* BlurView.swift */; }; + 6E2EB632EAA13D7E3F253182D5EDAE5D /* PFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBA68E17F636641EEF7F6B0C1A3ED6B /* PFAnalytics.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6F24A392EE77F9BC86D8C6ACA612DD76 /* DesignableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551EE9025523998B18B7AB0BB9072DEF /* DesignableTextField.swift */; }; + 6F5709124B3DC31E570B59BC705B546D /* PFNetworkActivityIndicatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8ED95232D191DF0DE05D9F204B844570 /* PFNetworkActivityIndicatorManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 789961C8751499A37693448677F994B6 /* Bolts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE91DA79B624411560B5B2457C882E07 /* Bolts.framework */; }; + 78F1A0E4B758A1DEB7026AA08A67AA8D /* Misc.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B4A73100EED242E6B6088B4EC04039 /* Misc.swift */; }; + 797BEF6CAF596943EAB49AFA7BEC9AED /* Spring-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9556991A4A1CC196C72CBA15695C9C66 /* Spring-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7D9DBA4C74B87457E2729EC274B887AA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE3AB227A9DECF0D7A517CA00DDEA8E4 /* QuartzCore.framework */; }; + 85A319F4EC05C6D733FC16701A736159 /* AsyncButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162C3E186D43628DC6C025F46A3505F3 /* AsyncButton.swift */; }; + 86696F2ACC2F26F4BD6D9BFD35EF286B /* LoadingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0CD3DB1FEA94D8D3022B252B44AD526B /* LoadingView.xib */; }; + 86697C7B6A2BE8A4D61F1E0158EA2083 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 447A90A1DF86228BE9B0FC05E6FBDF79 /* AudioToolbox.framework */; }; + 879CA5F7D58EC1547F4C82A2E5AD6E59 /* PFFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A3C003ADB23AFA9891FCFED74BF52FE /* PFFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8CEA74B0BE059CE20868AE718DEB84F8 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 481DF68EEF835A341EB0F153E4549C06 /* CoreGraphics.framework */; }; + 91251A9D5AC072C6F627076843716148 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9FDD6A42083728DA1BEFDA129A0534 /* StoreKit.framework */; }; + 91EB8F84EC24846D4B3D1EFFD96E94AD /* PFGeoPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C110F4AFDB615BD352AEECC67092B89 /* PFGeoPoint.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92EB8EFED4EFDF516B15A811A2D068AC /* Empty.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A4C2E1CED68CD804F7010D8DC45F632 /* Empty.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 9385A34223C160C4B574ABFE60FA3FEA /* SpringView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D086A3C3E0F7DA5ABF471FBCA3D240 /* SpringView.swift */; }; + 942C7D6E4596F66CD67B254B20A19798 /* PFSubclassing.h in Headers */ = {isa = PBXBuildFile; fileRef = D60BA2783E1207216A869D0A4D676EB8 /* PFSubclassing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9600B545AE4341D8EBE0D5249D0A8778 /* AutoTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8DCF0B0EA637A807BF78B589AACFCF6 /* AutoTextView.swift */; }; + 9930B9FEF95F4557476EBA8C3422D3D2 /* SpringTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 613C81BA1A69B2E743D1D800D703150F /* SpringTextField.swift */; }; + 99904E00A2BA3DC6A12142B192039C5F /* Bolts.m in Sources */ = {isa = PBXBuildFile; fileRef = F9A2FFC4D435DE7CDA7D0642811681A4 /* Bolts.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9DEC37FC901BB00149A719DAB118D4C0 /* PFPurchase.h in Headers */ = {isa = PBXBuildFile; fileRef = B35D31859EB35C42E9167EA4AAC9D440 /* PFPurchase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9F748C2CF1EB934C69834824507C57A7 /* BFCancellationTokenRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = 41C91C8E828CBCD9762210B16000F880 /* BFCancellationTokenRegistration.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9FD6846B525140DB8A487A4E943AA255 /* BFExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = E30785C52DC143428B64D0A250377C84 /* BFExecutor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A4A18156DB0EB293B90DD839C57DE56B /* PFSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EA27B9EE3270C1434F3C0092AB2880 /* PFSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A677DF0F8B36E163078D3CEC105D6980 /* DesignableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A283BB584489DC24DA30D7AF22C27DFC /* DesignableLabel.swift */; }; + AC1F233AC1709AC2291C40E0B141A19F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F93EA00628955BE835809BE7751F3B8 /* SystemConfiguration.framework */; }; + ADE3838A73F25EF67D4820CF9A96A782 /* PFTwitterUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = BA6116C802B071E219CE13959C570200 /* PFTwitterUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ADF5698715A8B12530A74AD38753EADA /* AsyncImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92B1B02F18A24E4D465FDE18451617E6 /* AsyncImageView.swift */; }; + B20710E63C4E138AD3E328D305EF3C86 /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E49A3C0A33A7A826B144D4B817E7CC0 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B227E4390901BD518AFD52E8D4E9D4CC /* PFUser.h in Headers */ = {isa = PBXBuildFile; fileRef = BA123AC830583B5DDD718DBBCC4CC81C /* PFUser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B674E36B5D5F03A1731DC8A15D3AF5C1 /* DesignableImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B07DB4AE173BA6C2B25F8903B9F51840 /* DesignableImageView.swift */; }; + BDE753D0E76677EEFF729911DCDD7920 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E07FCBC36307FDFDAA1C33F6BEDB9B57 /* CFNetwork.framework */; }; + C3E58ABB8DC1E32BC52F7FCC838562E3 /* Parse-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 33A029DA4B05BD314122A8A14E67FA56 /* Parse-dummy.m */; }; + C5F5302ECA7AAC39A2FE6F20AC37F185 /* SpringAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43ABFAEB0CCD0F76573B5499FE4225EE /* SpringAnimation.swift */; }; + C77BC43BFF3B430263AC543767085AAA /* BFCancellationTokenSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E0D7789F25DE70F639F1A26D7BD2AF /* BFCancellationTokenSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C77D8080C4757D0A9D25A825DB1C6BE2 /* BFCancellationTokenSource.m in Sources */ = {isa = PBXBuildFile; fileRef = EAD4CA38781D2D3830DFE179461DE8D3 /* BFCancellationTokenSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + CA7B258C22505CCF22377B8DE0CF71DF /* Spring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8188489CF7D3F6AC153DB8E77E58FE7A /* Spring.swift */; }; + CC8BF970D142C0F34804966DDFCED1BE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */; }; + D5C3D342B137CD83A87D8241D7155C1E /* BFExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7B01A5D813F3A41EFE26BB04167644 /* BFExecutor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D68D7A0BB56E9C9FD9A54C8B807E5118 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */; }; + D822BE5C8BAF3DEC4FDC0EFA8FDD56AF /* BoltsVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 402CEA2A4D7B07D32A0B3186E342B059 /* BoltsVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA7BD818A492AE5CA41B1D541F958C99 /* SoundPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BB00891C8DABDB79665071475C00071 /* SoundPlayer.swift */; }; + E037326191F1E784EF7D79EE6B72A04F /* PFQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = B02EE72FF15735938EEE05CC11B8C0A4 /* PFQuery.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E4EAFC05818FC113E13B23A26FA0FD01 /* Pods-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BCC458FDD5F692BBB2BFC64BB5701FC /* Pods-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E59EBFA001F5ED2BA4E8D2481B9B7AF1 /* Parse-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 78BE9635D59FB41C0354EBC581801E8F /* Parse-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E871588F36B3C18B062C065E16CB9491 /* DesignableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 205B0F032C269C5F1F35761BDC46ED31 /* DesignableTextView.swift */; }; + EA55CD6E6FEF204B42995574A82522E7 /* PFObject+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE13C809F3C05E238D15B8052AC7596 /* PFObject+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F153419C493823327C2114199CE4C038 /* PFPush.h in Headers */ = {isa = PBXBuildFile; fileRef = C78B43D020DBA19670270E55D53B012D /* PFPush.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F5FBB1976C2442DC3F082F6132711D9C /* Bolts-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BA847226DCDF231803F02634AE425BBC /* Bolts-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FB2E0BD55E3872D4DC5E33AE37CAAFEF /* PFProduct.h in Headers */ = {isa = PBXBuildFile; fileRef = C01A068BC0BD8C0DA651CA4FEDCA3AC6 /* PFProduct.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FB30FB9732AEF110A3D6756587EB35EB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 291DC93D39D47039E216E0404EBA5546 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 66D9046CB8E6B543604FE2E6FFECE3DD; + remoteInfo = Parse; + }; + 3EFCD389412FB1DB1C62FAD573660C99 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3329BF946FA72D0496326B27F8C5D93D; + remoteInfo = Spring; + }; + 8D9CAB84CE13E2AC5F94681FAB7A9591 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = BCA053B6430690326435042FEB61B458; + remoteInfo = Bolts; + }; + EFB84C6601ECE4AB3F0767E68201EA94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = BCA053B6430690326435042FEB61B458; + remoteInfo = Bolts; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 007426D4289E40D231F74EFE9A6E38EB /* Bolts.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Bolts.xcconfig; sourceTree = ""; }; + 04EA27B9EE3270C1434F3C0092AB2880 /* PFSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFSession.h; sourceTree = ""; }; + 0A4C2E1CED68CD804F7010D8DC45F632 /* Empty.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = Empty.m; sourceTree = ""; }; + 0CD3DB1FEA94D8D3022B252B44AD526B /* LoadingView.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = LoadingView.xib; path = Spring/LoadingView.xib; sourceTree = ""; }; + 0E7B01A5D813F3A41EFE26BB04167644 /* BFExecutor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFExecutor.h; path = Bolts/Common/BFExecutor.h; sourceTree = ""; }; + 0F23CB0C11ADCC2693629F2D9903AC68 /* PFConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFConstants.h; sourceTree = ""; }; + 0F4D8E04DE46009F0C873B6AAEA84D4C /* BFTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTask.h; path = Bolts/Common/BFTask.h; sourceTree = ""; }; + 0F93EA00628955BE835809BE7751F3B8 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + 0FF50EBC927DDAA8BC75A89B508FCB4F /* PFConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFConfig.h; sourceTree = ""; }; + 162C3E186D43628DC6C025F46A3505F3 /* AsyncButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncButton.swift; path = Spring/AsyncButton.swift; sourceTree = ""; }; + 187D76AFF42B7B8616DF54DDB7E97474 /* PFCloud.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFCloud.h; sourceTree = ""; }; + 1E15E859A4F920CBA1EBC4C1D58C807B /* Spring.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Spring.modulemap; sourceTree = ""; }; + 1E2EA2020AF0D43F5520A3DBA4CF0312 /* Parse-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Parse-prefix.pch"; sourceTree = ""; }; + 205B0F032C269C5F1F35761BDC46ED31 /* DesignableTextView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableTextView.swift; path = Spring/DesignableTextView.swift; sourceTree = ""; }; + 2103486EB6603BFCC8D73B9809CD1A5C /* BFCancellationToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationToken.h; path = Bolts/Common/BFCancellationToken.h; sourceTree = ""; }; + 2A717BEECD5EEB6190D8C62483DE7FF4 /* SpringTextView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringTextView.swift; path = Spring/SpringTextView.swift; sourceTree = ""; }; + 2BCC458FDD5F692BBB2BFC64BB5701FC /* Pods-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-umbrella.h"; sourceTree = ""; }; + 3114B214F966B2D67230A254E2805271 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 33A029DA4B05BD314122A8A14E67FA56 /* Parse-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Parse-dummy.m"; sourceTree = ""; }; + 347A8D42F308F25ABAEEDD2ED0F05F62 /* BFTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTask.m; path = Bolts/Common/BFTask.m; sourceTree = ""; }; + 39AE28BABB5E857D8AD21F886DFA5D59 /* PFAnonymousUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFAnonymousUtils.h; sourceTree = ""; }; + 3A3C003ADB23AFA9891FCFED74BF52FE /* PFFile.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFFile.h; sourceTree = ""; }; + 3BB00891C8DABDB79665071475C00071 /* SoundPlayer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SoundPlayer.swift; path = Spring/SoundPlayer.swift; sourceTree = ""; }; + 3E3BC1CCD012CFFCDBFF97EE167270D2 /* PFRelation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFRelation.h; sourceTree = ""; }; + 3E43846F71FF589017C4814E79AEAA28 /* libParseLib.a */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = archive.ar; path = libParseLib.a; sourceTree = ""; }; + 4008722D937CB7A2259BDF9722D3185E /* KeyboardLayoutConstraint.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KeyboardLayoutConstraint.swift; path = Spring/KeyboardLayoutConstraint.swift; sourceTree = ""; }; + 402CEA2A4D7B07D32A0B3186E342B059 /* BoltsVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BoltsVersion.h; path = Bolts/Common/BoltsVersion.h; sourceTree = ""; }; + 40518C06CAE371BFC0BE82BC3A50C1D7 /* SpringImageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringImageView.swift; path = Spring/SpringImageView.swift; sourceTree = ""; }; + 41C91C8E828CBCD9762210B16000F880 /* BFCancellationTokenRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenRegistration.m; path = Bolts/Common/BFCancellationTokenRegistration.m; sourceTree = ""; }; + 43ABFAEB0CCD0F76573B5499FE4225EE /* SpringAnimation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringAnimation.swift; path = Spring/SpringAnimation.swift; sourceTree = ""; }; + 447A90A1DF86228BE9B0FC05E6FBDF79 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; }; + 481DF68EEF835A341EB0F153E4549C06 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + 4F2E2F7E83DD98B356A4A1A4B2C82BC6 /* Bolts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Bolts.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5127D45F6307297F542C2520558EC145 /* ImageLoader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImageLoader.swift; path = Spring/ImageLoader.swift; sourceTree = ""; }; + 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 54226DAAE3EBFCE333B149B69AD4CC53 /* Bolts.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Bolts.modulemap; sourceTree = ""; }; + 551EE9025523998B18B7AB0BB9072DEF /* DesignableTextField.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableTextField.swift; path = Spring/DesignableTextField.swift; sourceTree = ""; }; + 5772FE721171563AA6B29D4ABB4F2DB4 /* Bolts.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Bolts.h; path = Bolts/Common/Bolts.h; sourceTree = ""; }; + 5B79E4DF3DA21EBBF9AD0B9588F70E49 /* LoadingView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LoadingView.swift; path = Spring/LoadingView.swift; sourceTree = ""; }; + 613C81BA1A69B2E743D1D800D703150F /* SpringTextField.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringTextField.swift; path = Spring/SpringTextField.swift; sourceTree = ""; }; + 63139E481C14F7BBCFB7506DE6E5B396 /* Spring.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Spring.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 645D6DAE07B99FBBBD16C2B43BFCEB20 /* TransitionManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransitionManager.swift; path = Spring/TransitionManager.swift; sourceTree = ""; }; + 64F5F4F987F63C4FCEF9BB7C475442AC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 6ACF85AFC7D431567245947285DA85D3 /* PFACL.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFACL.h; sourceTree = ""; }; + 6BA759A7A8BF5C403B93678ECE6C1F85 /* DesignableView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableView.swift; path = Spring/DesignableView.swift; sourceTree = ""; }; + 6EAE47BD64F3196FA5D6E4BC318D14B9 /* SpringButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringButton.swift; path = Spring/SpringButton.swift; sourceTree = ""; }; + 6F715E38101B9425073EAEB1BFE551CB /* Spring.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Spring.xcconfig; sourceTree = ""; }; + 742E609FC066E599E0D930001579E130 /* TransitionZoom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransitionZoom.swift; path = Spring/TransitionZoom.swift; sourceTree = ""; }; + 74FBCA8F3B2C2D805E04C07CAF48388A /* SpringLabel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringLabel.swift; path = Spring/SpringLabel.swift; sourceTree = ""; }; + 78BE9635D59FB41C0354EBC581801E8F /* Parse-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Parse-umbrella.h"; sourceTree = ""; }; + 79A9DEDC89FE8336BF5FEDAAF75BF7FC /* Pods.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Pods.modulemap; sourceTree = ""; }; + 79D1487F7AB0A578C19EB63EFBD561BD /* BFTaskCompletionSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTaskCompletionSource.m; path = Bolts/Common/BFTaskCompletionSource.m; sourceTree = ""; }; + 7C110F4AFDB615BD352AEECC67092B89 /* PFGeoPoint.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFGeoPoint.h; sourceTree = ""; }; + 7E49A3C0A33A7A826B144D4B817E7CC0 /* Parse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = Parse.h; sourceTree = ""; }; + 8066D219060145C84E2C8A06F21D8790 /* BFTaskCompletionSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTaskCompletionSource.h; path = Bolts/Common/BFTaskCompletionSource.h; sourceTree = ""; }; + 8188489CF7D3F6AC153DB8E77E58FE7A /* Spring.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Spring.swift; path = Spring/Spring.swift; sourceTree = ""; }; + 83E0D7789F25DE70F639F1A26D7BD2AF /* BFCancellationTokenSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenSource.h; path = Bolts/Common/BFCancellationTokenSource.h; sourceTree = ""; }; + 87B213035BAC5F75386F62D3C75D2342 /* Pods-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-acknowledgements.plist"; sourceTree = ""; }; + 894E5DA93A9F359521A89826BE6DA777 /* Pods-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dummy.m"; sourceTree = ""; }; + 8B9FDD6A42083728DA1BEFDA129A0534 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; }; + 8C118D3BE26359F15B0FA49C9620855C /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8D2C7BB70949900F69F4200C2323DCB2 /* BFCancellationToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationToken.m; path = Bolts/Common/BFCancellationToken.m; sourceTree = ""; }; + 8ED95232D191DF0DE05D9F204B844570 /* PFNetworkActivityIndicatorManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFNetworkActivityIndicatorManager.h; sourceTree = ""; }; + 92B1B02F18A24E4D465FDE18451617E6 /* AsyncImageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncImageView.swift; path = Spring/AsyncImageView.swift; sourceTree = ""; }; + 9556991A4A1CC196C72CBA15695C9C66 /* Spring-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Spring-umbrella.h"; sourceTree = ""; }; + 977577C045EDA9D9D1F46E2598D19FC7 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.debug.xcconfig; sourceTree = ""; }; + 97CC8B00A137B81C8A95640C5E678726 /* Parse.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Parse.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9AA7B81FC5EFA9DECEC22FADD358F630 /* Parse.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Parse.xcconfig; sourceTree = ""; }; + 9BD3F1B9AE0D545E4BDFC67F18BA26A2 /* Parse.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = Parse.modulemap; sourceTree = ""; }; + A283BB584489DC24DA30D7AF22C27DFC /* DesignableLabel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableLabel.swift; path = Spring/DesignableLabel.swift; sourceTree = ""; }; + A8DCF0B0EA637A807BF78B589AACFCF6 /* AutoTextView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AutoTextView.swift; path = Spring/AutoTextView.swift; sourceTree = ""; }; + AC20152CCF6EB58EB13E17290CAB5B22 /* Spring-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Spring-prefix.pch"; sourceTree = ""; }; + ACA8F688C64D21DA3EB587F9D6E390C6 /* PFObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFObject.h; sourceTree = ""; }; + B02EE72FF15735938EEE05CC11B8C0A4 /* PFQuery.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFQuery.h; sourceTree = ""; }; + B07DB4AE173BA6C2B25F8903B9F51840 /* DesignableImageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableImageView.swift; path = Spring/DesignableImageView.swift; sourceTree = ""; }; + B35D31859EB35C42E9167EA4AAC9D440 /* PFPurchase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFPurchase.h; sourceTree = ""; }; + B7290272D2A75FEF4B6213B80971F2DC /* PF_Twitter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PF_Twitter.h; sourceTree = ""; }; + B78F3787C48849A569993B5C48B0DE8D /* BlurView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlurView.swift; path = Spring/BlurView.swift; sourceTree = ""; }; + BA123AC830583B5DDD718DBBCC4CC81C /* PFUser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFUser.h; sourceTree = ""; }; + BA6116C802B071E219CE13959C570200 /* PFTwitterUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFTwitterUtils.h; sourceTree = ""; }; + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + BA7DD3BDCFE451B5DB91A9DD652ABF0E /* Images.xcassets */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SpringApp/Images.xcassets; sourceTree = ""; }; + BA847226DCDF231803F02634AE425BBC /* Bolts-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-umbrella.h"; sourceTree = ""; }; + C01A068BC0BD8C0DA651CA4FEDCA3AC6 /* PFProduct.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFProduct.h; sourceTree = ""; }; + C38A0698AE48CFC688B19B19253FFA36 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C78B43D020DBA19670270E55D53B012D /* PFPush.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFPush.h; sourceTree = ""; }; + CBC0F7C552B739C909B650A0F42F7F38 /* Pods-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-resources.sh"; sourceTree = ""; }; + CC66C9979052D7C2395B1464A2D885A2 /* PFNullability.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFNullability.h; sourceTree = ""; }; + CCE13C809F3C05E238D15B8052AC7596 /* PFObject+Subclass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PFObject+Subclass.h"; sourceTree = ""; }; + D0405803033A2A777B8E4DFA0C1800ED /* Pods-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-acknowledgements.markdown"; sourceTree = ""; }; + D21784E1E9542E77762924DD3CF01BC5 /* PFRole.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFRole.h; sourceTree = ""; }; + D5578109B2738623953DB9F36FC5DB99 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CoreLocation.framework; sourceTree = DEVELOPER_DIR; }; + D5A46486BB91E18B4EFC7C93A720A93C /* BFCancellationTokenRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenRegistration.h; path = Bolts/Common/BFCancellationTokenRegistration.h; sourceTree = ""; }; + D60BA2783E1207216A869D0A4D676EB8 /* PFSubclassing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFSubclassing.h; sourceTree = ""; }; + D8B4A73100EED242E6B6088B4EC04039 /* Misc.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Misc.swift; path = Spring/Misc.swift; sourceTree = ""; }; + DA312349A49333542E6F4B36B329960E /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.release.xcconfig; sourceTree = ""; }; + DB00711F1CDEC4ACAA4C4614625A731E /* Bolts-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Bolts-dummy.m"; sourceTree = ""; }; + DBA288AA5A64EBEA9AEB8589F9AE3C52 /* UnwindSegue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UnwindSegue.swift; path = Spring/UnwindSegue.swift; sourceTree = ""; }; + DCBA68E17F636641EEF7F6B0C1A3ED6B /* PFAnalytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFAnalytics.h; sourceTree = ""; }; + DE3AB227A9DECF0D7A517CA00DDEA8E4 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + DE91DA79B624411560B5B2457C882E07 /* Bolts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Bolts.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E07FCBC36307FDFDAA1C33F6BEDB9B57 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + E1D086A3C3E0F7DA5ABF471FBCA3D240 /* SpringView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpringView.swift; path = Spring/SpringView.swift; sourceTree = ""; }; + E30785C52DC143428B64D0A250377C84 /* BFExecutor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFExecutor.m; path = Bolts/Common/BFExecutor.m; sourceTree = ""; }; + E5561B67A94FA65813851FF7FFA04774 /* DesignableButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableButton.swift; path = Spring/DesignableButton.swift; sourceTree = ""; }; + E7F21354943D9F42A70697D5A5EF72E9 /* Pods-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-frameworks.sh"; sourceTree = ""; }; + E8446514FBAD26C0E18F24A5715AEF67 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAD4CA38781D2D3830DFE179461DE8D3 /* BFCancellationTokenSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenSource.m; path = Bolts/Common/BFCancellationTokenSource.m; sourceTree = ""; }; + EB2CB22924FE7A65613BC074384B8BAC /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EF492926A41DEB9561310F6779BE8C1D /* PFInstallation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = PFInstallation.h; sourceTree = ""; }; + F130FE5E677E2ECD08BD9AF9E6CBAAAC /* Spring-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Spring-dummy.m"; sourceTree = ""; }; + F33A6752009DDD893E284D732CDDB35E /* Bolts-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-prefix.pch"; sourceTree = ""; }; + F9A2FFC4D435DE7CDA7D0642811681A4 /* Bolts.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Bolts.m; path = Bolts/Common/Bolts.m; sourceTree = ""; }; + FB835673AA76224F4A1385E53C945A52 /* DesignableTabBarController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DesignableTabBarController.swift; path = Spring/DesignableTabBarController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 137677EB7290F620413E73E3A9337756 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 86697C7B6A2BE8A4D61F1E0158EA2083 /* AudioToolbox.framework in Frameworks */, + 789961C8751499A37693448677F994B6 /* Bolts.framework in Frameworks */, + BDE753D0E76677EEFF729911DCDD7920 /* CFNetwork.framework in Frameworks */, + 8CEA74B0BE059CE20868AE718DEB84F8 /* CoreGraphics.framework in Frameworks */, + 1FD82704EA5EA1CE2664DB01E87BE39F /* CoreLocation.framework in Frameworks */, + 0BAD11F8633A1D3B0FED08D72098EB03 /* Foundation.framework in Frameworks */, + 7D9DBA4C74B87457E2729EC274B887AA /* QuartzCore.framework in Frameworks */, + 243FE11CF582BBBFC9767143930EA658 /* Security.framework in Frameworks */, + 91251A9D5AC072C6F627076843716148 /* StoreKit.framework in Frameworks */, + AC1F233AC1709AC2291C40E0B141A19F /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 829A0D84220A0BE484FCA0B14D5CEE2C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CC8BF970D142C0F34804966DDFCED1BE /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A14A8ECFAC2964AE0BAD0B78F5318F91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D68D7A0BB56E9C9FD9A54C8B807E5118 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D53A11166F299F697AFEFDB93699F0E3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FB30FB9732AEF110A3D6756587EB35EB /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1873F64ECFB01E9CE5B44996F88A7647 /* Tasks */ = { + isa = PBXGroup; + children = ( + 2103486EB6603BFCC8D73B9809CD1A5C /* BFCancellationToken.h */, + 8D2C7BB70949900F69F4200C2323DCB2 /* BFCancellationToken.m */, + D5A46486BB91E18B4EFC7C93A720A93C /* BFCancellationTokenRegistration.h */, + 41C91C8E828CBCD9762210B16000F880 /* BFCancellationTokenRegistration.m */, + 83E0D7789F25DE70F639F1A26D7BD2AF /* BFCancellationTokenSource.h */, + EAD4CA38781D2D3830DFE179461DE8D3 /* BFCancellationTokenSource.m */, + 0E7B01A5D813F3A41EFE26BB04167644 /* BFExecutor.h */, + E30785C52DC143428B64D0A250377C84 /* BFExecutor.m */, + 0F4D8E04DE46009F0C873B6AAEA84D4C /* BFTask.h */, + 347A8D42F308F25ABAEEDD2ED0F05F62 /* BFTask.m */, + 8066D219060145C84E2C8A06F21D8790 /* BFTaskCompletionSource.h */, + 79D1487F7AB0A578C19EB63EFBD561BD /* BFTaskCompletionSource.m */, + 5772FE721171563AA6B29D4ABB4F2DB4 /* Bolts.h */, + F9A2FFC4D435DE7CDA7D0642811681A4 /* Bolts.m */, + 402CEA2A4D7B07D32A0B3186E342B059 /* BoltsVersion.h */, + ); + name = Tasks; + sourceTree = ""; + }; + 1DDCF1308030ED30DBA088AD5B7B1AD0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3E43846F71FF589017C4814E79AEAA28 /* libParseLib.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 29FCC7E51C9FE1E926592508380F440A /* Parse */ = { + isa = PBXGroup; + children = ( + 0A4C2E1CED68CD804F7010D8DC45F632 /* Empty.m */, + 7E49A3C0A33A7A826B144D4B817E7CC0 /* Parse.h */, + B7290272D2A75FEF4B6213B80971F2DC /* PF_Twitter.h */, + 6ACF85AFC7D431567245947285DA85D3 /* PFACL.h */, + DCBA68E17F636641EEF7F6B0C1A3ED6B /* PFAnalytics.h */, + 39AE28BABB5E857D8AD21F886DFA5D59 /* PFAnonymousUtils.h */, + 187D76AFF42B7B8616DF54DDB7E97474 /* PFCloud.h */, + 0FF50EBC927DDAA8BC75A89B508FCB4F /* PFConfig.h */, + 0F23CB0C11ADCC2693629F2D9903AC68 /* PFConstants.h */, + 3A3C003ADB23AFA9891FCFED74BF52FE /* PFFile.h */, + 7C110F4AFDB615BD352AEECC67092B89 /* PFGeoPoint.h */, + EF492926A41DEB9561310F6779BE8C1D /* PFInstallation.h */, + 8ED95232D191DF0DE05D9F204B844570 /* PFNetworkActivityIndicatorManager.h */, + CC66C9979052D7C2395B1464A2D885A2 /* PFNullability.h */, + ACA8F688C64D21DA3EB587F9D6E390C6 /* PFObject.h */, + CCE13C809F3C05E238D15B8052AC7596 /* PFObject+Subclass.h */, + C01A068BC0BD8C0DA651CA4FEDCA3AC6 /* PFProduct.h */, + B35D31859EB35C42E9167EA4AAC9D440 /* PFPurchase.h */, + C78B43D020DBA19670270E55D53B012D /* PFPush.h */, + B02EE72FF15735938EEE05CC11B8C0A4 /* PFQuery.h */, + 3E3BC1CCD012CFFCDBFF97EE167270D2 /* PFRelation.h */, + D21784E1E9542E77762924DD3CF01BC5 /* PFRole.h */, + 04EA27B9EE3270C1434F3C0092AB2880 /* PFSession.h */, + D60BA2783E1207216A869D0A4D676EB8 /* PFSubclassing.h */, + BA6116C802B071E219CE13959C570200 /* PFTwitterUtils.h */, + BA123AC830583B5DDD718DBBCC4CC81C /* PFUser.h */, + 1DDCF1308030ED30DBA088AD5B7B1AD0 /* Frameworks */, + 78EBF8F2C49ACD2F6CEC4CEB3188F227 /* Support Files */, + ); + path = Parse; + sourceTree = ""; + }; + 3D220C91DD72A777ABCBE7243D50CFF8 /* Support Files */ = { + isa = PBXGroup; + children = ( + 8C118D3BE26359F15B0FA49C9620855C /* Info.plist */, + 1E15E859A4F920CBA1EBC4C1D58C807B /* Spring.modulemap */, + 6F715E38101B9425073EAEB1BFE551CB /* Spring.xcconfig */, + F130FE5E677E2ECD08BD9AF9E6CBAAAC /* Spring-dummy.m */, + AC20152CCF6EB58EB13E17290CAB5B22 /* Spring-prefix.pch */, + 9556991A4A1CC196C72CBA15695C9C66 /* Spring-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Spring"; + sourceTree = ""; + }; + 44E5CA6134C04B093AD8C39BAB4EFD8E /* Frameworks */ = { + isa = PBXGroup; + children = ( + DE91DA79B624411560B5B2457C882E07 /* Bolts.framework */, + BEB9D98F85AA82A7DE37EDD8C7227A16 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4A42634F5D89AC97B4E29FECE125EAFD /* Bolts */ = { + isa = PBXGroup; + children = ( + 71C2F3C85C09CD53A98DFBC5235F23D8 /* Support Files */, + 1873F64ECFB01E9CE5B44996F88A7647 /* Tasks */, + ); + path = Bolts; + sourceTree = ""; + }; + 71C2F3C85C09CD53A98DFBC5235F23D8 /* Support Files */ = { + isa = PBXGroup; + children = ( + 54226DAAE3EBFCE333B149B69AD4CC53 /* Bolts.modulemap */, + 007426D4289E40D231F74EFE9A6E38EB /* Bolts.xcconfig */, + DB00711F1CDEC4ACAA4C4614625A731E /* Bolts-dummy.m */, + F33A6752009DDD893E284D732CDDB35E /* Bolts-prefix.pch */, + BA847226DCDF231803F02634AE425BBC /* Bolts-umbrella.h */, + EB2CB22924FE7A65613BC074384B8BAC /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/Bolts"; + sourceTree = ""; + }; + 75D98FF52E597A11900E131B6C4E1ADA /* Pods */ = { + isa = PBXGroup; + children = ( + E8446514FBAD26C0E18F24A5715AEF67 /* Info.plist */, + 79A9DEDC89FE8336BF5FEDAAF75BF7FC /* Pods.modulemap */, + D0405803033A2A777B8E4DFA0C1800ED /* Pods-acknowledgements.markdown */, + 87B213035BAC5F75386F62D3C75D2342 /* Pods-acknowledgements.plist */, + 894E5DA93A9F359521A89826BE6DA777 /* Pods-dummy.m */, + E7F21354943D9F42A70697D5A5EF72E9 /* Pods-frameworks.sh */, + CBC0F7C552B739C909B650A0F42F7F38 /* Pods-resources.sh */, + 2BCC458FDD5F692BBB2BFC64BB5701FC /* Pods-umbrella.h */, + 977577C045EDA9D9D1F46E2598D19FC7 /* Pods.debug.xcconfig */, + DA312349A49333542E6F4B36B329960E /* Pods.release.xcconfig */, + ); + name = Pods; + path = "Target Support Files/Pods"; + sourceTree = ""; + }; + 78EBF8F2C49ACD2F6CEC4CEB3188F227 /* Support Files */ = { + isa = PBXGroup; + children = ( + C38A0698AE48CFC688B19B19253FFA36 /* Info.plist */, + 9BD3F1B9AE0D545E4BDFC67F18BA26A2 /* Parse.modulemap */, + 9AA7B81FC5EFA9DECEC22FADD358F630 /* Parse.xcconfig */, + 33A029DA4B05BD314122A8A14E67FA56 /* Parse-dummy.m */, + 1E2EA2020AF0D43F5520A3DBA4CF0312 /* Parse-prefix.pch */, + 78BE9635D59FB41C0354EBC581801E8F /* Parse-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Parse"; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */, + 44E5CA6134C04B093AD8C39BAB4EFD8E /* Frameworks */, + D5B73FDE60F16582300B4C8A8BB2ED1C /* Pods */, + AF678C0C05BF517BB227DCB0791FA7D2 /* Products */, + B7B80995527643776607AFFA75B91E24 /* Targets Support Files */, + ); + sourceTree = ""; + }; + 8701E2B11F35DAFDDCB5481FEB8E9D32 /* Resources */ = { + isa = PBXGroup; + children = ( + BA7DD3BDCFE451B5DB91A9DD652ABF0E /* Images.xcassets */, + 0CD3DB1FEA94D8D3022B252B44AD526B /* LoadingView.xib */, + ); + name = Resources; + sourceTree = ""; + }; + AF678C0C05BF517BB227DCB0791FA7D2 /* Products */ = { + isa = PBXGroup; + children = ( + 4F2E2F7E83DD98B356A4A1A4B2C82BC6 /* Bolts.framework */, + 97CC8B00A137B81C8A95640C5E678726 /* Parse.framework */, + 3114B214F966B2D67230A254E2805271 /* Pods.framework */, + 63139E481C14F7BBCFB7506DE6E5B396 /* Spring.framework */, + ); + name = Products; + sourceTree = ""; + }; + B7B80995527643776607AFFA75B91E24 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 75D98FF52E597A11900E131B6C4E1ADA /* Pods */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + BEB9D98F85AA82A7DE37EDD8C7227A16 /* iOS */ = { + isa = PBXGroup; + children = ( + 447A90A1DF86228BE9B0FC05E6FBDF79 /* AudioToolbox.framework */, + E07FCBC36307FDFDAA1C33F6BEDB9B57 /* CFNetwork.framework */, + 481DF68EEF835A341EB0F153E4549C06 /* CoreGraphics.framework */, + D5578109B2738623953DB9F36FC5DB99 /* CoreLocation.framework */, + 52BE56B6755AA9A6E83CFA2837ABEFAC /* Foundation.framework */, + DE3AB227A9DECF0D7A517CA00DDEA8E4 /* QuartzCore.framework */, + 64F5F4F987F63C4FCEF9BB7C475442AC /* Security.framework */, + 8B9FDD6A42083728DA1BEFDA129A0534 /* StoreKit.framework */, + 0F93EA00628955BE835809BE7751F3B8 /* SystemConfiguration.framework */, + ); + name = iOS; + sourceTree = ""; + }; + BF26F5507A74F8F2AB2155DBEE1E2E7A /* Spring */ = { + isa = PBXGroup; + children = ( + 162C3E186D43628DC6C025F46A3505F3 /* AsyncButton.swift */, + 92B1B02F18A24E4D465FDE18451617E6 /* AsyncImageView.swift */, + A8DCF0B0EA637A807BF78B589AACFCF6 /* AutoTextView.swift */, + B78F3787C48849A569993B5C48B0DE8D /* BlurView.swift */, + E5561B67A94FA65813851FF7FFA04774 /* DesignableButton.swift */, + B07DB4AE173BA6C2B25F8903B9F51840 /* DesignableImageView.swift */, + A283BB584489DC24DA30D7AF22C27DFC /* DesignableLabel.swift */, + FB835673AA76224F4A1385E53C945A52 /* DesignableTabBarController.swift */, + 551EE9025523998B18B7AB0BB9072DEF /* DesignableTextField.swift */, + 205B0F032C269C5F1F35761BDC46ED31 /* DesignableTextView.swift */, + 6BA759A7A8BF5C403B93678ECE6C1F85 /* DesignableView.swift */, + 5127D45F6307297F542C2520558EC145 /* ImageLoader.swift */, + 4008722D937CB7A2259BDF9722D3185E /* KeyboardLayoutConstraint.swift */, + 5B79E4DF3DA21EBBF9AD0B9588F70E49 /* LoadingView.swift */, + D8B4A73100EED242E6B6088B4EC04039 /* Misc.swift */, + 3BB00891C8DABDB79665071475C00071 /* SoundPlayer.swift */, + 8188489CF7D3F6AC153DB8E77E58FE7A /* Spring.swift */, + 43ABFAEB0CCD0F76573B5499FE4225EE /* SpringAnimation.swift */, + 6EAE47BD64F3196FA5D6E4BC318D14B9 /* SpringButton.swift */, + 40518C06CAE371BFC0BE82BC3A50C1D7 /* SpringImageView.swift */, + 74FBCA8F3B2C2D805E04C07CAF48388A /* SpringLabel.swift */, + 613C81BA1A69B2E743D1D800D703150F /* SpringTextField.swift */, + 2A717BEECD5EEB6190D8C62483DE7FF4 /* SpringTextView.swift */, + E1D086A3C3E0F7DA5ABF471FBCA3D240 /* SpringView.swift */, + 645D6DAE07B99FBBBD16C2B43BFCEB20 /* TransitionManager.swift */, + 742E609FC066E599E0D930001579E130 /* TransitionZoom.swift */, + DBA288AA5A64EBEA9AEB8589F9AE3C52 /* UnwindSegue.swift */, + 8701E2B11F35DAFDDCB5481FEB8E9D32 /* Resources */, + 3D220C91DD72A777ABCBE7243D50CFF8 /* Support Files */, + ); + path = Spring; + sourceTree = ""; + }; + D5B73FDE60F16582300B4C8A8BB2ED1C /* Pods */ = { + isa = PBXGroup; + children = ( + 4A42634F5D89AC97B4E29FECE125EAFD /* Bolts */, + 29FCC7E51C9FE1E926592508380F440A /* Parse */, + BF26F5507A74F8F2AB2155DBEE1E2E7A /* Spring */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 3B90072A8B711CB40567D2E517FEC322 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E4EAFC05818FC113E13B23A26FA0FD01 /* Pods-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 508DC92DFBAA819458A80D8A0A4C4722 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 797BEF6CAF596943EAB49AFA7BEC9AED /* Spring-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BB9496D4E7CCEE0645637499735927BA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0FD335B00E7676E2EDC2E0BF5AC57AA5 /* BFCancellationToken.h in Headers */, + 18757A3056E96BA4CEF1C5334C739262 /* BFCancellationTokenRegistration.h in Headers */, + C77BC43BFF3B430263AC543767085AAA /* BFCancellationTokenSource.h in Headers */, + D5C3D342B137CD83A87D8241D7155C1E /* BFExecutor.h in Headers */, + 0CE318213A7DB28E23158713AC90F18A /* BFTask.h in Headers */, + 503E50398C46B3ABD259B2D850B9AB60 /* BFTaskCompletionSource.h in Headers */, + F5FBB1976C2442DC3F082F6132711D9C /* Bolts-umbrella.h in Headers */, + 6871F0F406CA41B381B3219ED97C72D7 /* Bolts.h in Headers */, + D822BE5C8BAF3DEC4FDC0EFA8FDD56AF /* BoltsVersion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CC9145A4CAD18554980614775ACD704D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E59EBFA001F5ED2BA4E8D2481B9B7AF1 /* Parse-umbrella.h in Headers */, + B20710E63C4E138AD3E328D305EF3C86 /* Parse.h in Headers */, + 3D24E0BB7B049C1B2515A2529E6E4BE4 /* PF_Twitter.h in Headers */, + 5D30593714F4B89F2CE32EA762F33333 /* PFACL.h in Headers */, + 6E2EB632EAA13D7E3F253182D5EDAE5D /* PFAnalytics.h in Headers */, + 0D8E0DF3427DE55A8EEABBA5587BA965 /* PFAnonymousUtils.h in Headers */, + 61193CBBF52F5CE7B05778298EE7C844 /* PFCloud.h in Headers */, + 01E464D5C315BAE0E801A4559E89961B /* PFConfig.h in Headers */, + 2C651CA3DA49ABA78227D4B754B49C05 /* PFConstants.h in Headers */, + 879CA5F7D58EC1547F4C82A2E5AD6E59 /* PFFile.h in Headers */, + 91EB8F84EC24846D4B3D1EFFD96E94AD /* PFGeoPoint.h in Headers */, + 45A3A95C90692374E0749620800925FC /* PFInstallation.h in Headers */, + 6F5709124B3DC31E570B59BC705B546D /* PFNetworkActivityIndicatorManager.h in Headers */, + 4FC975C717DC62575D67107C9B8420FC /* PFNullability.h in Headers */, + EA55CD6E6FEF204B42995574A82522E7 /* PFObject+Subclass.h in Headers */, + 32F3F04EC8F9A3170C25D385A5C8E4E0 /* PFObject.h in Headers */, + FB2E0BD55E3872D4DC5E33AE37CAAFEF /* PFProduct.h in Headers */, + 9DEC37FC901BB00149A719DAB118D4C0 /* PFPurchase.h in Headers */, + F153419C493823327C2114199CE4C038 /* PFPush.h in Headers */, + E037326191F1E784EF7D79EE6B72A04F /* PFQuery.h in Headers */, + 3DA9ECEB4F067C9DC809B6C9BFB2DBD1 /* PFRelation.h in Headers */, + 4CAF488CD347DD5E69D90B8E65866D89 /* PFRole.h in Headers */, + A4A18156DB0EB293B90DD839C57DE56B /* PFSession.h in Headers */, + 942C7D6E4596F66CD67B254B20A19798 /* PFSubclassing.h in Headers */, + ADE3838A73F25EF67D4820CF9A96A782 /* PFTwitterUtils.h in Headers */, + B227E4390901BD518AFD52E8D4E9D4CC /* PFUser.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3329BF946FA72D0496326B27F8C5D93D /* Spring */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6C142D100B1FED2B5DA39A83389EBC90 /* Build configuration list for PBXNativeTarget "Spring" */; + buildPhases = ( + AF9F0CF82428E522B5CC17FB8BE3E209 /* Sources */, + A14A8ECFAC2964AE0BAD0B78F5318F91 /* Frameworks */, + 68266F0041E36DA21747FA8462E89C4D /* Resources */, + 508DC92DFBAA819458A80D8A0A4C4722 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Spring; + productName = Spring; + productReference = 63139E481C14F7BBCFB7506DE6E5B396 /* Spring.framework */; + productType = "com.apple.product-type.framework"; + }; + 66D9046CB8E6B543604FE2E6FFECE3DD /* Parse */ = { + isa = PBXNativeTarget; + buildConfigurationList = C116230CDE0631E7214042F74923E7D4 /* Build configuration list for PBXNativeTarget "Parse" */; + buildPhases = ( + 996C1F2E3A0C22EF3C0C3DB910F30821 /* Sources */, + 137677EB7290F620413E73E3A9337756 /* Frameworks */, + CC9145A4CAD18554980614775ACD704D /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + 20665B07EDF115762FCD400A347FC7CE /* PBXTargetDependency */, + ); + name = Parse; + productName = Parse; + productReference = 97CC8B00A137B81C8A95640C5E678726 /* Parse.framework */; + productType = "com.apple.product-type.framework"; + }; + BCA053B6430690326435042FEB61B458 /* Bolts */ = { + isa = PBXNativeTarget; + buildConfigurationList = B680C8B17CA11E478B53E94F8C3A9E2F /* Build configuration list for PBXNativeTarget "Bolts" */; + buildPhases = ( + 9A0A0D5F2792EC3D29818468BDA5DE86 /* Sources */, + D53A11166F299F697AFEFDB93699F0E3 /* Frameworks */, + BB9496D4E7CCEE0645637499735927BA /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Bolts; + productName = Bolts; + productReference = 4F2E2F7E83DD98B356A4A1A4B2C82BC6 /* Bolts.framework */; + productType = "com.apple.product-type.framework"; + }; + FAFDF522BFBDD6DBDBE9BAE62929D075 /* Pods */ = { + isa = PBXNativeTarget; + buildConfigurationList = B7E2512D6BA63729B3D0EE48FAF890BF /* Build configuration list for PBXNativeTarget "Pods" */; + buildPhases = ( + 2DDFA15A408444F60CEF5A051D1EE59B /* Sources */, + 829A0D84220A0BE484FCA0B14D5CEE2C /* Frameworks */, + 3B90072A8B711CB40567D2E517FEC322 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + F26DB4A96EFC5986544E8F6A729269C9 /* PBXTargetDependency */, + 980064033A15D23334EF0717CBD6A245 /* PBXTargetDependency */, + 05FC81F75BBF6E1159CBA016F8C787A4 /* PBXTargetDependency */, + ); + name = Pods; + productName = Pods; + productReference = 3114B214F966B2D67230A254E2805271 /* Pods.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = AF678C0C05BF517BB227DCB0791FA7D2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BCA053B6430690326435042FEB61B458 /* Bolts */, + 66D9046CB8E6B543604FE2E6FFECE3DD /* Parse */, + FAFDF522BFBDD6DBDBE9BAE62929D075 /* Pods */, + 3329BF946FA72D0496326B27F8C5D93D /* Spring */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 68266F0041E36DA21747FA8462E89C4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40A6C2C81777EDAB06DE786ACD638213 /* Images.xcassets in Resources */, + 86696F2ACC2F26F4BD6D9BFD35EF286B /* LoadingView.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2DDFA15A408444F60CEF5A051D1EE59B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 402AC683A87471CA3012A2EC3A6CE52E /* Pods-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 996C1F2E3A0C22EF3C0C3DB910F30821 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92EB8EFED4EFDF516B15A811A2D068AC /* Empty.m in Sources */, + C3E58ABB8DC1E32BC52F7FCC838562E3 /* Parse-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9A0A0D5F2792EC3D29818468BDA5DE86 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 67A6F11D09B28E52149E1B83C62DFAEB /* BFCancellationToken.m in Sources */, + 9F748C2CF1EB934C69834824507C57A7 /* BFCancellationTokenRegistration.m in Sources */, + C77D8080C4757D0A9D25A825DB1C6BE2 /* BFCancellationTokenSource.m in Sources */, + 9FD6846B525140DB8A487A4E943AA255 /* BFExecutor.m in Sources */, + 2FD3E73BAF45B63DBEB732030F7275E8 /* BFTask.m in Sources */, + 33158BB89047D7DCFA9159C7E911DBF4 /* BFTaskCompletionSource.m in Sources */, + 1C2813967EF8AFE6E23C70855A85C9F8 /* Bolts-dummy.m in Sources */, + 99904E00A2BA3DC6A12142B192039C5F /* Bolts.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF9F0CF82428E522B5CC17FB8BE3E209 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 85A319F4EC05C6D733FC16701A736159 /* AsyncButton.swift in Sources */, + ADF5698715A8B12530A74AD38753EADA /* AsyncImageView.swift in Sources */, + 9600B545AE4341D8EBE0D5249D0A8778 /* AutoTextView.swift in Sources */, + 69065F716924528B0E88C89CE8FD1E1D /* BlurView.swift in Sources */, + 3CAE2A7FFA706BF057AD210E1B21646D /* DesignableButton.swift in Sources */, + B674E36B5D5F03A1731DC8A15D3AF5C1 /* DesignableImageView.swift in Sources */, + A677DF0F8B36E163078D3CEC105D6980 /* DesignableLabel.swift in Sources */, + 12023BC59FFD5920814242A925C92856 /* DesignableTabBarController.swift in Sources */, + 6F24A392EE77F9BC86D8C6ACA612DD76 /* DesignableTextField.swift in Sources */, + E871588F36B3C18B062C065E16CB9491 /* DesignableTextView.swift in Sources */, + 0173657AE1BE4C4A6EF698CFE4A2E871 /* DesignableView.swift in Sources */, + 048C182AF8AA3E7F56B0DCE963595E62 /* ImageLoader.swift in Sources */, + 34C41EE6BC98C43CAE565D55866F93E1 /* KeyboardLayoutConstraint.swift in Sources */, + 1A78CB1DA6EF6CF1A54E27064C993B97 /* LoadingView.swift in Sources */, + 78F1A0E4B758A1DEB7026AA08A67AA8D /* Misc.swift in Sources */, + DA7BD818A492AE5CA41B1D541F958C99 /* SoundPlayer.swift in Sources */, + 161563B8950E5827BC41EBE5BD6E45A7 /* Spring-dummy.m in Sources */, + CA7B258C22505CCF22377B8DE0CF71DF /* Spring.swift in Sources */, + C5F5302ECA7AAC39A2FE6F20AC37F185 /* SpringAnimation.swift in Sources */, + 0F97E480AEE9F6B862B53874923A1FD5 /* SpringButton.swift in Sources */, + 27DF16D5626EB896AD8DDC2F64206911 /* SpringImageView.swift in Sources */, + 475731D4AAAAAB8F245ACD705228AA09 /* SpringLabel.swift in Sources */, + 9930B9FEF95F4557476EBA8C3422D3D2 /* SpringTextField.swift in Sources */, + 0CD486C05BAC3B9E3864298F483CCDF6 /* SpringTextView.swift in Sources */, + 9385A34223C160C4B574ABFE60FA3FEA /* SpringView.swift in Sources */, + 2162B43C7759EDCD6E60F61D5A9D1400 /* TransitionManager.swift in Sources */, + 07BAB8C0C46E40C8275641B40ECE1738 /* TransitionZoom.swift in Sources */, + 0BA7E85FCDD2D4FB442F4832501766CC /* UnwindSegue.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 05FC81F75BBF6E1159CBA016F8C787A4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Spring; + target = 3329BF946FA72D0496326B27F8C5D93D /* Spring */; + targetProxy = 3EFCD389412FB1DB1C62FAD573660C99 /* PBXContainerItemProxy */; + }; + 20665B07EDF115762FCD400A347FC7CE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Bolts; + target = BCA053B6430690326435042FEB61B458 /* Bolts */; + targetProxy = 8D9CAB84CE13E2AC5F94681FAB7A9591 /* PBXContainerItemProxy */; + }; + 980064033A15D23334EF0717CBD6A245 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Parse; + target = 66D9046CB8E6B543604FE2E6FFECE3DD /* Parse */; + targetProxy = 291DC93D39D47039E216E0404EBA5546 /* PBXContainerItemProxy */; + }; + F26DB4A96EFC5986544E8F6A729269C9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Bolts; + target = BCA053B6430690326435042FEB61B458 /* Bolts */; + targetProxy = EFB84C6601ECE4AB3F0767E68201EA94 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 11C09C9B8C287FC351730FFC9BC8E672 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9AA7B81FC5EFA9DECEC22FADD358F630 /* Parse.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Parse/Parse-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Parse/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Parse/Parse.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Parse; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 1F9064FE565822247736A51A08B2DB96 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9AA7B81FC5EFA9DECEC22FADD358F630 /* Parse.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Parse/Parse-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Parse/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Parse/Parse.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = Parse; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 25E5F8E2C6B9F89810A51F085C8F0B0D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6F715E38101B9425073EAEB1BFE551CB /* Spring.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Spring/Spring-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Spring/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Spring/Spring.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = Spring; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 511103F7F15A7E8F83B268EA03462CAB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5B6982DDC9F46EFA672EFEAAEC07E588 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 007426D4289E40D231F74EFE9A6E38EB /* Bolts.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Bolts/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Bolts/Bolts.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = Bolts; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 8FF195389DED67F8C6D548F1EB875CBE /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 977577C045EDA9D9D1F46E2598D19FC7 /* Pods.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + INFOPLIST_FILE = "Target Support Files/Pods/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods/Pods.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = Pods; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 97E5B27788C59888F89C8F9FAA0562DF /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6F715E38101B9425073EAEB1BFE551CB /* Spring.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Spring/Spring-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Spring/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Spring/Spring.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Spring; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + AA05AF9C3A14EE0E32F42C6E6D42D34F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + ONLY_ACTIVE_ARCH = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + C74ACB4A5D38BF163C2AF001D6988AC7 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 007426D4289E40D231F74EFE9A6E38EB /* Bolts.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Bolts/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Bolts/Bolts.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Bolts; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + DB177A96CC978495462D41D8CC896C94 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DA312349A49333542E6F4B36B329960E /* Pods.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + INFOPLIST_FILE = "Target Support Files/Pods/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.4; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods/Pods.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = Pods; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AA05AF9C3A14EE0E32F42C6E6D42D34F /* Debug */, + 511103F7F15A7E8F83B268EA03462CAB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6C142D100B1FED2B5DA39A83389EBC90 /* Build configuration list for PBXNativeTarget "Spring" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 25E5F8E2C6B9F89810A51F085C8F0B0D /* Debug */, + 97E5B27788C59888F89C8F9FAA0562DF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B680C8B17CA11E478B53E94F8C3A9E2F /* Build configuration list for PBXNativeTarget "Bolts" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5B6982DDC9F46EFA672EFEAAEC07E588 /* Debug */, + C74ACB4A5D38BF163C2AF001D6988AC7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B7E2512D6BA63729B3D0EE48FAF890BF /* Build configuration list for PBXNativeTarget "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8FF195389DED67F8C6D548F1EB875CBE /* Debug */, + DB177A96CC978495462D41D8CC896C94 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C116230CDE0631E7214042F74923E7D4 /* Build configuration list for PBXNativeTarget "Parse" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1F9064FE565822247736A51A08B2DB96 /* Debug */, + 11C09C9B8C287FC351730FFC9BC8E672 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Pods/Spring/LICENSE b/Pods/Spring/LICENSE new file mode 100644 index 0000000..2b55794 --- /dev/null +++ b/Pods/Spring/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014-2015 Meng To (meng@designcode.io) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Pods/Spring/README.md b/Pods/Spring/README.md new file mode 100644 index 0000000..7daf4d6 --- /dev/null +++ b/Pods/Spring/README.md @@ -0,0 +1,113 @@ +![](http://cl.ly/image/012R0D3R3x2g/download/springswift2.jpg) + +## Updated for Swift 2 +This update will be in this branch until Swift 2 is out of beta. + +## Installation +Drop in the Spring folder to your Xcode project. + +Or via CocoaPods: +``` +use_frameworks! +pod 'Spring', :git => 'https://github.com/MengTo/Spring.git', :branch => 'swift2' +``` + + +## Usage with Storyboard +In Identity Inspector, connect the UIView to SpringView Class and set the animation properties in Attribute Inspector. + +![](http://cl.ly/image/241o0G1G3S36/download/springsetup.jpg) + +## Usage with Code + layer.animation = "squeezeDown" + layer.animate() + +## Demo The Animations +![](http://cl.ly/image/1n1E2j3W3y24/springscreen.jpg) + +## Chaining Animations + layer.y = -50 + animateToNext { + layer.animation = "fall" + layer.animateTo() + } + +## Functions + animate() + animateNext { ... } + animateTo() + animateToNext { ... } + +## Animation + shake + pop + morph + squeeze + wobble + swing + flipX + flipY + fall + squeezeLeft + squeezeRight + squeezeDown + squeezeUp + slideLeft + slideRight + slideDown + slideUp + fadeIn + fadeOut + fadeInLeft + fadeInRight + fadeInDown + fadeInUp + zoomIn + zoomOut + flash + +## Curve + spring + linear + easeIn + easeOut + easeInOut + +## Properties + force + duration + delay + damping + velocity + repeatCount + scale + x + y + rotate + +\* Not all properties work together. Play with the demo app. + + +## Autostart +Allows you to animate without code. Don't need to use this is if you plan to start the animation in code. + +## Autohide +Saves you the hassle of adding a line "layer.alpha = 0" in viewDidLoad(). + +## Known issue +Animations won't autostart when view is reached via performSegueWithIdentifier. + +Animations using IBInspectables are currently not working in iOS 7. iOS 8 is supported. We're looking for a fix. Animations in code works for both iOS 7 and 8. + +This project now requires Xcode 6.3 and Swift 1.2. For old version please download [1.0.2](https://github.com/MengTo/Spring/tree/1.0.2) + +## Tutorials +- Tutorials available on [Design+Code](https://designcode.io/swiftapp). +- [Integrate Spring to existing Objective-C projects](https://medium.com/ios-apprentice/using-swift-in-objective-c-projects-f7e7a09f8be) + +## ChangeLog +- At [ChangeLog](https://github.com/MengTo/Spring/wiki/CHANGELOG) wiki page + +## License + +Spring is released under the MIT license. See LICENSE for details. diff --git a/Spring/AsyncButton.swift b/Pods/Spring/Spring/AsyncButton.swift similarity index 100% rename from Spring/AsyncButton.swift rename to Pods/Spring/Spring/AsyncButton.swift diff --git a/Spring/AsyncImageView.swift b/Pods/Spring/Spring/AsyncImageView.swift similarity index 95% rename from Spring/AsyncImageView.swift rename to Pods/Spring/Spring/AsyncImageView.swift index 0e20cdf..f3ac178 100644 --- a/Spring/AsyncImageView.swift +++ b/Pods/Spring/Spring/AsyncImageView.swift @@ -34,7 +34,7 @@ public class AsyncImageView: UIImageView { if let strongSelf = self { dispatch_async(dispatch_get_main_queue(), { () -> Void in if strongSelf.url?.absoluteString == url { - strongSelf.image = image + strongSelf.image = image ?? strongSelf.placeholderImage } }) } diff --git a/Spring/AutoTextView.swift b/Pods/Spring/Spring/AutoTextView.swift similarity index 69% rename from Spring/AutoTextView.swift rename to Pods/Spring/Spring/AutoTextView.swift index abc4e9d..3abced4 100644 --- a/Spring/AutoTextView.swift +++ b/Pods/Spring/Spring/AutoTextView.swift @@ -1,15 +1,15 @@ // -// TextView.swift -// DNApp +// AutoTextView.swift +// SpringApp // -// Created by Meng To on 2015-03-02. +// Created by Meng To on 2015-03-27. // Copyright (c) 2015 Meng To. All rights reserved. // import UIKit -class AutoTextView: UITextView { - override func intrinsicContentSize() -> CGSize { +public class AutoTextView: UITextView { + override public func intrinsicContentSize() -> CGSize { var size = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max)) size.width = self.frame.size.width if text.length == 0 { diff --git a/Spring/BlurView.swift b/Pods/Spring/Spring/BlurView.swift old mode 100755 new mode 100644 similarity index 89% rename from Spring/BlurView.swift rename to Pods/Spring/Spring/BlurView.swift index 4583633..d7871ee --- a/Spring/BlurView.swift +++ b/Pods/Spring/Spring/BlurView.swift @@ -22,11 +22,12 @@ import UIKit -public func insertBlurView (view: UIView, style: UIBlurEffectStyle) { +public func insertBlurView (view: UIView, style: UIBlurEffectStyle) -> UIVisualEffectView { view.backgroundColor = UIColor.clearColor() - var blurEffect = UIBlurEffect(style: style) - var blurEffectView = UIVisualEffectView(effect: blurEffect) + let blurEffect = UIBlurEffect(style: style) + let blurEffectView = UIVisualEffectView(effect: blurEffect) blurEffectView.frame = view.bounds view.insertSubview(blurEffectView, atIndex: 0) + return blurEffectView } \ No newline at end of file diff --git a/Spring/DesignableButton.swift b/Pods/Spring/Spring/DesignableButton.swift old mode 100755 new mode 100644 similarity index 100% rename from Spring/DesignableButton.swift rename to Pods/Spring/Spring/DesignableButton.swift diff --git a/Spring/DesignableImageView.swift b/Pods/Spring/Spring/DesignableImageView.swift old mode 100755 new mode 100644 similarity index 100% rename from Spring/DesignableImageView.swift rename to Pods/Spring/Spring/DesignableImageView.swift diff --git a/Spring/DesignableLabel.swift b/Pods/Spring/Spring/DesignableLabel.swift old mode 100755 new mode 100644 similarity index 88% rename from Spring/DesignableLabel.swift rename to Pods/Spring/Spring/DesignableLabel.swift index e982cb4..146174b --- a/Spring/DesignableLabel.swift +++ b/Pods/Spring/Spring/DesignableLabel.swift @@ -26,13 +26,13 @@ import UIKit @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font.fontName, size: self.font.pointSize) + let text = self.text - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) + let attributedString = NSMutableAttributedString(string: text!) attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) diff --git a/Spring/DesignableTabBarController.swift b/Pods/Spring/Spring/DesignableTabBarController.swift old mode 100755 new mode 100644 similarity index 89% rename from Spring/DesignableTabBarController.swift rename to Pods/Spring/Spring/DesignableTabBarController.swift index fc57f65..16e9887 --- a/Spring/DesignableTabBarController.swift +++ b/Pods/Spring/Spring/DesignableTabBarController.swift @@ -47,7 +47,7 @@ import UIKit @IBInspectable var firstSelectedImage: UIImage? { didSet { if let image = firstSelectedImage { - var tabBarItems = self.tabBar.items as! [UITabBarItem] + var tabBarItems = self.tabBar.items as [UITabBarItem]! tabBarItems[0].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) } } @@ -56,7 +56,7 @@ import UIKit @IBInspectable var secondSelectedImage: UIImage? { didSet { if let image = secondSelectedImage { - var tabBarItems = self.tabBar.items as! [UITabBarItem] + var tabBarItems = self.tabBar.items as [UITabBarItem]! tabBarItems[1].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) } } @@ -65,7 +65,7 @@ import UIKit @IBInspectable var thirdSelectedImage: UIImage? { didSet { if let image = thirdSelectedImage { - var tabBarItems = self.tabBar.items as! [UITabBarItem] + var tabBarItems = self.tabBar.items as [UITabBarItem]! tabBarItems[2].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) } } @@ -74,7 +74,7 @@ import UIKit @IBInspectable var fourthSelectedImage: UIImage? { didSet { if let image = fourthSelectedImage { - var tabBarItems = self.tabBar.items as! [UITabBarItem] + var tabBarItems = self.tabBar.items as [UITabBarItem]! tabBarItems[3].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) } } @@ -83,7 +83,7 @@ import UIKit @IBInspectable var fifthSelectedImage: UIImage? { didSet { if let image = fifthSelectedImage { - var tabBarItems = self.tabBar.items as! [UITabBarItem] + var tabBarItems = self.tabBar.items as [UITabBarItem]! tabBarItems[4].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) } } @@ -92,7 +92,7 @@ import UIKit override func viewDidLoad() { super.viewDidLoad() - for item in self.tabBar.items as! [UITabBarItem] { + for item in self.tabBar.items as [UITabBarItem]! { if let image = item.image { item.image = image.imageWithColor(self.normalTint).imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) } @@ -104,10 +104,10 @@ extension UIImage { func imageWithColor(tintColor: UIColor) -> UIImage { UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) - let context = UIGraphicsGetCurrentContext() as CGContextRef + let context = UIGraphicsGetCurrentContext() CGContextTranslateCTM(context, 0, self.size.height) CGContextScaleCTM(context, 1.0, -1.0); - CGContextSetBlendMode(context, kCGBlendModeNormal) + CGContextSetBlendMode(context, CGBlendMode.Normal) let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect CGContextClipToMask(context, rect, self.CGImage) diff --git a/Spring/DesignableTextField.swift b/Pods/Spring/Spring/DesignableTextField.swift old mode 100755 new mode 100644 similarity index 87% rename from Spring/DesignableTextField.swift rename to Pods/Spring/Spring/DesignableTextField.swift index 7d70e2b..2a60b53 --- a/Spring/DesignableTextField.swift +++ b/Pods/Spring/Spring/DesignableTextField.swift @@ -34,7 +34,7 @@ import UIKit @IBInspectable public var sidePadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, sidePadding, sidePadding)) + let padding = UIView(frame: CGRectMake(0, 0, sidePadding, sidePadding)) leftViewMode = UITextFieldViewMode.Always leftView = padding @@ -46,7 +46,7 @@ import UIKit @IBInspectable public var leftPadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, leftPadding, 0)) + let padding = UIView(frame: CGRectMake(0, 0, leftPadding, 0)) leftViewMode = UITextFieldViewMode.Always leftView = padding @@ -55,7 +55,7 @@ import UIKit @IBInspectable public var rightPadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, 0, rightPadding)) + let padding = UIView(frame: CGRectMake(0, 0, rightPadding, 0)) rightViewMode = UITextFieldViewMode.Always rightView = padding @@ -82,13 +82,13 @@ import UIKit @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + let text = self.text - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) + let attributedString = NSMutableAttributedString(string: text!) attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) diff --git a/Spring/DesignableTextView.swift b/Pods/Spring/Spring/DesignableTextView.swift old mode 100755 new mode 100644 similarity index 84% rename from Spring/DesignableTextView.swift rename to Pods/Spring/Spring/DesignableTextView.swift index 7e4b899..27fe285 --- a/Spring/DesignableTextView.swift +++ b/Pods/Spring/Spring/DesignableTextView.swift @@ -41,22 +41,16 @@ import UIKit layer.cornerRadius = cornerRadius } } - - @IBInspectable public var containerInset: CGFloat = 0 { - didSet { - contentInset = UIEdgeInsetsMake(-4, -4, -4, -4) - } - } @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + let text = self.text - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) + let attributedString = NSMutableAttributedString(string: text!) attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) diff --git a/Spring/DesignableView.swift b/Pods/Spring/Spring/DesignableView.swift old mode 100755 new mode 100644 similarity index 100% rename from Spring/DesignableView.swift rename to Pods/Spring/Spring/DesignableView.swift diff --git a/Spring/ImageLoader.swift b/Pods/Spring/Spring/ImageLoader.swift similarity index 87% rename from Spring/ImageLoader.swift rename to Pods/Spring/Spring/ImageLoader.swift index fe13699..eacd05e 100755 --- a/Spring/ImageLoader.swift +++ b/Pods/Spring/Spring/ImageLoader.swift @@ -37,7 +37,7 @@ public class ImageLoader { public func imageForUrl(urlString: String, completionHandler:(image: UIImage?, url: String) -> ()) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in - var data: NSData? = self.cache.objectForKey(urlString) as? NSData + let data: NSData? = self.cache.objectForKey(urlString) as? NSData if let goodData = data { let image = UIImage(data: goodData) @@ -47,23 +47,23 @@ public class ImageLoader { return } - var downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: {(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in + let downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: { (data, response, error) -> Void in if (error != nil) { completionHandler(image: nil, url: urlString) return } if data != nil { - let image = UIImage(data: data) - self.cache.setObject(data, forKey: urlString) + let image = UIImage(data: data!) + self.cache.setObject(data!, forKey: urlString) dispatch_async(dispatch_get_main_queue(), {() in completionHandler(image: image, url: urlString) }) return } - }) downloadTask.resume() + }) } diff --git a/Spring/KeyboardLayoutConstraint.swift b/Pods/Spring/Spring/KeyboardLayoutConstraint.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/KeyboardLayoutConstraint.swift rename to Pods/Spring/Spring/KeyboardLayoutConstraint.swift index b8dfe5e..1fad0b5 --- a/Spring/KeyboardLayoutConstraint.swift +++ b/Pods/Spring/Spring/KeyboardLayoutConstraint.swift @@ -53,7 +53,7 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) { case let (.Some(duration), .Some(curve)): - let options = UIViewAnimationOptions(curve.unsignedLongValue) + let options = UIViewAnimationOptions(rawValue: curve.unsignedLongValue) UIView.animateWithDuration( NSTimeInterval(duration.doubleValue), @@ -82,7 +82,7 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) { case let (.Some(duration), .Some(curve)): - let options = UIViewAnimationOptions(curve.unsignedLongValue) + let options = UIViewAnimationOptions(rawValue: curve.unsignedLongValue) UIView.animateWithDuration( NSTimeInterval(duration.doubleValue), diff --git a/Spring/LoadingView.swift b/Pods/Spring/Spring/LoadingView.swift old mode 100755 new mode 100644 similarity index 92% rename from Spring/LoadingView.swift rename to Pods/Spring/Spring/LoadingView.swift index 8884037..8ef23be --- a/Spring/LoadingView.swift +++ b/Pods/Spring/Spring/LoadingView.swift @@ -49,7 +49,7 @@ public extension UIView { public func showLoading() { - if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { + if self.viewWithTag(LoadingViewConstants.Tag) != nil { // If loading view is already found in current view hierachy, do nothing return } @@ -60,7 +60,7 @@ public extension UIView { self.addSubview(loadingXibView) loadingXibView.alpha = 0 - spring(0.7, { + SpringAnimation.spring(0.7, animations: { loadingXibView.alpha = 1 }) } @@ -70,10 +70,10 @@ public extension UIView { if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { loadingXibView.alpha = 1 - springWithCompletion(0.7, { + SpringAnimation.springWithCompletion(0.7, animations: { loadingXibView.alpha = 0 loadingXibView.transform = CGAffineTransformMakeScale(3, 3) - }, { (completed) -> Void in + }, completion: { (completed) -> Void in loadingXibView.removeFromSuperview() }) } diff --git a/Spring/LoadingView.xib b/Pods/Spring/Spring/LoadingView.xib old mode 100755 new mode 100644 similarity index 100% rename from Spring/LoadingView.xib rename to Pods/Spring/Spring/LoadingView.xib diff --git a/Spring/Misc.swift b/Pods/Spring/Spring/Misc.swift old mode 100755 new mode 100644 similarity index 62% rename from Spring/Misc.swift rename to Pods/Spring/Spring/Misc.swift index e75d296..a2aa327 --- a/Spring/Misc.swift +++ b/Pods/Spring/Spring/Misc.swift @@ -23,7 +23,7 @@ import UIKit public extension String { - public var length: Int { return count(self) } + public var length: Int { return self.characters.count } public func toURL() -> NSURL? { return NSURL(string: self) @@ -32,7 +32,12 @@ public extension String { public func htmlToAttributedString(text: String) -> NSAttributedString! { let htmlData = text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) - let htmlString = NSAttributedString(data: htmlData!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil) + let htmlString: NSAttributedString? + do { + htmlString = try NSAttributedString(data: htmlData!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) + } catch _ { + htmlString = nil + } return htmlString } @@ -62,40 +67,40 @@ public extension UIColor { var green: CGFloat = 0.0 var blue: CGFloat = 0.0 var alpha: CGFloat = 1.0 + var hex: String = hex if hex.hasPrefix("#") { - let index = advance(hex.startIndex, 1) - let hex = hex.substringFromIndex(index) - let scanner = NSScanner(string: hex) - var hexValue: CUnsignedLongLong = 0 - if scanner.scanHexLongLong(&hexValue) { - switch (count(hex)) { - case 3: - red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 - green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 - blue = CGFloat(hexValue & 0x00F) / 15.0 - case 4: - red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 - green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 - blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 - alpha = CGFloat(hexValue & 0x000F) / 15.0 - case 6: - red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 - green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 - blue = CGFloat(hexValue & 0x0000FF) / 255.0 - case 8: - red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 - green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 - blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 - alpha = CGFloat(hexValue & 0x000000FF) / 255.0 - default: - print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8") - } - } else { - println("Scan hex error") + let index = hex.startIndex.advancedBy(1) + hex = hex.substringFromIndex(index) + } + + let scanner = NSScanner(string: hex) + var hexValue: CUnsignedLongLong = 0 + if scanner.scanHexLongLong(&hexValue) { + switch (hex.characters.count) { + case 3: + red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 + green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 + blue = CGFloat(hexValue & 0x00F) / 15.0 + case 4: + red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 + green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 + blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 + alpha = CGFloat(hexValue & 0x000F) / 15.0 + case 6: + red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 + green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 + blue = CGFloat(hexValue & 0x0000FF) / 255.0 + case 8: + red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 + green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat(hexValue & 0x000000FF) / 255.0 + default: + print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") } } else { - print("Invalid RGB string, missing '#' as prefix") + print("Scan hex error") } self.init(red:red, green:green, blue:blue, alpha:alpha) } @@ -115,37 +120,31 @@ public func UIColorFromRGB(rgbValue: UInt) -> UIColor { ) } -var dateFormatter : NSDateFormatter? - public func stringFromDate(date: NSDate, format: String) -> String { - - if dateFormatter == nil { - dateFormatter = NSDateFormatter() - } - - dateFormatter!.dateFormat = format - return dateFormatter!.stringFromDate(date) + let dateFormatter = NSDateFormatter() + dateFormatter.dateFormat = format + return dateFormatter.stringFromDate(date) } public func dateFromString(date: String, format: String) -> NSDate { - - if dateFormatter == nil { - dateFormatter = NSDateFormatter() + let dateFormatter = NSDateFormatter() + dateFormatter.dateFormat = format + if let date = dateFormatter.dateFromString(date) { + return date + } else { + return NSDate(timeIntervalSince1970: 0) } - - dateFormatter!.dateFormat = format - return dateFormatter!.dateFromString(date)! } public func randomStringWithLength (len : Int) -> NSString { let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var randomString : NSMutableString = NSMutableString(capacity: len) + let randomString : NSMutableString = NSMutableString(capacity: len) for (var i=0; i < len; i++){ - var length = UInt32 (letters.length) - var rand = arc4random_uniform(length) + let length = UInt32 (letters.length) + let rand = arc4random_uniform(length) randomString.appendFormat("%C", letters.characterAtIndex(Int(rand))) } @@ -154,11 +153,11 @@ public func randomStringWithLength (len : Int) -> NSString { public func timeAgoSinceDate(date:NSDate, numericDates:Bool) -> String { let calendar = NSCalendar.currentCalendar() - let unitFlags = NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitWeekOfYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitSecond + let unitFlags: NSCalendarUnit = [NSCalendarUnit.Minute, NSCalendarUnit.Hour, NSCalendarUnit.Day, NSCalendarUnit.WeekOfYear, NSCalendarUnit.Month, NSCalendarUnit.Year, NSCalendarUnit.Second] let now = NSDate() let earliest = now.earlierDate(date) - let latest = now.laterDate(date) - let components:NSDateComponents = calendar.components(unitFlags, fromDate: earliest, toDate: latest, options: nil) + let latest = (earliest == now) ? date : now + let components: NSDateComponents = calendar.components(unitFlags, fromDate: earliest, toDate: latest, options: []) if (components.year >= 2) { return "\(components.year)y" @@ -169,12 +168,12 @@ public func timeAgoSinceDate(date:NSDate, numericDates:Bool) -> String { return "1y" } } else if (components.month >= 2) { - return "\(components.month)" + return "\(components.month * 4)w" } else if (components.month >= 1){ if (numericDates){ - return "1M" + return "4w" } else { - return "1M" + return "4w" } } else if (components.weekOfYear >= 2) { return "\(components.weekOfYear)w" diff --git a/Spring/SoundPlayer.swift b/Pods/Spring/Spring/SoundPlayer.swift old mode 100755 new mode 100644 similarity index 82% rename from Spring/SoundPlayer.swift rename to Pods/Spring/Spring/SoundPlayer.swift index 6fc5505..11b595a --- a/Spring/SoundPlayer.swift +++ b/Pods/Spring/Spring/SoundPlayer.swift @@ -23,16 +23,16 @@ import UIKit import AudioToolbox -struct SoundPlayer { +public class SoundPlayer: NSObject { - static var filename : String? - static var enabled : Bool = true + @IBInspectable var filename : String? + @IBInspectable var enabled : Bool = true private struct Internal { static var cache = [NSURL:SystemSoundID]() } - static func playSound(soundFile: String) { + public func playSound(soundFile:String) { if !enabled { return @@ -50,11 +50,13 @@ struct SoundPlayer { AudioServicesPlaySystemSound(soundID) } else { - println("Could not find sound file name `\(soundFile)`") + print("Could not find sound file name `\(soundFile)`") } } - static func play(file: String) { - self.playSound(file) + @IBAction public func play(sender: AnyObject?) { + if let filename = filename { + self.playSound(filename) + } } } diff --git a/Pods/Spring/Spring/Spring.swift b/Pods/Spring/Spring/Spring.swift new file mode 100644 index 0000000..06c7bf7 --- /dev/null +++ b/Pods/Spring/Spring/Spring.swift @@ -0,0 +1,530 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@objc public protocol Springable { + var autostart: Bool { get set } + var autohide: Bool { get set } + var animation: String { get set } + var force: CGFloat { get set } + var delay: CGFloat { get set } + var duration: CGFloat { get set } + var damping: CGFloat { get set } + var velocity: CGFloat { get set } + var repeatCount: Float { get set } + var x: CGFloat { get set } + var y: CGFloat { get set } + var scaleX: CGFloat { get set } + var scaleY: CGFloat { get set } + var rotate: CGFloat { get set } + var opacity: CGFloat { get set } + var animateFrom: Bool { get set } + var curve: String { get set } + + // UIView + var layer : CALayer { get } + var transform : CGAffineTransform { get set } + var alpha : CGFloat { get set } + + func animate() + func animateNext(completion: () -> ()) + func animateTo() + func animateToNext(completion: () -> ()) +} + +public class Spring : NSObject { + + private unowned var view : Springable + private var shouldAnimateAfterActive = false + private var shouldAnimateInLayoutSubviews = true + + init(_ view: Springable) { + self.view = view + super.init() + commonInit() + } + + func commonInit() { + NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBecomeActiveNotification:", name: UIApplicationDidBecomeActiveNotification, object: nil) + } + + func didBecomeActiveNotification(notification: NSNotification) { + if shouldAnimateAfterActive { + alpha = 0 + animate() + shouldAnimateAfterActive = false + } + } + + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidBecomeActiveNotification, object: nil) + } + + private var autostart: Bool { set { self.view.autostart = newValue } get { return self.view.autostart }} + private var autohide: Bool { set { self.view.autohide = newValue } get { return self.view.autohide }} + private var animation: String { set { self.view.animation = newValue } get { return self.view.animation }} + private var force: CGFloat { set { self.view.force = newValue } get { return self.view.force }} + private var delay: CGFloat { set { self.view.delay = newValue } get { return self.view.delay }} + private var duration: CGFloat { set { self.view.duration = newValue } get { return self.view.duration }} + private var damping: CGFloat { set { self.view.damping = newValue } get { return self.view.damping }} + private var velocity: CGFloat { set { self.view.velocity = newValue } get { return self.view.velocity }} + private var repeatCount: Float { set { self.view.repeatCount = newValue } get { return self.view.repeatCount }} + private var x: CGFloat { set { self.view.x = newValue } get { return self.view.x }} + private var y: CGFloat { set { self.view.y = newValue } get { return self.view.y }} + private var scaleX: CGFloat { set { self.view.scaleX = newValue } get { return self.view.scaleX }} + private var scaleY: CGFloat { set { self.view.scaleY = newValue } get { return self.view.scaleY }} + private var rotate: CGFloat { set { self.view.rotate = newValue } get { return self.view.rotate }} + private var opacity: CGFloat { set { self.view.opacity = newValue } get { return self.view.opacity }} + private var animateFrom: Bool { set { self.view.animateFrom = newValue } get { return self.view.animateFrom }} + private var curve: String { set { self.view.curve = newValue } get { return self.view.curve }} + + // UIView + private var layer : CALayer { return view.layer } + private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} + private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } + + public enum AnimationPreset: String { + case SlideLeft = "slideLeft" + case SlideRight = "slideRight" + case SlideDown = "slideDown" + case SlideUp = "slideUp" + case SqueezeLeft = "squeezeLeft" + case SqueezeRight = "squeezeRight" + case SqueezeDown = "squeezeDown" + case SqueezeUp = "squeezeUp" + case FadeIn = "fadeIn" + case FadeOut = "fadeOut" + case FadeOutIn = "fadeOutIn" + case FadeInLeft = "fadeInLeft" + case FadeInRight = "fadeInRight" + case FadeInDown = "fadeInDown" + case FadeInUp = "fadeInUp" + case ZoomIn = "zoomIn" + case ZoomOut = "zoomOut" + case Fall = "fall" + case Shake = "shake" + case Pop = "pop" + case FlipX = "flipX" + case FlipY = "flipY" + case Morph = "morph" + case Squeeze = "squeeze" + case Flash = "flash" + case Wobble = "wobble" + case Swing = "swing" + } + + public enum AnimationCurve: String { + case EaseIn = "easeIn" + case EaseOut = "easeOut" + case EaseInOut = "easeInOut" + case Linear = "linear" + case Spring = "spring" + case EaseInSine = "easeInSine" + case EaseOutSine = "easeOutSine" + case EaseInOutSine = "easeInOutSine" + case EaseInQuad = "easeInQuad" + case EaseOutQuad = "easeOutQuad" + case EaseInOutQuad = "easeInOutQuad" + case EaseInCubic = "easeInCubic" + case EaseOutCubic = "easeOutCubic" + case EaseInOutCubic = "easeInOutCubic" + case EaseInQuart = "easeInQuart" + case EaseOutQuart = "easeOutQuart" + case EaseInOutQuart = "easeInOutQuart" + case EaseInQuint = "easeInQuint" + case EaseOutQuint = "easeOutQuint" + case EaseInOutQuint = "easeInOutQuint" + case EaseInExpo = "easeInExpo" + case EaseOutExpo = "easeOutExpo" + case EaseInOutExpo = "easeInOutExpo" + case EaseInCirc = "easeInCirc" + case EaseOutCirc = "easeOutCirc" + case EaseInOutCirc = "easeInOutCirc" + case EaseInBack = "easeInBack" + case EaseOutBack = "easeOutBack" + case EaseInOutBack = "easeInOutBack" + } + + func animatePreset() { + alpha = 0.99 + if let animation = AnimationPreset(rawValue: animation) { + switch animation { + case .SlideLeft: + x = 300*force + case .SlideRight: + x = -300*force + case .SlideDown: + y = -300*force + case .SlideUp: + y = 300*force + case .SqueezeLeft: + x = 300 + scaleX = 3*force + case .SqueezeRight: + x = -300 + scaleX = 3*force + case .SqueezeDown: + y = -300 + scaleY = 3*force + case .SqueezeUp: + y = 300 + scaleY = 3*force + case .FadeIn: + opacity = 0 + case .FadeOut: + animateFrom = false + opacity = 0 + case .FadeOutIn: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.timingFunction = getTimingFunction(curve) + animation.duration = CFTimeInterval(duration) + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.autoreverses = true + layer.addAnimation(animation, forKey: "fade") + case .FadeInLeft: + opacity = 0 + x = 300*force + case .FadeInRight: + x = -300*force + opacity = 0 + case .FadeInDown: + y = -300*force + opacity = 0 + case .FadeInUp: + y = 300*force + opacity = 0 + case .ZoomIn: + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .ZoomOut: + animateFrom = false + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .Fall: + animateFrom = false + rotate = 15 * CGFloat(M_PI/180) + y = 600*force + case .Shake: + let animation = CAKeyframeAnimation() + animation.keyPath = "position.x" + animation.values = [0, 30*force, -30*force, 30*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve) + animation.duration = CFTimeInterval(duration) + animation.additive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(animation, forKey: "shake") + case .Pop: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.scale" + animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve) + animation.duration = CFTimeInterval(duration) + animation.additive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(animation, forKey: "pop") + case .FlipX: + rotate = 0 + scaleX = 1 + scaleY = 1 + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(CATransform3D: + CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(CATransform3D: + CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0))) + animation.duration = CFTimeInterval(duration) + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve) + layer.addAnimation(animation, forKey: "3d") + case .FlipY: + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(CATransform3D: + CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(CATransform3D: + CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0))) + animation.duration = CFTimeInterval(duration) + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve) + layer.addAnimation(animation, forKey: "3d") + case .Morph: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.7, 1.3*force, 0.7, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(morphY, forKey: "morphY") + case .Squeeze: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.5, 1, 0.5, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(morphY, forKey: "morphY") + case .Flash: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount * 2.0 + animation.autoreverses = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(animation, forKey: "flash") + case .Wobble: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.additive = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(animation, forKey: "wobble") + + let x = CAKeyframeAnimation() + x.keyPath = "position.x" + x.values = [0, 30*force, -30*force, 30*force, 0] + x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + x.timingFunction = getTimingFunction(curve) + x.duration = CFTimeInterval(duration) + x.additive = true + x.repeatCount = repeatCount + x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(x, forKey: "x") + case .Swing: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.additive = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.addAnimation(animation, forKey: "swing") + } + } + } + + func getTimingFunction(curve: String) -> CAMediaTimingFunction { + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .EaseIn: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) + case .EaseOut: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) + case .EaseInOut: return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + case .Linear: return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) + case .Spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) + case .EaseInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) + case .EaseOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) + case .EaseInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) + case .EaseInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) + case .EaseOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) + case .EaseInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) + case .EaseInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) + case .EaseOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) + case .EaseInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) + case .EaseInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) + case .EaseOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) + case .EaseInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + case .EaseInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) + case .EaseOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) + case .EaseInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) + case .EaseInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) + case .EaseOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) + case .EaseInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) + case .EaseInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) + case .EaseOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) + case .EaseInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) + case .EaseInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) + case .EaseOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) + case .EaseInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) + } + } + return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) + } + + func getAnimationOptions(curve: String) -> UIViewAnimationOptions { + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .EaseIn: return UIViewAnimationOptions.CurveEaseIn + case .EaseOut: return UIViewAnimationOptions.CurveEaseOut + case .EaseInOut: return UIViewAnimationOptions.CurveEaseInOut + default: break + } + } + return UIViewAnimationOptions.CurveLinear + } + + public func animate() { + animateFrom = true + animatePreset() + setView {} + } + + public func animateNext(completion: () -> ()) { + animateFrom = true + animatePreset() + setView { + completion() + } + } + + public func animateTo() { + animateFrom = false + animatePreset() + setView {} + } + + public func animateToNext(completion: () -> ()) { + animateFrom = false + animatePreset() + setView { + completion() + } + } + + public func customAwakeFromNib() { + if autohide { + alpha = 0 + } + } + + public func customLayoutSubviews() { + if shouldAnimateInLayoutSubviews { + shouldAnimateInLayoutSubviews = false + if autostart { + if UIApplication.sharedApplication().applicationState != .Active { + shouldAnimateAfterActive = true + return + } + alpha = 0 + animate() + } + } + } + + func setView(completion: () -> ()) { + if animateFrom { + let translate = CGAffineTransformMakeTranslation(self.x, self.y) + let scale = CGAffineTransformMakeScale(self.scaleX, self.scaleY) + let rotate = CGAffineTransformMakeRotation(self.rotate) + let translateAndScale = CGAffineTransformConcat(translate, scale) + self.transform = CGAffineTransformConcat(rotate, translateAndScale) + + self.alpha = self.opacity + } + + UIView.animateWithDuration( NSTimeInterval(duration), + delay: NSTimeInterval(delay), + usingSpringWithDamping: damping, + initialSpringVelocity: velocity, + options: [getAnimationOptions(curve), UIViewAnimationOptions.AllowUserInteraction], + animations: { [weak self] in + if let _self = self + { + if _self.animateFrom { + _self.transform = CGAffineTransformIdentity + _self.alpha = 1 + } + else { + let translate = CGAffineTransformMakeTranslation(_self.x, _self.y) + let scale = CGAffineTransformMakeScale(_self.scaleX, _self.scaleY) + let rotate = CGAffineTransformMakeRotation(_self.rotate) + let translateAndScale = CGAffineTransformConcat(translate, scale) + _self.transform = CGAffineTransformConcat(rotate, translateAndScale) + + _self.alpha = _self.opacity + } + + } + + }, completion: { [weak self] finished in + + completion() + self?.resetAll() + + }) + + } + + func reset() { + x = 0 + y = 0 + opacity = 1 + } + + func resetAll() { + x = 0 + y = 0 + animation = "" + opacity = 1 + scaleX = 1 + scaleY = 1 + rotate = 0 + damping = 0.7 + velocity = 0.7 + repeatCount = 1 + delay = 0 + duration = 0.7 + } + +} \ No newline at end of file diff --git a/Pods/Spring/Spring/SpringAnimation.swift b/Pods/Spring/Spring/SpringAnimation.swift new file mode 100644 index 0000000..51038c3 --- /dev/null +++ b/Pods/Spring/Spring/SpringAnimation.swift @@ -0,0 +1,112 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@objc public class SpringAnimation: NSObject { + public class func spring(duration: NSTimeInterval, animations: () -> Void) { + UIView.animateWithDuration( + duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, + completion: nil + ) + } + + public class func springEaseIn(duration: NSTimeInterval, animations: (() -> Void)!) { + UIView.animateWithDuration( + duration, + delay: 0, + options: .CurveEaseIn, + animations: { + animations() + }, + completion: nil + ) + } + + public class func springEaseOut(duration: NSTimeInterval, animations: (() -> Void)!) { + UIView.animateWithDuration( + duration, + delay: 0, + options: .CurveEaseOut, + animations: { + animations() + }, completion: nil + ) + } + + public class func springEaseInOut(duration: NSTimeInterval, animations: (() -> Void)!) { + UIView.animateWithDuration( + duration, + delay: 0, + options: .CurveEaseInOut, + animations: { + animations() + }, completion: nil + ) + } + + public class func springLinear(duration: NSTimeInterval, animations: (() -> Void)!) { + UIView.animateWithDuration( + duration, + delay: 0, + options: .CurveLinear, + animations: { + animations() + }, completion: nil + ) + } + + public class func springWithDelay(duration: NSTimeInterval, delay: NSTimeInterval, animations: (() -> Void)!) { + UIView.animateWithDuration( + duration, + delay: delay, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: nil + ) + } + + public class func springWithCompletion(duration: NSTimeInterval, animations: (() -> Void)!, completion: (Bool -> Void)!) { + UIView.animateWithDuration( + duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: { finished in + completion(finished) + } + ) + } +} diff --git a/Spring/SpringButton.swift b/Pods/Spring/Spring/SpringButton.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringButton.swift rename to Pods/Spring/Spring/SpringButton.swift index 040f0f8..7851c14 --- a/Spring/SpringButton.swift +++ b/Pods/Spring/Spring/SpringButton.swift @@ -48,9 +48,9 @@ public class SpringButton: UIButton, Springable { self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/SpringImageView.swift b/Pods/Spring/Spring/SpringImageView.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringImageView.swift rename to Pods/Spring/Spring/SpringImageView.swift index 6b6481d..1ba3904 --- a/Spring/SpringImageView.swift +++ b/Pods/Spring/Spring/SpringImageView.swift @@ -48,9 +48,9 @@ public class SpringImageView: UIImageView, Springable { self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/SpringLabel.swift b/Pods/Spring/Spring/SpringLabel.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringLabel.swift rename to Pods/Spring/Spring/SpringLabel.swift index 4ce4934..6a70b6c --- a/Spring/SpringLabel.swift +++ b/Pods/Spring/Spring/SpringLabel.swift @@ -48,9 +48,9 @@ public class SpringLabel: UILabel, Springable { self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/SpringTextField.swift b/Pods/Spring/Spring/SpringTextField.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringTextField.swift rename to Pods/Spring/Spring/SpringTextField.swift index b943688..ea30597 --- a/Spring/SpringTextField.swift +++ b/Pods/Spring/Spring/SpringTextField.swift @@ -48,9 +48,9 @@ public class SpringTextField: UITextField, Springable { self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/SpringTextView.swift b/Pods/Spring/Spring/SpringTextView.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringTextView.swift rename to Pods/Spring/Spring/SpringTextView.swift index ab7ba15..5b8f5f7 --- a/Spring/SpringTextView.swift +++ b/Pods/Spring/Spring/SpringTextView.swift @@ -48,9 +48,9 @@ public class SpringTextView: UITextView, Springable { self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/SpringView.swift b/Pods/Spring/Spring/SpringView.swift old mode 100755 new mode 100644 similarity index 95% rename from Spring/SpringView.swift rename to Pods/Spring/Spring/SpringView.swift index 1917924..405e2af --- a/Spring/SpringView.swift +++ b/Pods/Spring/Spring/SpringView.swift @@ -47,10 +47,10 @@ public class SpringView: UIView, Springable { super.awakeFromNib() self.spring.customAwakeFromNib() } - - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + + public override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { diff --git a/Spring/TransitionManager.swift b/Pods/Spring/Spring/TransitionManager.swift old mode 100755 new mode 100644 similarity index 93% rename from Spring/TransitionManager.swift rename to Pods/Spring/Spring/TransitionManager.swift index 401e1c3..1aee7c5 --- a/Spring/TransitionManager.swift +++ b/Pods/Spring/Spring/TransitionManager.swift @@ -28,7 +28,7 @@ public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, var duration = 0.3 public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView() + let container = transitionContext.containerView()! let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! @@ -37,7 +37,7 @@ public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, toView.transform = CGAffineTransformMakeTranslation(0, container.frame.size.height) container.addSubview(fromView) container.addSubview(toView) - springEaseInOut(duration) { + SpringAnimation.springEaseInOut(duration) { fromView.transform = CGAffineTransformMakeScale(0.8, 0.8) fromView.alpha = 0.5 toView.transform = CGAffineTransformIdentity @@ -58,19 +58,19 @@ public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, container.addSubview(toView) container.addSubview(fromView) - springEaseInOut(duration) { + SpringAnimation.springEaseInOut(duration) { fromView.transform = CGAffineTransformMakeTranslation(0, fromView.frame.size.height) toView.transform = CGAffineTransformIdentity toView.alpha = 1 } } - delay(duration, { + delay(duration, closure: { transitionContext.completeTransition(true) }) } - public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { + public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return duration } diff --git a/Spring/TransitionZoom.swift b/Pods/Spring/Spring/TransitionZoom.swift old mode 100755 new mode 100644 similarity index 92% rename from Spring/TransitionZoom.swift rename to Pods/Spring/Spring/TransitionZoom.swift index da1f4bc..92c43de --- a/Spring/TransitionZoom.swift +++ b/Pods/Spring/Spring/TransitionZoom.swift @@ -28,7 +28,7 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI var duration = 0.4 public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView() + let container = transitionContext.containerView()! let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! @@ -38,7 +38,8 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI toView.alpha = 0 toView.transform = CGAffineTransformMakeScale(2, 2) - springEaseInOut(duration) { + + SpringAnimation.springEaseInOut(duration) { fromView.transform = CGAffineTransformMakeScale(0.5, 0.5) fromView.alpha = 0 toView.transform = CGAffineTransformIdentity @@ -49,7 +50,7 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI container.addSubview(toView) container.addSubview(fromView) - springEaseInOut(duration) { + SpringAnimation.springEaseInOut(duration) { fromView.transform = CGAffineTransformMakeScale(2, 2) fromView.alpha = 0 toView.transform = CGAffineTransformMakeScale(1, 1) @@ -57,12 +58,12 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI } } - delay(duration, { + delay(duration, closure: { transitionContext.completeTransition(true) }) } - public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { + public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { return duration } diff --git a/Spring/UnwindSegue.swift b/Pods/Spring/Spring/UnwindSegue.swift old mode 100755 new mode 100644 similarity index 100% rename from Spring/UnwindSegue.swift rename to Pods/Spring/Spring/UnwindSegue.swift diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..17d5afa --- /dev/null +++ b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,80 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "appicon@58.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "appicon@87.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "appicon@80.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "appicon@120.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "appicon@120-1.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "appicon@180.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "appicon@29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "appicon@58-1.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "appicon@40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "appicon@80-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "appicon@76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "appicon@152.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120-1.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120-1.png new file mode 100644 index 0000000..38af767 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120-1.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120.png new file mode 100644 index 0000000..38af767 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@120.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@152.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@152.png new file mode 100644 index 0000000..1a0d757 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@152.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@180.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@180.png new file mode 100644 index 0000000..6bfe77f Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@180.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@29.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@29.png new file mode 100644 index 0000000..6b2bd68 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@29.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@40.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@40.png new file mode 100644 index 0000000..633ec7d Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@40.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58-1.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58-1.png new file mode 100644 index 0000000..dac27f8 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58-1.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58.png new file mode 100644 index 0000000..dac27f8 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@58.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@76.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@76.png new file mode 100644 index 0000000..2a61084 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@76.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80-1.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80-1.png new file mode 100644 index 0000000..8741b04 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80-1.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80.png new file mode 100644 index 0000000..8741b04 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@80.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@87.png b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@87.png new file mode 100644 index 0000000..629e004 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@87.png differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/Contents.json b/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/Contents.json new file mode 100644 index 0000000..6c93b66 --- /dev/null +++ b/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon-shape.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/icon-shape.pdf b/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/icon-shape.pdf new file mode 100644 index 0000000..0831cb2 Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/icon-shape.imageset/icon-shape.pdf differ diff --git a/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/Contents.json b/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/Contents.json new file mode 100644 index 0000000..07f4d24 --- /dev/null +++ b/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "loading.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/loading.pdf b/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/loading.pdf new file mode 100644 index 0000000..42c33ee Binary files /dev/null and b/Pods/Spring/SpringApp/Images.xcassets/loading.imageset/loading.pdf differ diff --git a/Pods/Target Support Files/Bolts/Bolts-dummy.m b/Pods/Target Support Files/Bolts/Bolts-dummy.m new file mode 100644 index 0000000..aeabf61 --- /dev/null +++ b/Pods/Target Support Files/Bolts/Bolts-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Bolts : NSObject +@end +@implementation PodsDummy_Bolts +@end diff --git a/Pods/Target Support Files/Bolts/Bolts-prefix.pch b/Pods/Target Support Files/Bolts/Bolts-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/Bolts/Bolts-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/Pods/Target Support Files/Bolts/Bolts-umbrella.h b/Pods/Target Support Files/Bolts/Bolts-umbrella.h new file mode 100644 index 0000000..af0b269 --- /dev/null +++ b/Pods/Target Support Files/Bolts/Bolts-umbrella.h @@ -0,0 +1,14 @@ +#import + +#import "BFCancellationToken.h" +#import "BFCancellationTokenRegistration.h" +#import "BFCancellationTokenSource.h" +#import "BFExecutor.h" +#import "BFTask.h" +#import "BFTaskCompletionSource.h" +#import "Bolts.h" +#import "BoltsVersion.h" + +FOUNDATION_EXPORT double BoltsVersionNumber; +FOUNDATION_EXPORT const unsigned char BoltsVersionString[]; + diff --git a/Pods/Target Support Files/Bolts/Bolts.modulemap b/Pods/Target Support Files/Bolts/Bolts.modulemap new file mode 100644 index 0000000..712e2c8 --- /dev/null +++ b/Pods/Target Support Files/Bolts/Bolts.modulemap @@ -0,0 +1,6 @@ +framework module Bolts { + umbrella header "Bolts-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Bolts/Bolts.xcconfig b/Pods/Target Support Files/Bolts/Bolts.xcconfig new file mode 100644 index 0000000..87d62af --- /dev/null +++ b/Pods/Target Support Files/Bolts/Bolts.xcconfig @@ -0,0 +1,4 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Bolts" "${PODS_ROOT}/Headers/Public" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/Bolts/Info.plist b/Pods/Target Support Files/Bolts/Info.plist new file mode 100644 index 0000000..ed58c09 --- /dev/null +++ b/Pods/Target Support Files/Bolts/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.2.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Parse/Info.plist b/Pods/Target Support Files/Parse/Info.plist new file mode 100644 index 0000000..ceba9b6 --- /dev/null +++ b/Pods/Target Support Files/Parse/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.7.5.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Parse/Parse-dummy.m b/Pods/Target Support Files/Parse/Parse-dummy.m new file mode 100644 index 0000000..3f17a64 --- /dev/null +++ b/Pods/Target Support Files/Parse/Parse-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Parse : NSObject +@end +@implementation PodsDummy_Parse +@end diff --git a/Pods/Target Support Files/Parse/Parse-prefix.pch b/Pods/Target Support Files/Parse/Parse-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/Parse/Parse-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/Pods/Target Support Files/Parse/Parse-umbrella.h b/Pods/Target Support Files/Parse/Parse-umbrella.h new file mode 100644 index 0000000..9303fe6 --- /dev/null +++ b/Pods/Target Support Files/Parse/Parse-umbrella.h @@ -0,0 +1,31 @@ +#import + +#import "Parse.h" +#import "PF_Twitter.h" +#import "PFACL.h" +#import "PFAnalytics.h" +#import "PFAnonymousUtils.h" +#import "PFCloud.h" +#import "PFConfig.h" +#import "PFConstants.h" +#import "PFFile.h" +#import "PFGeoPoint.h" +#import "PFInstallation.h" +#import "PFNetworkActivityIndicatorManager.h" +#import "PFNullability.h" +#import "PFObject+Subclass.h" +#import "PFObject.h" +#import "PFProduct.h" +#import "PFPurchase.h" +#import "PFPush.h" +#import "PFQuery.h" +#import "PFRelation.h" +#import "PFRole.h" +#import "PFSession.h" +#import "PFSubclassing.h" +#import "PFTwitterUtils.h" +#import "PFUser.h" + +FOUNDATION_EXPORT double ParseVersionNumber; +FOUNDATION_EXPORT const unsigned char ParseVersionString[]; + diff --git a/Pods/Target Support Files/Parse/Parse.modulemap b/Pods/Target Support Files/Parse/Parse.modulemap new file mode 100644 index 0000000..2499731 --- /dev/null +++ b/Pods/Target Support Files/Parse/Parse.modulemap @@ -0,0 +1,6 @@ +framework module Parse { + umbrella header "Parse-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Parse/Parse.xcconfig b/Pods/Target Support Files/Parse/Parse.xcconfig new file mode 100644 index 0000000..5bf86fe --- /dev/null +++ b/Pods/Target Support Files/Parse/Parse.xcconfig @@ -0,0 +1,6 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Parse" "${PODS_ROOT}/Headers/Public" +LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Parse" +OTHER_LDFLAGS = -ObjC -l"ParseLib" -l"sqlite3" -l"z" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreGraphics" -framework "CoreLocation" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -weak_framework "Accounts" -weak_framework "Social" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/Pods/Info.plist b/Pods/Target Support Files/Pods/Info.plist new file mode 100644 index 0000000..6974542 --- /dev/null +++ b/Pods/Target Support Files/Pods/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown new file mode 100644 index 0000000..a9f7272 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown @@ -0,0 +1,63 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Bolts + +BSD License + +For Bolts software + +Copyright (c) 2013-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## Parse + +See https://www.parse.com/about/terms + +## Spring + +Copyright (c) 2014-2015 Meng To (meng@designcode.io) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Generated by CocoaPods - http://cocoapods.org diff --git a/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/Pods/Target Support Files/Pods/Pods-acknowledgements.plist new file mode 100644 index 0000000..c9f2d62 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-acknowledgements.plist @@ -0,0 +1,101 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + BSD License + +For Bolts software + +Copyright (c) 2013-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Title + Bolts + Type + PSGroupSpecifier + + + FooterText + See https://www.parse.com/about/terms + Title + Parse + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2014-2015 Meng To (meng@designcode.io) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Title + Spring + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - http://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods/Pods-dummy.m b/Pods/Target Support Files/Pods/Pods-dummy.m new file mode 100644 index 0000000..ade64bd --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods : NSObject +@end +@implementation PodsDummy_Pods +@end diff --git a/Pods/Target Support Files/Pods/Pods-frameworks.sh b/Pods/Target Support Files/Pods/Pods-frameworks.sh new file mode 100755 index 0000000..deeada1 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-frameworks.sh @@ -0,0 +1,95 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # use filter instead of exclude so missing patterns dont' throw errors + echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" + /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "Pods/Bolts.framework" + install_framework "Pods/Parse.framework" + install_framework "Pods/Spring.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "Pods/Bolts.framework" + install_framework "Pods/Parse.framework" + install_framework "Pods/Spring.framework" +fi diff --git a/Pods/Target Support Files/Pods/Pods-resources.sh b/Pods/Target Support Files/Pods/Pods-resources.sh new file mode 100755 index 0000000..16774fb --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-resources.sh @@ -0,0 +1,95 @@ +#!/bin/sh +set -e + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +realpath() { + DIRECTORY="$(cd "${1%/*}" && pwd)" + FILENAME="${1##*/}" + echo "$DIRECTORY/$FILENAME" +} + +install_resource() +{ + case $1 in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.framework) + echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" + xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + /*) + echo "$1" + echo "$1" >> "$RESOURCES_TO_COPY" + ;; + *) + echo "${PODS_ROOT}/$1" + echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; + esac + + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "`realpath $PODS_ROOT`*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Pods/Target Support Files/Pods/Pods-umbrella.h b/Pods/Target Support Files/Pods/Pods-umbrella.h new file mode 100644 index 0000000..21dcfd2 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-umbrella.h @@ -0,0 +1,6 @@ +#import + + +FOUNDATION_EXPORT double PodsVersionNumber; +FOUNDATION_EXPORT const unsigned char PodsVersionString[]; + diff --git a/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/Pods/Target Support Files/Pods/Pods.debug.xcconfig new file mode 100644 index 0000000..a113ad3 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods.debug.xcconfig @@ -0,0 +1,8 @@ +EMBEDDED_CONTENT_CONTAINS_SWIFT = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Bolts.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Parse.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Spring.framework/Headers" +OTHER_LDFLAGS = $(inherited) -ObjC -framework "Bolts" -framework "Parse" -framework "Spring" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Pods/Target Support Files/Pods/Pods.modulemap b/Pods/Target Support Files/Pods/Pods.modulemap new file mode 100644 index 0000000..8413413 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods.modulemap @@ -0,0 +1,6 @@ +framework module Pods { + umbrella header "Pods-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Pods/Pods.release.xcconfig b/Pods/Target Support Files/Pods/Pods.release.xcconfig new file mode 100644 index 0000000..a113ad3 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods.release.xcconfig @@ -0,0 +1,8 @@ +EMBEDDED_CONTENT_CONTAINS_SWIFT = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Bolts.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Parse.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Spring.framework/Headers" +OTHER_LDFLAGS = $(inherited) -ObjC -framework "Bolts" -framework "Parse" -framework "Spring" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Pods/Target Support Files/Spring/Info.plist b/Pods/Target Support Files/Spring/Info.plist new file mode 100644 index 0000000..6e49a7d --- /dev/null +++ b/Pods/Target Support Files/Spring/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.cocoapods.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Spring/Spring-dummy.m b/Pods/Target Support Files/Spring/Spring-dummy.m new file mode 100644 index 0000000..c9de78b --- /dev/null +++ b/Pods/Target Support Files/Spring/Spring-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Spring : NSObject +@end +@implementation PodsDummy_Spring +@end diff --git a/Pods/Target Support Files/Spring/Spring-prefix.pch b/Pods/Target Support Files/Spring/Spring-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/Spring/Spring-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import +#endif + diff --git a/Pods/Target Support Files/Spring/Spring-umbrella.h b/Pods/Target Support Files/Spring/Spring-umbrella.h new file mode 100644 index 0000000..2c573fb --- /dev/null +++ b/Pods/Target Support Files/Spring/Spring-umbrella.h @@ -0,0 +1,6 @@ +#import + + +FOUNDATION_EXPORT double SpringVersionNumber; +FOUNDATION_EXPORT const unsigned char SpringVersionString[]; + diff --git a/Pods/Target Support Files/Spring/Spring.modulemap b/Pods/Target Support Files/Spring/Spring.modulemap new file mode 100644 index 0000000..24686cd --- /dev/null +++ b/Pods/Target Support Files/Spring/Spring.modulemap @@ -0,0 +1,6 @@ +framework module Spring { + umbrella header "Spring-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Spring/Spring.xcconfig b/Pods/Target Support Files/Spring/Spring.xcconfig new file mode 100644 index 0000000..d895cf7 --- /dev/null +++ b/Pods/Target Support Files/Spring/Spring.xcconfig @@ -0,0 +1,5 @@ +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Spring" "${PODS_ROOT}/Headers/Public" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/PreviewImageViewController.swift b/PreviewImageViewController.swift deleted file mode 100644 index d865520..0000000 --- a/PreviewImageViewController.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// PreviewImageViewController.swift -// Dindr -// -// Created by lsecrease on 10/20/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class PreviewImageViewController: UIViewController { - - - - @IBOutlet weak var imageView: UIImageView! - - var image: UIImage! - - init(image: UIImage) - { - self.image = image - super.init(nibName: nil, bundle: nil) - } - - required init(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - override func viewDidLoad() { - super.viewDidLoad() - - imageView.image = image - - - -} -} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..851a7b0 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# RestaurantDindr diff --git a/RestCollectionViewCell.swift b/RestCollectionViewCell.swift deleted file mode 100644 index a1de592..0000000 --- a/RestCollectionViewCell.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// RestCollectionViewCell.swift -// Dindr -// -// Created by lsecrease on 9/15/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class RestCollectionViewCell: UICollectionViewCell { - - @IBOutlet weak var dishImage: UIImage! - - -} diff --git a/RestaurantDataViewController.swift b/RestaurantDataViewController.swift deleted file mode 100644 index f522b18..0000000 --- a/RestaurantDataViewController.swift +++ /dev/null @@ -1,316 +0,0 @@ -// -// RestaurantDataViewController.swift -// Dindr -// -// Created by lsecrease on 8/15/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import Foundation -import UIKit -import Photos - -class RestaurantDataViewController: UIViewController, UIAlertViewDelegate, - UINavigationControllerDelegate, - UIImagePickerControllerDelegate { - - - - @IBOutlet weak var collectionView: UICollectionView! - - @IBOutlet weak var restImage1: UIImageView! - @IBOutlet weak var restImage2: UIImageView! - @IBOutlet weak var restImage3: UIImageView! - @IBOutlet weak var restImage4: UIImageView! - - private var postImage: UIImage! //Used to Store restImage image - - @IBOutlet weak var numberOfDishesSwiped: UILabel! - @IBOutlet weak var checkInTotal: UILabel! - @IBOutlet weak var usersInRadius: UILabel! - - - var swipeObj = PFObject(className: "") - - var baseArray:[DishModel] = [] - - - override func viewDidLoad() { - super.viewDidLoad() - println("\(PFUser.currentUser())") - // Do any additional setup after loading the view. - - //numberOfDishesSwiped.text = "\(swipeObj[])" - - let dish1 = DishModel(image: UIImage(named: "f1.jpg")) - let dish2 = DishModel(image: UIImage(named: "f2.jpg")) - let dish3 = DishModel(image: UIImage(named: "f4.jpg")) - - baseArray = [dish1, dish2, dish3, DishModel(image: UIImage(named: "f1")), DishModel(image: UIImage(named: "f1")), DishModel(image: UIImage(named: "f1"))] - println("\(baseArray)") - - - } - - //Check to see if User is logged in; If not, head over to login - override func viewDidAppear(animated: Bool) { - super.viewDidAppear(animated) - if (PFUser.currentUser() == nil) { - self.performSegueWithIdentifier("login", sender: self) - } else if (PFUser.currentUser() != nil) { - self.storyboard?.instantiateViewControllerWithIdentifier("RestaurantData") - } - } - - //Using ImagePickerSheet Controller - @IBAction func pickFeaturedImageClicked(sender: UITapGestureRecognizer) { - - let authorization = PHPhotoLibrary.authorizationStatus() - - if authorization == .NotDetermined { - PHPhotoLibrary.requestAuthorization({ (status) -> Void in - //self.pickFeaturedImageClicked(sender) - dispatch_async(dispatch_get_main_queue(), { () -> Void in - self.pickFeaturedImageClicked(sender) - }) - }) - return - } - //Do you want to Take a Photo or Video with the Camera - if authorization == .Authorized { - let controller = ImagePickerSheetController() - controller.addAction(ImageAction(title: NSLocalizedString("Take Photo or Video", comment: "ActionTitle"), secondaryTitle: NSLocalizedString("Use This One", comment: "ActionTitle"), handler: { (_) -> () in - - self.presentCamera() - - }, secondaryHandler: { (action, numberOfPhotos) -> () in - controller.getSelectedImagesWithCompletion({ (images) -> Void in - self.postImage = images[0] - self.restImage1.image = self.postImage - }) - })) - - controller.addAction(ImageAction(title: NSLocalizedString("Cancel", comment: "Action Title"), style: .Cancel)) - - presentViewController(controller, animated: true, completion: nil) - - } - - } - - func presentCamera() { - - } - - - //Using ImagePickerSheet Controller for 2nd Image - @IBAction func pick2ndFeaturedImageClicked(sender: UITapGestureRecognizer) { - - let authorization = PHPhotoLibrary.authorizationStatus() - - if authorization == .NotDetermined { - PHPhotoLibrary.requestAuthorization({ (status) -> Void in - //self.pickFeaturedImageClicked(sender) - dispatch_async(dispatch_get_main_queue(), { () -> Void in - self.pickFeaturedImageClicked(sender) - }) - }) - return - } - //Do you want to Take a Photo or Video with the Camera - if authorization == .Authorized { - let controller = ImagePickerSheetController() - controller.addAction(ImageAction(title: NSLocalizedString("Take Photo or Video", comment: "ActionTitle"), secondaryTitle: NSLocalizedString("Use This One", comment: "ActionTitle"), handler: { (_) -> () in - - self.presentCamera() - - }, secondaryHandler: { (action, numberOfPhotos) -> () in - controller.getSelectedImagesWithCompletion({ (images) -> Void in - self.postImage = images[0] - self.restImage2.image = self.postImage - }) - })) - - controller.addAction(ImageAction(title: NSLocalizedString("Cancel", comment: "Action Title"), style: .Cancel)) - - presentViewController(controller, animated: true, completion: nil) - - } - - } - - //Using ImagePickerSheet Controller - @IBAction func pick3rdFeaturedImageClicked(sender: UITapGestureRecognizer) { - - let authorization = PHPhotoLibrary.authorizationStatus() - - if authorization == .NotDetermined { - PHPhotoLibrary.requestAuthorization({ (status) -> Void in - //self.pickFeaturedImageClicked(sender) - dispatch_async(dispatch_get_main_queue(), { () -> Void in - self.pickFeaturedImageClicked(sender) - }) - }) - return - } - //Do you want to Take a Photo or Video with the Camera - if authorization == .Authorized { - let controller = ImagePickerSheetController() - controller.addAction(ImageAction(title: NSLocalizedString("Take Photo or Video", comment: "ActionTitle"), secondaryTitle: NSLocalizedString("Use This One", comment: "ActionTitle"), handler: { (_) -> () in - - self.presentCamera() - - }, secondaryHandler: { (action, numberOfPhotos) -> () in - controller.getSelectedImagesWithCompletion({ (images) -> Void in - self.postImage = images[0] - self.restImage3.image = self.postImage - }) - })) - - controller.addAction(ImageAction(title: NSLocalizedString("Cancel", comment: "Action Title"), style: .Cancel)) - - presentViewController(controller, animated: true, completion: nil) - - } - - } - - - //Using ImagePickerSheet Controller - @IBAction func pick4thFeaturedImageClicked(sender: UITapGestureRecognizer) { - - let authorization = PHPhotoLibrary.authorizationStatus() - - if authorization == .NotDetermined { - PHPhotoLibrary.requestAuthorization({ (status) -> Void in - //self.pickFeaturedImageClicked(sender) - dispatch_async(dispatch_get_main_queue(), { () -> Void in - self.pickFeaturedImageClicked(sender) - }) - }) - return - } - //Do you want to Take a Photo or Video with the Camera - if authorization == .Authorized { - let controller = ImagePickerSheetController() - controller.addAction(ImageAction(title: NSLocalizedString("Take Photo or Video", comment: "ActionTitle"), secondaryTitle: NSLocalizedString("Use This One", comment: "ActionTitle"), handler: { (_) -> () in - - self.presentCamera() - - }, secondaryHandler: { (action, numberOfPhotos) -> () in - controller.getSelectedImagesWithCompletion({ (images) -> Void in - self.postImage = images[0] - self.restImage4.image = self.postImage - }) - })) - - controller.addAction(ImageAction(title: NSLocalizedString("Cancel", comment: "Action Title"), style: .Cancel)) - - presentViewController(controller, animated: true, completion: nil) - - } - - } - - - - - - - -// // BUTTON FOR IMAGES -// func buttImageTapped(sender: UIButton) { -// var button = sender as UIButton -// buttTAG = button.tag -// println("\(buttTAG)") -// println("\(button.tag)") -// -// var alert = UIAlertView(title: "Dindr", -// message: "Add a Photo", -// delegate: self, -// cancelButtonTitle: "Cancel", -// otherButtonTitles: -// "Take a picture", -// "Choose from Library" -// ) -// alert.show() -// -// } - -// // AlertView delegate -// func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) { -// -// // OPEN DEVICE'S CAMERA -// if alertView.buttonTitleAtIndex(buttonIndex) == "Take a picture" { -// if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) { -// var imagePicker = UIImagePickerController() -// imagePicker.delegate = self -// imagePicker.sourceType = UIImagePickerControllerSourceType.Camera; -// imagePicker.allowsEditing = false -// self.presentViewController(imagePicker, animated: true, completion: nil) -// } -// -// -// // PICK A PHOTO FROM LIBRARY -// } else if alertView.buttonTitleAtIndex(buttonIndex) == "Choose from Library" { -// if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) { -// var imagePicker = UIImagePickerController() -// imagePicker.delegate = self -// imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary; -// imagePicker.allowsEditing = false -// self.presentViewController(imagePicker, animated: true, completion: nil) -// } -// } -// } - - - -// // ImagePicker Delegate -// func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) { -// -// // Assign Images -// switch buttTAG { -// case 0: restImage1.image = image; break -// case 1: restImage2.image = image; break -// case 2: restImage3.image = image; break -// case 3: restImage4.image = image; break -// default: break -// } -// dismissViewControllerAnimated(true, completion: nil) -// } - - - @IBAction func editSpecialButtonTapped(sender: AnyObject) { - - println("Edit Specials Button Tapped!") - self.performSegueWithIdentifier("showPerks", sender: self) - } - - - - -} - -extension RestaurantDataViewController : UICollectionViewDataSource -{ - func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { - return 1 - } - - func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return baseArray.count - } - - func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - - let thisDish = baseArray[indexPath.item] - - let cellIdentifier = "Dish" - let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as! RestCollectionViewCell - - cell.dishImage = thisDish.image - - return cell - } -} - diff --git a/SpecialsTableViewCell.swift b/SpecialsTableViewCell.swift deleted file mode 100644 index 692a959..0000000 --- a/SpecialsTableViewCell.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// SpecialsTableViewCell.swift -// Dindr -// -// Created by lsecrease on 10/27/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class SpecialsTableViewCell: UITableViewCell { - - @IBOutlet weak var perkImage: UIImageView! - @IBOutlet weak var perkDescription: UILabel! - - - - - - -} diff --git a/SpecialsTableViewController.swift b/SpecialsTableViewController.swift deleted file mode 100644 index 7ca5f93..0000000 --- a/SpecialsTableViewController.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// SpecialsTableViewController.swift -// Dindr -// -// Created by lsecrease on 9/15/15. -// Copyright (c) 2015 ImagineME. All rights reserved. -// - -import UIKit - -class SpecialsTableViewController: UITableViewController { - - - var paidMember: Bool = false - var perksArray = NSMutableArray() - - override func viewDidLoad() { - super.viewDidLoad() - - - } - - - // MARK: - Table view data source - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - // #warning Potentially incomplete method implementation. - // Return the number of sections. - return 1 - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - // #warning Incomplete method implementation. - // Return the number of rows in the section. - if paidMember == false { - return 3 - } else { - return perksArray.count - } - } - -// override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { -// <#code#> -// } - - } diff --git a/Spring/Spring.h b/Spring/Spring.h deleted file mode 100755 index 1a11dfe..0000000 --- a/Spring/Spring.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Spring.h -// Spring -// -// Created by James Tang on 20/1/15. -// Copyright (c) 2015 Meng To. All rights reserved. -// - -#import - -//! Project version number for Spring. -FOUNDATION_EXPORT double SpringVersionNumber; - -//! Project version string for Spring. -FOUNDATION_EXPORT const unsigned char SpringVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Spring/Spring.swift b/Spring/Spring.swift deleted file mode 100755 index 7e8c2a5..0000000 --- a/Spring/Spring.swift +++ /dev/null @@ -1,454 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@objc public protocol Springable { - var autostart: Bool { get set } - var autohide: Bool { get set } - var animation: String { get set } - var force: CGFloat { get set } - var delay: CGFloat { get set } - var duration: CGFloat { get set } - var damping: CGFloat { get set } - var velocity: CGFloat { get set } - var repeatCount: Float { get set } - var x: CGFloat { get set } - var y: CGFloat { get set } - var scaleX: CGFloat { get set } - var scaleY: CGFloat { get set } - var rotate: CGFloat { get set } - var opacity: CGFloat { get set } - var animateFrom: Bool { get set } - var curve: String { get set } - - // UIView - var layer : CALayer { get } - var transform : CGAffineTransform { get set } - var alpha : CGFloat { get set } - - func animate() - func animateNext(completion: () -> ()) - func animateTo() - func animateToNext(completion: () -> ()) -} - -public class Spring : NSObject { - - private unowned var view : Springable - private var shouldAnimateAfterActive = false - - init(_ view: Springable) { - self.view = view - super.init() - commonInit() - } - - func commonInit() { - NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBecomeActiveNotification:", name: UIApplicationDidBecomeActiveNotification, object: nil) - } - - func didBecomeActiveNotification(notification: NSNotification) { - if shouldAnimateAfterActive { - alpha = 0 - animate() - shouldAnimateAfterActive = false - } - } - - deinit { - NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidBecomeActiveNotification, object: nil) - } - - private var autostart: Bool { set { self.view.autostart = newValue } get { return self.view.autostart }} - private var autohide: Bool { set { self.view.autohide = newValue } get { return self.view.autohide }} - private var animation: String { set { self.view.animation = newValue } get { return self.view.animation }} - private var force: CGFloat { set { self.view.force = newValue } get { return self.view.force }} - private var delay: CGFloat { set { self.view.delay = newValue } get { return self.view.delay }} - private var duration: CGFloat { set { self.view.duration = newValue } get { return self.view.duration }} - private var damping: CGFloat { set { self.view.damping = newValue } get { return self.view.damping }} - private var velocity: CGFloat { set { self.view.velocity = newValue } get { return self.view.velocity }} - private var repeatCount: Float { set { self.view.repeatCount = newValue } get { return self.view.repeatCount }} - private var x: CGFloat { set { self.view.x = newValue } get { return self.view.x }} - private var y: CGFloat { set { self.view.y = newValue } get { return self.view.y }} - private var scaleX: CGFloat { set { self.view.scaleX = newValue } get { return self.view.scaleX }} - private var scaleY: CGFloat { set { self.view.scaleY = newValue } get { return self.view.scaleY }} - private var rotate: CGFloat { set { self.view.rotate = newValue } get { return self.view.rotate }} - private var opacity: CGFloat { set { self.view.opacity = newValue } get { return self.view.opacity }} - private var animateFrom: Bool { set { self.view.animateFrom = newValue } get { return self.view.animateFrom }} - private var curve: String { set { self.view.curve = newValue } get { return self.view.curve }} - - // UIView - private var layer : CALayer { return view.layer } - private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} - private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } - - func animatePreset() { - if animation == "" { - return - } - - switch animation { - case "slideLeft": - x = 300*force - case "slideRight": - x = -300*force - case "slideDown": - y = -300*force - case "slideUp": - y = 300*force - case "squeezeLeft": - x = 300 - scaleX = 3*force - case "squeezeRight": - x = -300 - scaleX = 3*force - case "squeezeDown": - y = -300 - scaleY = 3*force - case "squeezeUp": - y = 300 - scaleY = 3*force - case "fadeIn": - opacity = 0 - case "fadeOut": - animateFrom = false - opacity = 0 - case "fadeOutIn": - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.autoreverses = true - layer.addAnimation(animation, forKey: "fade") - case "fadeInLeft": - opacity = 0 - x = 300*force - case "fadeInRight": - x = -300*force - opacity = 0 - case "fadeInDown": - y = -300*force - opacity = 0 - case "fadeInUp": - y = 300*force - opacity = 0 - case "zoomIn": - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case "zoomOut": - animateFrom = false - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case "fall": - animateFrom = false - rotate = 15 * CGFloat(M_PI/180) - y = 600*force - case "shake": - let animation = CAKeyframeAnimation() - animation.keyPath = "position.x" - animation.values = [0, 30*force, -30*force, 30*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "shake") - case "pop": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.scale" - animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "pop") - case "flipX": - rotate = 0 - scaleX = 1 - scaleY = 1 - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(CATransform3D: - CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(CATransform3D: - CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0))) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve) - layer.addAnimation(animation, forKey: "3d") - case "flipY": - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(CATransform3D: - CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(CATransform3D: - CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0))) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve) - layer.addAnimation(animation, forKey: "3d") - case "morph": - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.7, 1.3*force, 0.7, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphY, forKey: "morphY") - case "squeeze": - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.5, 1, 0.5, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphY, forKey: "morphY") - case "flash": - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.duration = CFTimeInterval(duration) - animation.repeatCount = repeatCount * 2.0 - animation.autoreverses = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "flash") - case "wobble": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "wobble") - - let x = CAKeyframeAnimation() - x.keyPath = "position.x" - x.values = [0, 30*force, -30*force, 30*force, 0] - x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - x.timingFunction = getTimingFunction(curve) - x.duration = CFTimeInterval(duration) - x.additive = true - x.repeatCount = repeatCount - x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(x, forKey: "x") - case "swing": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "swing") - default: - x = 300 - } - } - - - func getTimingFunction(curve: String) -> CAMediaTimingFunction { - switch curve { - case "easeIn": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) - case "easeOut": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) - case "easeInOut": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) - case "linear": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) - case "spring": - return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) - default: - return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) - } - } - func getAnimationOptions(curve: String) -> UIViewAnimationOptions { - switch curve { - case "easeIn": - return UIViewAnimationOptions.CurveEaseIn - case "easeOut": - return UIViewAnimationOptions.CurveEaseOut - case "easeInOut": - return UIViewAnimationOptions.CurveEaseInOut - case "linear": - return UIViewAnimationOptions.CurveLinear - case "spring": - return UIViewAnimationOptions.CurveLinear - default: - return UIViewAnimationOptions.CurveLinear - } - } - - public func animate() { - animateFrom = true - animatePreset() - setView {} - } - - public func animateNext(completion: () -> ()) { - animateFrom = true - animatePreset() - setView { - completion() - } - } - - public func animateTo() { - animateFrom = false - animatePreset() - setView {} - } - - public func animateToNext(completion: () -> ()) { - animateFrom = false - animatePreset() - setView { - completion() - } - } - - public func customAwakeFromNib() { - if autohide { - alpha = 0 - } - } - - public func customDidMoveToWindow() { - - if autostart { - - if UIApplication.sharedApplication().applicationState != .Active { - shouldAnimateAfterActive = true - return - } - - alpha = 0 - animate() - } - } - - func setView(completion: () -> ()) { - if animateFrom { - let translate = CGAffineTransformMakeTranslation(self.x, self.y) - let scale = CGAffineTransformMakeScale(self.scaleX, self.scaleY) - let rotate = CGAffineTransformMakeRotation(self.rotate) - let translateAndScale = CGAffineTransformConcat(translate, scale) - self.transform = CGAffineTransformConcat(rotate, translateAndScale) - - self.alpha = self.opacity - } - - UIView.animateWithDuration( NSTimeInterval(duration), - delay: NSTimeInterval(delay), - usingSpringWithDamping: damping, - initialSpringVelocity: velocity, - options: getAnimationOptions(curve), - animations: { [weak self] in - if let _self = self - { - if _self.animateFrom { - _self.transform = CGAffineTransformIdentity - _self.alpha = 1 - } - else { - let translate = CGAffineTransformMakeTranslation(_self.x, _self.y) - let scale = CGAffineTransformMakeScale(_self.scaleX, _self.scaleY) - let rotate = CGAffineTransformMakeRotation(_self.rotate) - let translateAndScale = CGAffineTransformConcat(translate, scale) - _self.transform = CGAffineTransformConcat(rotate, translateAndScale) - - _self.alpha = _self.opacity - } - - } - - }, completion: { [weak self] finished in - - completion() - self?.resetAll() - - }) - } - - func reset() { - x = 0 - y = 0 - opacity = 1 - } - - func resetAll() { - x = 0 - y = 0 - animation = "" - opacity = 1 - scaleX = 1 - scaleY = 1 - rotate = 0 - damping = 0.7 - velocity = 0.7 - repeatCount = 1 - delay = 0 - duration = 0.7 - } - -} \ No newline at end of file diff --git a/Spring/SpringAnimation.swift b/Spring/SpringAnimation.swift deleted file mode 100755 index ff5d787..0000000 --- a/Spring/SpringAnimation.swift +++ /dev/null @@ -1,127 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public func spring(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springEaseIn(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseIn, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springEaseOut(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseOut, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springEaseInOut(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseInOut, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springLinear(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveLinear, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springWithDelay(duration: NSTimeInterval, delay: NSTimeInterval, animations: (() -> Void)!) { - UIView.animateWithDuration( - duration, - delay: delay, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springWithCompletion(duration: NSTimeInterval, animations: (() -> Void)!, completion: ((Bool) -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - completion(true) - }) -} \ No newline at end of file diff --git a/UIImage+Crop.h b/UIImage+Crop.h deleted file mode 100755 index 803a2af..0000000 --- a/UIImage+Crop.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// UIImage+Crop.h -// LLSimpleCamera -// -// Created by Ömer Faruk Gül on 27/10/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import - -@interface UIImage(CropCategory) -- (UIImage *)crop:(CGRect)rect; -@end diff --git a/UIImage+Crop.m b/UIImage+Crop.m deleted file mode 100755 index aac9484..0000000 --- a/UIImage+Crop.m +++ /dev/null @@ -1,24 +0,0 @@ -// -// UIImage+Crop.m -// LLSimpleCamera -// -// Created by Ömer Faruk Gül on 27/10/14. -// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved. -// - -#import "UIImage+Crop.h" - -@implementation UIImage(CropCategory) -- (UIImage *)crop:(CGRect)rect { - - rect = CGRectMake(rect.origin.x * self.scale, - rect.origin.y * self.scale, - rect.size.width * self.scale, - rect.size.height * self.scale); - - CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect); - UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; - CGImageRelease(imageRef); - return result; -} -@end diff --git a/UIImage+FixOrientation.h b/UIImage+FixOrientation.h deleted file mode 100755 index 618d046..0000000 --- a/UIImage+FixOrientation.h +++ /dev/null @@ -1,9 +0,0 @@ -// http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload - - - -#import - -@interface UIImage(fixOrientation) -- (UIImage *)fixOrientation; -@end diff --git a/UIImage+FixOrientation.m b/UIImage+FixOrientation.m deleted file mode 100755 index d50f3af..0000000 --- a/UIImage+FixOrientation.m +++ /dev/null @@ -1,87 +0,0 @@ -// http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload - -#import "UIImage+FixOrientation.h" - -@implementation UIImage (fixOrientation) - -- (UIImage *)fixOrientation { - - // No-op if the orientation is already correct - if (self.imageOrientation == UIImageOrientationUp) return self; - - // We need to calculate the proper transformation to make the image upright. - // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. - CGAffineTransform transform = CGAffineTransformIdentity; - - switch (self.imageOrientation) { - case UIImageOrientationDown: - case UIImageOrientationDownMirrored: - transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); - transform = CGAffineTransformRotate(transform, M_PI); - break; - - case UIImageOrientationLeft: - case UIImageOrientationLeftMirrored: - transform = CGAffineTransformTranslate(transform, self.size.width, 0); - transform = CGAffineTransformRotate(transform, M_PI_2); - break; - - case UIImageOrientationRight: - case UIImageOrientationRightMirrored: - transform = CGAffineTransformTranslate(transform, 0, self.size.height); - transform = CGAffineTransformRotate(transform, -M_PI_2); - break; - case UIImageOrientationUp: - case UIImageOrientationUpMirrored: - break; - } - - switch (self.imageOrientation) { - case UIImageOrientationUpMirrored: - case UIImageOrientationDownMirrored: - transform = CGAffineTransformTranslate(transform, self.size.width, 0); - transform = CGAffineTransformScale(transform, -1, 1); - break; - - case UIImageOrientationLeftMirrored: - case UIImageOrientationRightMirrored: - transform = CGAffineTransformTranslate(transform, self.size.height, 0); - transform = CGAffineTransformScale(transform, -1, 1); - break; - case UIImageOrientationUp: - case UIImageOrientationDown: - case UIImageOrientationLeft: - case UIImageOrientationRight: - break; - } - - // Now we draw the underlying CGImage into a new context, applying the transform - // calculated above. - CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, - CGImageGetBitsPerComponent(self.CGImage), 0, - CGImageGetColorSpace(self.CGImage), - CGImageGetBitmapInfo(self.CGImage)); - CGContextConcatCTM(ctx, transform); - switch (self.imageOrientation) { - case UIImageOrientationLeft: - case UIImageOrientationLeftMirrored: - case UIImageOrientationRight: - case UIImageOrientationRightMirrored: - // Grr... - CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); - break; - - default: - CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); - break; - } - - // And now we just create a new UIImage from the drawing context - CGImageRef cgimg = CGBitmapContextCreateImage(ctx); - UIImage *img = [UIImage imageWithCGImage:cgimg]; - CGContextRelease(ctx); - CGImageRelease(cgimg); - return img; -} - -@end diff --git a/UIImage+Resize.h b/UIImage+Resize.h deleted file mode 100755 index 0c69c7a..0000000 --- a/UIImage+Resize.h +++ /dev/null @@ -1,36 +0,0 @@ -/*********************************************************************************** - * - * Copyright (c) 2010 Olivier Halligon - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *********************************************************************************** - * - * Any comment or suggestion welcome. Referencing this project in your AboutBox is appreciated. - * Please tell me if you use this class so we can cross-reference our projects. - * - ***********************************************************************************/ - - -#import - -@interface UIImage(ResizeCategory) --(UIImage*)resizedImageToSize:(CGSize)dstSize; --(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale; -@end diff --git a/UIImage+Resize.m b/UIImage+Resize.m deleted file mode 100755 index 60e4ea9..0000000 --- a/UIImage+Resize.m +++ /dev/null @@ -1,153 +0,0 @@ -// -// UIImage+Resize.m -// -// Created by Olivier Halligon on 12/08/09. -// Copyright 2009 AliSoftware. All rights reserved. -// - -#import "UIImage+Resize.h" - -@implementation UIImage (ResizeCategory) - --(UIImage*)resizedImageToSize:(CGSize)dstSize -{ - CGImageRef imgRef = self.CGImage; - // the below values are regardless of orientation : for UIImages from Camera, width>height (landscape) - CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)! - - /* Don't resize if we already meet the required destination size. */ - if (CGSizeEqualToSize(srcSize, dstSize)) { - return self; - } - - CGFloat scaleRatio = dstSize.width / srcSize.width; - UIImageOrientation orient = self.imageOrientation; - CGAffineTransform transform = CGAffineTransformIdentity; - switch(orient) { - - case UIImageOrientationUp: //EXIF = 1 - transform = CGAffineTransformIdentity; - break; - - case UIImageOrientationUpMirrored: //EXIF = 2 - transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0); - transform = CGAffineTransformScale(transform, -1.0, 1.0); - break; - - case UIImageOrientationDown: //EXIF = 3 - transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height); - transform = CGAffineTransformRotate(transform, M_PI); - break; - - case UIImageOrientationDownMirrored: //EXIF = 4 - transform = CGAffineTransformMakeTranslation(0.0, srcSize.height); - transform = CGAffineTransformScale(transform, 1.0, -1.0); - break; - - case UIImageOrientationLeftMirrored: //EXIF = 5 - dstSize = CGSizeMake(dstSize.height, dstSize.width); - transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width); - transform = CGAffineTransformScale(transform, -1.0, 1.0); - transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); - break; - - case UIImageOrientationLeft: //EXIF = 6 - dstSize = CGSizeMake(dstSize.height, dstSize.width); - transform = CGAffineTransformMakeTranslation(0.0, srcSize.width); - transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); - break; - - case UIImageOrientationRightMirrored: //EXIF = 7 - dstSize = CGSizeMake(dstSize.height, dstSize.width); - transform = CGAffineTransformMakeScale(-1.0, 1.0); - transform = CGAffineTransformRotate(transform, M_PI_2); - break; - - case UIImageOrientationRight: //EXIF = 8 - dstSize = CGSizeMake(dstSize.height, dstSize.width); - transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0); - transform = CGAffineTransformRotate(transform, M_PI_2); - break; - - default: - [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; - - } - - ///////////////////////////////////////////////////////////////////////////// - // The actual resize: draw the image on a new context, applying a transform matrix - UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale); - - CGContextRef context = UIGraphicsGetCurrentContext(); - - if (!context) { - return nil; - } - - if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { - CGContextScaleCTM(context, -scaleRatio, scaleRatio); - CGContextTranslateCTM(context, -srcSize.height, 0); - } else { - CGContextScaleCTM(context, scaleRatio, -scaleRatio); - CGContextTranslateCTM(context, 0, -srcSize.height); - } - - CGContextConcatCTM(context, transform); - - // we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio) - CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef); - UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return resizedImage; -} - - - -///////////////////////////////////////////////////////////////////////////// - - - --(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale -{ - // get the image size (independant of imageOrientation) - CGImageRef imgRef = self.CGImage; - CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which depends on the imageOrientation)! - - // adjust boundingSize to make it independant on imageOrientation too for farther computations - UIImageOrientation orient = self.imageOrientation; - switch (orient) { - case UIImageOrientationLeft: - case UIImageOrientationRight: - case UIImageOrientationLeftMirrored: - case UIImageOrientationRightMirrored: - boundingSize = CGSizeMake(boundingSize.height, boundingSize.width); - break; - default: - // NOP - break; - } - - // Compute the target CGRect in order to keep aspect-ratio - CGSize dstSize; - - if ( !scale && (srcSize.width < boundingSize.width) && (srcSize.height < boundingSize.height) ) { - //NSLog(@"Image is smaller, and we asked not to scale it in this case (scaleIfSmaller:NO)"); - dstSize = srcSize; // no resize (we could directly return 'self' here, but we draw the image anyway to take image orientation into account) - } else { - CGFloat wRatio = boundingSize.width / srcSize.width; - CGFloat hRatio = boundingSize.height / srcSize.height; - - if (wRatio < hRatio) { - //NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio); - dstSize = CGSizeMake(boundingSize.width, floorf(srcSize.height * wRatio)); - } else { - //NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio); - dstSize = CGSizeMake(floorf(srcSize.width * hRatio), boundingSize.height); - } - } - - return [self resizedImageToSize:dstSize]; -} - -@end diff --git a/VideoViewController.h b/VideoViewController.h deleted file mode 100755 index 488ca81..0000000 --- a/VideoViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// TestVideoViewController.h -// Memento -// -// Created by Ömer Faruk Gül on 22/05/15. -// Copyright (c) 2015 Ömer Faruk Gül. All rights reserved. -// - -#import - -@interface VideoViewController : UIViewController -- (instancetype)initWithVideoUrl:(NSURL *)url; -@end diff --git a/VideoViewController.m b/VideoViewController.m deleted file mode 100755 index 87de52d..0000000 --- a/VideoViewController.m +++ /dev/null @@ -1,103 +0,0 @@ -// -// TestVideoViewController.m -// Memento -// -// Created by Ömer Faruk Gül on 22/05/15. -// Copyright (c) 2015 Ömer Faruk Gül. All rights reserved. -// - -#import "VideoViewController.h" -@import AVFoundation; - -@interface VideoViewController () -@property (strong, nonatomic) NSURL *videoUrl; -@property (strong, nonatomic) AVPlayer *avPlayer; -@property (strong, nonatomic) AVPlayerLayer *avPlayerLayer; -@property (strong, nonatomic) UIButton *cancelButton; -@end - -@implementation VideoViewController - -- (instancetype)initWithVideoUrl:(NSURL *)url { - self = [super init]; - if(self) { - _videoUrl = url; - } - - return self; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [UIColor whiteColor]; - - // the video player - self.avPlayer = [AVPlayer playerWithURL:self.videoUrl]; - self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; - - self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; - //self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(playerItemDidReachEnd:) - name:AVPlayerItemDidPlayToEndTimeNotification - object:[self.avPlayer currentItem]]; - - CGRect screenRect = [[UIScreen mainScreen] bounds]; - - self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height); - [self.view.layer addSublayer:self.avPlayerLayer]; - - // cancel button - [self.view addSubview:self.cancelButton]; - [self.cancelButton addTarget:self action:@selector(cancelButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - self.cancelButton.frame = CGRectMake(0, 0, 44, 44); -} - -- (void)viewWillAppear:(BOOL)animated{ - [super viewWillAppear:animated]; - - [self.avPlayer play]; -} - -- (void)playerItemDidReachEnd:(NSNotification *)notification { - AVPlayerItem *p = [notification object]; - [p seekToTime:kCMTimeZero]; -} - -- (BOOL)prefersStatusBarHidden { - return YES; -} - -- (UIButton *)cancelButton { - if(!_cancelButton) { - UIImage *cancelImage = [UIImage imageNamed:@"cancel.png"]; - UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; - button.tintColor = [UIColor whiteColor]; - [button setImage:cancelImage forState:UIControlStateNormal]; - button.imageView.clipsToBounds = NO; - button.contentEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); - button.layer.shadowColor = [UIColor blackColor].CGColor; - button.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); - button.layer.shadowOpacity = 0.4f; - button.layer.shadowRadius = 1.0f; - button.clipsToBounds = NO; - - _cancelButton = button; - } - - return _cancelButton; -} - -- (void)cancelButtonPressed:(UIButton *)button { - NSLog(@"cancel button pressed!"); - [self.navigationController popViewControllerAnimated:YES]; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end diff --git a/ViewUtils.h b/ViewUtils.h deleted file mode 100755 index efa5a28..0000000 --- a/ViewUtils.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// ViewUtils.h -// -// Version 1.1.2 -// -// Created by Nick Lockwood on 19/11/2011. -// Copyright (c) 2011 Charcoal Design -// -// Distributed under the permissive zlib License -// Get the latest version from here: -// -// https://github.com/nicklockwood/ViewUtils -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// - - -#import - -@interface UIView (ViewUtils) - -//nib loading - -+ (id)instanceWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil owner:(id)owner; -- (void)loadContentsWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil; - -//hierarchy - -- (UIView *)viewMatchingPredicate:(NSPredicate *)predicate; -- (UIView *)viewWithTag:(NSInteger)tag ofClass:(Class)viewClass; -- (UIView *)viewOfClass:(Class)viewClass; -- (NSArray *)viewsMatchingPredicate:(NSPredicate *)predicate; -- (NSArray *)viewsWithTag:(NSInteger)tag; -- (NSArray *)viewsWithTag:(NSInteger)tag ofClass:(Class)viewClass; -- (NSArray *)viewsOfClass:(Class)viewClass; - -- (UIView *)firstSuperviewMatchingPredicate:(NSPredicate *)predicate; -- (UIView *)firstSuperviewOfClass:(Class)viewClass; -- (UIView *)firstSuperviewWithTag:(NSInteger)tag; -- (UIView *)firstSuperviewWithTag:(NSInteger)tag ofClass:(Class)viewClass; - -- (BOOL)viewOrAnySuperviewMatchesPredicate:(NSPredicate *)predicate; -- (BOOL)viewOrAnySuperviewIsKindOfClass:(Class)viewClass; -- (BOOL)isSuperviewOfView:(UIView *)view; -- (BOOL)isSubviewOfView:(UIView *)view; - -- (UIViewController *)firstViewController; -- (UIView *)firstResponder; - -//frame accessors - -@property (nonatomic, assign) CGPoint origin; -@property (nonatomic, assign) CGSize size; -@property (nonatomic, assign) CGFloat top; -@property (nonatomic, assign) CGFloat left; -@property (nonatomic, assign) CGFloat bottom; -@property (nonatomic, assign) CGFloat right; -@property (nonatomic, assign) CGFloat width; -@property (nonatomic, assign) CGFloat height; -@property (nonatomic, assign) CGFloat x; -@property (nonatomic, assign) CGFloat y; - -//bounds accessors - -@property (nonatomic, assign) CGSize boundsSize; -@property (nonatomic, assign) CGFloat boundsWidth; -@property (nonatomic, assign) CGFloat boundsHeight; - -//content getters - -@property (nonatomic, readonly) CGRect contentBounds; -@property (nonatomic, readonly) CGPoint contentCenter; - -//additional frame setters - -- (void)setLeft:(CGFloat)left right:(CGFloat)right; -- (void)setWidth:(CGFloat)width right:(CGFloat)right; -- (void)setTop:(CGFloat)top bottom:(CGFloat)bottom; -- (void)setHeight:(CGFloat)height bottom:(CGFloat)bottom; - -//animation - -- (void)crossfadeWithDuration:(NSTimeInterval)duration; -- (void)crossfadeWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion; - -@end - diff --git a/ViewUtils.m b/ViewUtils.m deleted file mode 100755 index fe5bcb7..0000000 --- a/ViewUtils.m +++ /dev/null @@ -1,479 +0,0 @@ -// -// ViewUtils.m -// -// Version 1.1.2 -// -// Created by Nick Lockwood on 19/11/2011. -// Copyright (c) 2011 Charcoal Design -// -// Distributed under the permissive zlib License -// Get the latest version from here: -// -// https://github.com/nicklockwood/ViewUtils -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// - -#import "ViewUtils.h" -#import - - -#pragma GCC diagnostic ignored "-Wgnu" - - -@implementation UIView (ViewUtils) - -//nib loading - -+ (id)instanceWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil owner:(id)owner -{ - //default values - NSString *nibName = nibNameOrNil ?: NSStringFromClass(self); - NSBundle *bundle = bundleOrNil ?: [NSBundle mainBundle]; - - //cache nib to prevent unnecessary filesystem access - static NSCache *nibCache = nil; - if (nibCache == nil) - { - nibCache = [[NSCache alloc] init]; - } - NSString *pathKey = [NSString stringWithFormat:@"%@.%@", bundle.bundleIdentifier, nibName]; - UINib *nib = [nibCache objectForKey:pathKey]; - if (nib == nil) - { - NSString *nibPath = [bundle pathForResource:nibName ofType:@"nib"]; - if (nibPath) nib = [UINib nibWithNibName:nibName bundle:bundle]; - [nibCache setObject:nib ?: [NSNull null] forKey:pathKey]; - } - else if ([nib isKindOfClass:[NSNull class]]) - { - nib = nil; - } - - if (nib) - { - //attempt to load from nib - NSArray *contents = [nib instantiateWithOwner:owner options:nil]; - UIView *view = [contents count]? [contents objectAtIndex:0]: nil; - NSAssert ([view isKindOfClass:self], @"First object in nib '%@' was '%@'. Expected '%@'", nibName, view, self); - return view; - } - - //return empty view - return [[[self class] alloc] init]; -} - -- (void)loadContentsWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil -{ - NSString *nibName = nibNameOrNil ?: NSStringFromClass([self class]); - UIView *view = [UIView instanceWithNibName:nibName bundle:bundleOrNil owner:self]; - if (view) - { - if (CGSizeEqualToSize(self.frame.size, CGSizeZero)) - { - //if we have zero size, set size from content - self.size = view.size; - } - else - { - //otherwise set content size to match our size - view.frame = self.contentBounds; - } - [self addSubview:view]; - } -} - -//view searching - -- (UIView *)viewMatchingPredicate:(NSPredicate *)predicate -{ - if ([predicate evaluateWithObject:self]) - { - return self; - } - for (UIView *view in self.subviews) - { - UIView *match = [view viewMatchingPredicate:predicate]; - if (match) return match; - } - return nil; -} - -- (UIView *)viewWithTag:(NSInteger)tag ofClass:(Class)viewClass -{ - return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused NSDictionary *bindings) { - return [evaluatedObject tag] == tag && [evaluatedObject isKindOfClass:viewClass]; - }]]; -} - -- (UIView *)viewOfClass:(Class)viewClass -{ - return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused NSDictionary *bindings) { - return [evaluatedObject isKindOfClass:viewClass]; - }]]; -} - -- (NSArray *)viewsMatchingPredicate:(NSPredicate *)predicate -{ - NSMutableArray *matches = [NSMutableArray array]; - if ([predicate evaluateWithObject:self]) - { - [matches addObject:self]; - } - for (UIView *view in self.subviews) - { - //check for subviews - //avoid creating unnecessary array - if ([view.subviews count]) - { - [matches addObjectsFromArray:[view viewsMatchingPredicate:predicate]]; - } - else if ([predicate evaluateWithObject:view]) - { - [matches addObject:view]; - } - } - return matches; -} - -- (NSArray *)viewsWithTag:(NSInteger)tag -{ - return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) { - return [evaluatedObject tag] == tag; - }]]; -} - -- (NSArray *)viewsWithTag:(NSInteger)tag ofClass:(Class)viewClass -{ - return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) { - return [evaluatedObject tag] == tag && [evaluatedObject isKindOfClass:viewClass]; - }]]; -} - -- (NSArray *)viewsOfClass:(Class)viewClass -{ - return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) { - return [evaluatedObject isKindOfClass:viewClass]; - }]]; -} - -- (UIView *)firstSuperviewMatchingPredicate:(NSPredicate *)predicate -{ - if ([predicate evaluateWithObject:self]) - { - return self; - } - return [self.superview firstSuperviewMatchingPredicate:predicate]; -} - -- (UIView *)firstSuperviewOfClass:(Class)viewClass -{ - return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) { - return [superview isKindOfClass:viewClass]; - }]]; -} - -- (UIView *)firstSuperviewWithTag:(NSInteger)tag -{ - return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) { - return superview.tag == tag; - }]]; -} - -- (UIView *)firstSuperviewWithTag:(NSInteger)tag ofClass:(Class)viewClass -{ - return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) { - return superview.tag == tag && [superview isKindOfClass:viewClass]; - }]]; -} - -- (BOOL)viewOrAnySuperviewMatchesPredicate:(NSPredicate *)predicate -{ - if ([predicate evaluateWithObject:self]) - { - return YES; - } - return [self.superview viewOrAnySuperviewMatchesPredicate:predicate]; -} - -- (BOOL)viewOrAnySuperviewIsKindOfClass:(Class)viewClass -{ - return [self viewOrAnySuperviewMatchesPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) { - return [superview isKindOfClass:viewClass]; - }]]; -} - -- (BOOL)isSuperviewOfView:(UIView *)view -{ - return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) { - return superview == view; - }]] != nil; -} - -- (BOOL)isSubviewOfView:(UIView *)view -{ - return [view isSuperviewOfView:self]; -} - -//responder chain - -- (UIViewController *)firstViewController -{ - id responder = self; - while ((responder = [responder nextResponder])) - { - if ([responder isKindOfClass:[UIViewController class]]) - { - return responder; - } - } - return nil; -} - -- (UIView *)firstResponder -{ - return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) { - return [evaluatedObject isFirstResponder]; - }]]; -} - -//frame accessors - -- (CGPoint)origin -{ - return self.frame.origin; -} - -- (void)setOrigin:(CGPoint)origin -{ - CGRect frame = self.frame; - frame.origin = origin; - self.frame = frame; -} - -- (CGSize)size -{ - return self.frame.size; -} - -- (void)setSize:(CGSize)size -{ - CGRect frame = self.frame; - frame.size = size; - self.frame = frame; -} - -- (CGFloat)top -{ - return self.origin.y; -} - -- (void)setTop:(CGFloat)top -{ - CGRect frame = self.frame; - frame.origin.y = top; - self.frame = frame; -} - -- (CGFloat)left -{ - return self.origin.x; -} - -- (void)setLeft:(CGFloat)left -{ - CGRect frame = self.frame; - frame.origin.x = left; - self.frame = frame; -} - -- (CGFloat)right -{ - return self.left + self.width; -} - -- (void)setRight:(CGFloat)right -{ - CGRect frame = self.frame; - frame.origin.x = right - frame.size.width; - self.frame = frame; -} - -- (CGFloat)bottom -{ - return self.top + self.height; -} - -- (void)setBottom:(CGFloat)bottom -{ - CGRect frame = self.frame; - frame.origin.y = bottom - frame.size.height; - self.frame = frame; -} - -- (CGFloat)width -{ - return self.size.width; -} - -- (void)setWidth:(CGFloat)width -{ - CGRect frame = self.frame; - frame.size.width = width; - self.frame = frame; -} - -- (CGFloat)height -{ - return self.size.height; -} - -- (void)setHeight:(CGFloat)height -{ - CGRect frame = self.frame; - frame.size.height = height; - self.frame = frame; -} - -- (CGFloat)x -{ - return self.center.x; -} - -- (void)setX:(CGFloat)x -{ - self.center = CGPointMake(x, self.center.y); -} - -- (CGFloat)y -{ - return self.center.y; -} - -- (void)setY:(CGFloat)y -{ - self.center = CGPointMake(self.center.x, y); -} - -//bounds accessors - -- (CGSize)boundsSize -{ - return self.bounds.size; -} - -- (void)setBoundsSize:(CGSize)size -{ - CGRect bounds = self.bounds; - bounds.size = size; - self.bounds = bounds; -} - -- (CGFloat)boundsWidth -{ - return self.boundsSize.width; -} - -- (void)setBoundsWidth:(CGFloat)width -{ - CGRect bounds = self.bounds; - bounds.size.width = width; - self.bounds = bounds; -} - -- (CGFloat)boundsHeight -{ - return self.boundsSize.height; -} - -- (void)setBoundsHeight:(CGFloat)height -{ - CGRect bounds = self.bounds; - bounds.size.height = height; - self.bounds = bounds; -} - -//content getters - -- (CGRect)contentBounds -{ - return CGRectMake(0.0f, 0.0f, self.boundsWidth, self.boundsHeight); -} - -- (CGPoint)contentCenter -{ - return CGPointMake(self.boundsWidth/2.0f, self.boundsHeight/2.0f); -} - -//additional frame setters - -- (void)setLeft:(CGFloat)left right:(CGFloat)right -{ - CGRect frame = self.frame; - frame.origin.x = left; - frame.size.width = right - left; - self.frame = frame; -} - -- (void)setWidth:(CGFloat)width right:(CGFloat)right -{ - CGRect frame = self.frame; - frame.origin.x = right - width; - frame.size.width = width; - self.frame = frame; -} - -- (void)setTop:(CGFloat)top bottom:(CGFloat)bottom -{ - CGRect frame = self.frame; - frame.origin.y = top; - frame.size.height = bottom - top; - self.frame = frame; -} - -- (void)setHeight:(CGFloat)height bottom:(CGFloat)bottom -{ - CGRect frame = self.frame; - frame.origin.y = bottom - height; - frame.size.height = height; - self.frame = frame; -} - -//animation - -- (void)crossfadeWithDuration:(NSTimeInterval)duration -{ - //jump through a few hoops to avoid QuartzCore framework dependency - CAAnimation *animation = [NSClassFromString(@"CATransition") animation]; - [animation setValue:@"kCATransitionFade" forKey:@"type"]; - animation.duration = duration; - [self.layer addAnimation:animation forKey:nil]; -} - -- (void)crossfadeWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion -{ - [self crossfadeWithDuration:duration]; - if (completion) - { - dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)); - dispatch_after(time, dispatch_get_main_queue(), completion); - } -} - -@end