├── .gitignore ├── FacebookImagePicker.podspec ├── FacebookImagePicker ├── FacebookImagePicker.xcassets │ ├── CTAssetsPickerChecked.imageset │ │ ├── CTAssetsPickerChecked.png │ │ ├── CTAssetsPickerChecked@2x.png │ │ └── Contents.json │ ├── CTAssetsPickerChecked~iOS6.imageset │ │ ├── CTAssetsPickerChecked~iOS6.png │ │ ├── CTAssetsPickerChecked~iOS6@2x.png │ │ └── Contents.json │ └── album_placeholder.imageset │ │ ├── Contents.json │ │ └── album_placeholder@2x.png ├── FacebookImagePicker.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── FacebookImagePicker.xcworkspace │ └── contents.xcworkspacedata ├── FacebookImagePicker │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── Main.storyboard │ ├── FacebookImagePicker-Info.plist │ ├── FacebookImagePicker-Prefix.pch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── FacebookImagePickerTests │ ├── FacebookImagePickerTests-Info.plist │ ├── FacebookImagePickerTests.m │ └── en.lproj │ │ └── InfoPlist.strings ├── OLAlbumViewController.h ├── OLAlbumViewController.m ├── OLAlbumViewController.xib ├── OLFacebookAlbum.h ├── OLFacebookAlbum.m ├── OLFacebookAlbumRequest.h ├── OLFacebookAlbumRequest.m ├── OLFacebookImage.h ├── OLFacebookImage.m ├── OLFacebookImageDownloadDelegate.h ├── OLFacebookImageDownloadDelegate.m ├── OLFacebookImageDownloader.h ├── OLFacebookImageDownloader.m ├── OLFacebookImagePickerCell.h ├── OLFacebookImagePickerCell.m ├── OLFacebookImagePickerConstants.h ├── OLFacebookImagePickerConstants.m ├── OLFacebookImagePickerController.h ├── OLFacebookImagePickerController.m ├── OLFacebookPhotosForAlbumRequest.h ├── OLFacebookPhotosForAlbumRequest.m ├── OLPhotoViewController.h ├── OLPhotoViewController.m ├── OLPhotoViewController.xib ├── Podfile ├── Podfile.lock ├── UIImageView+FacebookFadeIn.h └── UIImageView+FacebookFadeIn.m ├── LICENSE ├── README.md └── preview.png /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # CocoaPods 23 | Pods -------------------------------------------------------------------------------- /FacebookImagePicker.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'FacebookImagePicker' 3 | s.version = '2.0.11' 4 | s.license = 'MIT' 5 | s.summary = 'An image/photo picker for Facebook albums & photos modelled after UIImagePickerController' 6 | s.author = { "Deon Botha" => "deon@oceanlabs.co" } 7 | s.social_media_url = 'https://twitter.com/dbotha' 8 | s.homepage = 'https://github.com/OceanLabs/FacebookImagePicker-iOS' 9 | s.platform = :ios, '7.0' 10 | s.requires_arc = true 11 | s.source = { 12 | :git => 'https://github.com/OceanLabs/FacebookImagePicker-iOS.git', 13 | :tag => s.version.to_s 14 | } 15 | s.source_files = ['FacebookImagePicker/OL*.{h,m}', 'FacebookImagePicker/UIImageView+FacebookFadeIn.{h,m}'] 16 | s.resources = ['FacebookImagePicker/FacebookImagePicker.xcassets', 'FacebookImagePicker/*.xib'] 17 | s.dependency 'FBSDKCoreKit', '~> 4.11.0' 18 | s.dependency 'FBSDKLoginKit', '~> 4.11.0' 19 | end 20 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked.imageset/CTAssetsPickerChecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked.imageset/CTAssetsPickerChecked.png -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked.imageset/CTAssetsPickerChecked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked.imageset/CTAssetsPickerChecked@2x.png -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "CTAssetsPickerChecked.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "CTAssetsPickerChecked@2x.png" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked~iOS6.imageset/CTAssetsPickerChecked~iOS6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked~iOS6.imageset/CTAssetsPickerChecked~iOS6.png -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked~iOS6.imageset/CTAssetsPickerChecked~iOS6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked~iOS6.imageset/CTAssetsPickerChecked~iOS6@2x.png -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/CTAssetsPickerChecked~iOS6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "CTAssetsPickerChecked~iOS6.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "CTAssetsPickerChecked~iOS6@2x.png" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/album_placeholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "album_placeholder@2x.png" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcassets/album_placeholder.imageset/album_placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/FacebookImagePicker/FacebookImagePicker.xcassets/album_placeholder.imageset/album_placeholder@2x.png -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2E5BDC4C1CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E5BDC491CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.m */; }; 11 | 2E5BDC4D1CEDF3B600257B1A /* OLFacebookImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E5BDC4B1CEDF3B600257B1A /* OLFacebookImageDownloader.m */; }; 12 | 3D0D7AC91AC07B8400746FC8 /* UIImageView+FacebookFadeIn.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0D7AC81AC07B8400746FC8 /* UIImageView+FacebookFadeIn.m */; }; 13 | 985B68DCADDD486BAD08BC6B /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 358D8857B0F243D7BEA15A1E /* libPods.a */; }; 14 | CD73BEDE185E220E0009DE03 /* OLFacebookAlbum.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEDD185E220E0009DE03 /* OLFacebookAlbum.m */; }; 15 | CD73BEE1185E221B0009DE03 /* OLFacebookImage.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEE0185E221B0009DE03 /* OLFacebookImage.m */; }; 16 | CD73BEE4185E22480009DE03 /* OLFacebookAlbumRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEE3185E22480009DE03 /* OLFacebookAlbumRequest.m */; }; 17 | CD73BEE9185EFFFB0009DE03 /* OLFacebookImagePickerConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEE8185EFFFB0009DE03 /* OLFacebookImagePickerConstants.m */; }; 18 | CD73BEEE185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEED185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.m */; }; 19 | CD73BEF2185F22C00009DE03 /* OLFacebookImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEF1185F22C00009DE03 /* OLFacebookImagePickerController.m */; }; 20 | CD73BF01185F26F60009DE03 /* OLAlbumViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BEFF185F26F60009DE03 /* OLAlbumViewController.m */; }; 21 | CD73BF02185F26F60009DE03 /* OLAlbumViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD73BF00185F26F60009DE03 /* OLAlbumViewController.xib */; }; 22 | CD73BF54185F6C570009DE03 /* OLPhotoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BF52185F6C570009DE03 /* OLPhotoViewController.m */; }; 23 | CD73BF55185F6C570009DE03 /* OLPhotoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD73BF53185F6C570009DE03 /* OLPhotoViewController.xib */; }; 24 | CD73BF5C185F7B560009DE03 /* OLFacebookImagePickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = CD73BF5B185F7B560009DE03 /* OLFacebookImagePickerCell.m */; }; 25 | CD73BF5E185F7F530009DE03 /* FacebookImagePicker.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD73BF5D185F7F530009DE03 /* FacebookImagePicker.xcassets */; }; 26 | CD9AF16E185E206A00A56B3F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF16D185E206A00A56B3F /* Foundation.framework */; }; 27 | CD9AF170185E206A00A56B3F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF16F185E206A00A56B3F /* CoreGraphics.framework */; }; 28 | CD9AF172185E206A00A56B3F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF171185E206A00A56B3F /* UIKit.framework */; }; 29 | CD9AF178185E206A00A56B3F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CD9AF176185E206A00A56B3F /* InfoPlist.strings */; }; 30 | CD9AF17A185E206A00A56B3F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9AF179185E206A00A56B3F /* main.m */; }; 31 | CD9AF17E185E206A00A56B3F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9AF17D185E206A00A56B3F /* AppDelegate.m */; }; 32 | CD9AF181185E206A00A56B3F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD9AF17F185E206A00A56B3F /* Main.storyboard */; }; 33 | CD9AF184185E206A00A56B3F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9AF183185E206A00A56B3F /* ViewController.m */; }; 34 | CD9AF186185E206A00A56B3F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD9AF185185E206A00A56B3F /* Images.xcassets */; }; 35 | CD9AF18D185E206A00A56B3F /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF18C185E206A00A56B3F /* XCTest.framework */; }; 36 | CD9AF18E185E206A00A56B3F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF16D185E206A00A56B3F /* Foundation.framework */; }; 37 | CD9AF18F185E206A00A56B3F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9AF171185E206A00A56B3F /* UIKit.framework */; }; 38 | CD9AF197185E206A00A56B3F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CD9AF195185E206A00A56B3F /* InfoPlist.strings */; }; 39 | CD9AF199185E206A00A56B3F /* FacebookImagePickerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD9AF198185E206A00A56B3F /* FacebookImagePickerTests.m */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXContainerItemProxy section */ 43 | CD9AF190185E206A00A56B3F /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = CD9AF162185E206A00A56B3F /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = CD9AF169185E206A00A56B3F; 48 | remoteInfo = FacebookImagePicker; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 144025EE631714E88B7F3F86 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 54 | 2E5BDC481CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImageDownloadDelegate.h; sourceTree = ""; }; 55 | 2E5BDC491CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImageDownloadDelegate.m; sourceTree = ""; }; 56 | 2E5BDC4A1CEDF3B600257B1A /* OLFacebookImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImageDownloader.h; sourceTree = ""; }; 57 | 2E5BDC4B1CEDF3B600257B1A /* OLFacebookImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImageDownloader.m; sourceTree = ""; }; 58 | 358D8857B0F243D7BEA15A1E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 3D0D7AC71AC07B8400746FC8 /* UIImageView+FacebookFadeIn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+FacebookFadeIn.h"; sourceTree = ""; }; 60 | 3D0D7AC81AC07B8400746FC8 /* UIImageView+FacebookFadeIn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+FacebookFadeIn.m"; sourceTree = ""; }; 61 | CD73BEDC185E220E0009DE03 /* OLFacebookAlbum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookAlbum.h; sourceTree = ""; }; 62 | CD73BEDD185E220E0009DE03 /* OLFacebookAlbum.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookAlbum.m; sourceTree = ""; }; 63 | CD73BEDF185E221B0009DE03 /* OLFacebookImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImage.h; sourceTree = ""; }; 64 | CD73BEE0185E221B0009DE03 /* OLFacebookImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImage.m; sourceTree = ""; }; 65 | CD73BEE2185E22480009DE03 /* OLFacebookAlbumRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookAlbumRequest.h; sourceTree = ""; }; 66 | CD73BEE3185E22480009DE03 /* OLFacebookAlbumRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookAlbumRequest.m; sourceTree = ""; }; 67 | CD73BEE7185EFFFB0009DE03 /* OLFacebookImagePickerConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImagePickerConstants.h; sourceTree = ""; }; 68 | CD73BEE8185EFFFB0009DE03 /* OLFacebookImagePickerConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImagePickerConstants.m; sourceTree = ""; }; 69 | CD73BEEC185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookPhotosForAlbumRequest.h; sourceTree = ""; }; 70 | CD73BEED185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookPhotosForAlbumRequest.m; sourceTree = ""; }; 71 | CD73BEF0185F22C00009DE03 /* OLFacebookImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImagePickerController.h; sourceTree = ""; }; 72 | CD73BEF1185F22C00009DE03 /* OLFacebookImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImagePickerController.m; sourceTree = ""; }; 73 | CD73BEFE185F26F60009DE03 /* OLAlbumViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLAlbumViewController.h; sourceTree = ""; }; 74 | CD73BEFF185F26F60009DE03 /* OLAlbumViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLAlbumViewController.m; sourceTree = ""; }; 75 | CD73BF00185F26F60009DE03 /* OLAlbumViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OLAlbumViewController.xib; sourceTree = ""; }; 76 | CD73BF51185F6C570009DE03 /* OLPhotoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLPhotoViewController.h; sourceTree = ""; }; 77 | CD73BF52185F6C570009DE03 /* OLPhotoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLPhotoViewController.m; sourceTree = ""; }; 78 | CD73BF53185F6C570009DE03 /* OLPhotoViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OLPhotoViewController.xib; sourceTree = ""; }; 79 | CD73BF5A185F7B560009DE03 /* OLFacebookImagePickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLFacebookImagePickerCell.h; sourceTree = ""; }; 80 | CD73BF5B185F7B560009DE03 /* OLFacebookImagePickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLFacebookImagePickerCell.m; sourceTree = ""; }; 81 | CD73BF5D185F7F530009DE03 /* FacebookImagePicker.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FacebookImagePicker.xcassets; sourceTree = ""; }; 82 | CD9AF16A185E206A00A56B3F /* FacebookImagePicker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FacebookImagePicker.app; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | CD9AF16D185E206A00A56B3F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 84 | CD9AF16F185E206A00A56B3F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 85 | CD9AF171185E206A00A56B3F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 86 | CD9AF175185E206A00A56B3F /* FacebookImagePicker-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FacebookImagePicker-Info.plist"; sourceTree = ""; }; 87 | CD9AF177185E206A00A56B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 88 | CD9AF179185E206A00A56B3F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 89 | CD9AF17B185E206A00A56B3F /* FacebookImagePicker-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FacebookImagePicker-Prefix.pch"; sourceTree = ""; }; 90 | CD9AF17C185E206A00A56B3F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 91 | CD9AF17D185E206A00A56B3F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 92 | CD9AF180185E206A00A56B3F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 93 | CD9AF182185E206A00A56B3F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 94 | CD9AF183185E206A00A56B3F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 95 | CD9AF185185E206A00A56B3F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 96 | CD9AF18B185E206A00A56B3F /* FacebookImagePickerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FacebookImagePickerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | CD9AF18C185E206A00A56B3F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 98 | CD9AF194185E206A00A56B3F /* FacebookImagePickerTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FacebookImagePickerTests-Info.plist"; sourceTree = ""; }; 99 | CD9AF196185E206A00A56B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 100 | CD9AF198185E206A00A56B3F /* FacebookImagePickerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FacebookImagePickerTests.m; sourceTree = ""; }; 101 | DAF8C837E5551290087B7F7A /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 102 | /* End PBXFileReference section */ 103 | 104 | /* Begin PBXFrameworksBuildPhase section */ 105 | CD9AF167185E206A00A56B3F /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | CD9AF170185E206A00A56B3F /* CoreGraphics.framework in Frameworks */, 110 | CD9AF172185E206A00A56B3F /* UIKit.framework in Frameworks */, 111 | CD9AF16E185E206A00A56B3F /* Foundation.framework in Frameworks */, 112 | 985B68DCADDD486BAD08BC6B /* libPods.a in Frameworks */, 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | CD9AF188185E206A00A56B3F /* Frameworks */ = { 117 | isa = PBXFrameworksBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | CD9AF18D185E206A00A56B3F /* XCTest.framework in Frameworks */, 121 | CD9AF18F185E206A00A56B3F /* UIKit.framework in Frameworks */, 122 | CD9AF18E185E206A00A56B3F /* Foundation.framework in Frameworks */, 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXFrameworksBuildPhase section */ 127 | 128 | /* Begin PBXGroup section */ 129 | CD73BEDA185E21840009DE03 /* FacebookImagePicker */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | CD73BF48185F5EAE0009DE03 /* Resources */, 133 | CD73BF57185F7A5C0009DE03 /* View */, 134 | CD73BEEB185F0B3D0009DE03 /* Controller */, 135 | CD73BEDB185E21F90009DE03 /* Model */, 136 | ); 137 | name = FacebookImagePicker; 138 | sourceTree = ""; 139 | }; 140 | CD73BEDB185E21F90009DE03 /* Model */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | CD73BEEF185F1EC90009DE03 /* Private */, 144 | CD73BEDF185E221B0009DE03 /* OLFacebookImage.h */, 145 | CD73BEE0185E221B0009DE03 /* OLFacebookImage.m */, 146 | ); 147 | name = Model; 148 | sourceTree = ""; 149 | }; 150 | CD73BEEB185F0B3D0009DE03 /* Controller */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | CD73BEF3185F26900009DE03 /* Private */, 154 | CD73BEF0185F22C00009DE03 /* OLFacebookImagePickerController.h */, 155 | CD73BEF1185F22C00009DE03 /* OLFacebookImagePickerController.m */, 156 | ); 157 | name = Controller; 158 | sourceTree = ""; 159 | }; 160 | CD73BEEF185F1EC90009DE03 /* Private */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | CD73BEDC185E220E0009DE03 /* OLFacebookAlbum.h */, 164 | CD73BEDD185E220E0009DE03 /* OLFacebookAlbum.m */, 165 | CD73BEE2185E22480009DE03 /* OLFacebookAlbumRequest.h */, 166 | CD73BEE3185E22480009DE03 /* OLFacebookAlbumRequest.m */, 167 | CD73BEEC185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.h */, 168 | CD73BEED185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.m */, 169 | CD73BEE7185EFFFB0009DE03 /* OLFacebookImagePickerConstants.h */, 170 | CD73BEE8185EFFFB0009DE03 /* OLFacebookImagePickerConstants.m */, 171 | 2E5BDC481CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.h */, 172 | 2E5BDC491CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.m */, 173 | 2E5BDC4A1CEDF3B600257B1A /* OLFacebookImageDownloader.h */, 174 | 2E5BDC4B1CEDF3B600257B1A /* OLFacebookImageDownloader.m */, 175 | ); 176 | name = Private; 177 | sourceTree = ""; 178 | }; 179 | CD73BEF3185F26900009DE03 /* Private */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | CD73BEFE185F26F60009DE03 /* OLAlbumViewController.h */, 183 | CD73BEFF185F26F60009DE03 /* OLAlbumViewController.m */, 184 | CD73BF51185F6C570009DE03 /* OLPhotoViewController.h */, 185 | CD73BF52185F6C570009DE03 /* OLPhotoViewController.m */, 186 | ); 187 | name = Private; 188 | sourceTree = ""; 189 | }; 190 | CD73BF48185F5EAE0009DE03 /* Resources */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | CD73BF5D185F7F530009DE03 /* FacebookImagePicker.xcassets */, 194 | ); 195 | name = Resources; 196 | sourceTree = ""; 197 | }; 198 | CD73BF57185F7A5C0009DE03 /* View */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | CD73BF58185F7A670009DE03 /* Private */, 202 | ); 203 | name = View; 204 | sourceTree = ""; 205 | }; 206 | CD73BF58185F7A670009DE03 /* Private */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | CD73BF59185F7A6F0009DE03 /* XIB */, 210 | CD73BF5A185F7B560009DE03 /* OLFacebookImagePickerCell.h */, 211 | CD73BF5B185F7B560009DE03 /* OLFacebookImagePickerCell.m */, 212 | 3D0D7AC71AC07B8400746FC8 /* UIImageView+FacebookFadeIn.h */, 213 | 3D0D7AC81AC07B8400746FC8 /* UIImageView+FacebookFadeIn.m */, 214 | ); 215 | name = Private; 216 | sourceTree = ""; 217 | }; 218 | CD73BF59185F7A6F0009DE03 /* XIB */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | CD73BF00185F26F60009DE03 /* OLAlbumViewController.xib */, 222 | CD73BF53185F6C570009DE03 /* OLPhotoViewController.xib */, 223 | ); 224 | name = XIB; 225 | sourceTree = ""; 226 | }; 227 | CD9AF161185E206A00A56B3F = { 228 | isa = PBXGroup; 229 | children = ( 230 | CD73BEDA185E21840009DE03 /* FacebookImagePicker */, 231 | CD9AF173185E206A00A56B3F /* Sample App */, 232 | CD9AF192185E206A00A56B3F /* FacebookImagePickerTests */, 233 | CD9AF16C185E206A00A56B3F /* Frameworks */, 234 | CD9AF16B185E206A00A56B3F /* Products */, 235 | FD7CCD7C7F39359FB6289E13 /* Pods */, 236 | ); 237 | sourceTree = ""; 238 | }; 239 | CD9AF16B185E206A00A56B3F /* Products */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | CD9AF16A185E206A00A56B3F /* FacebookImagePicker.app */, 243 | CD9AF18B185E206A00A56B3F /* FacebookImagePickerTests.xctest */, 244 | ); 245 | name = Products; 246 | sourceTree = ""; 247 | }; 248 | CD9AF16C185E206A00A56B3F /* Frameworks */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | CD9AF16D185E206A00A56B3F /* Foundation.framework */, 252 | CD9AF16F185E206A00A56B3F /* CoreGraphics.framework */, 253 | CD9AF171185E206A00A56B3F /* UIKit.framework */, 254 | CD9AF18C185E206A00A56B3F /* XCTest.framework */, 255 | 358D8857B0F243D7BEA15A1E /* libPods.a */, 256 | ); 257 | name = Frameworks; 258 | sourceTree = ""; 259 | }; 260 | CD9AF173185E206A00A56B3F /* Sample App */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | CD9AF17C185E206A00A56B3F /* AppDelegate.h */, 264 | CD9AF17D185E206A00A56B3F /* AppDelegate.m */, 265 | CD9AF17F185E206A00A56B3F /* Main.storyboard */, 266 | CD9AF182185E206A00A56B3F /* ViewController.h */, 267 | CD9AF183185E206A00A56B3F /* ViewController.m */, 268 | CD9AF185185E206A00A56B3F /* Images.xcassets */, 269 | CD9AF174185E206A00A56B3F /* Supporting Files */, 270 | ); 271 | name = "Sample App"; 272 | path = FacebookImagePicker; 273 | sourceTree = ""; 274 | }; 275 | CD9AF174185E206A00A56B3F /* Supporting Files */ = { 276 | isa = PBXGroup; 277 | children = ( 278 | CD9AF175185E206A00A56B3F /* FacebookImagePicker-Info.plist */, 279 | CD9AF176185E206A00A56B3F /* InfoPlist.strings */, 280 | CD9AF179185E206A00A56B3F /* main.m */, 281 | CD9AF17B185E206A00A56B3F /* FacebookImagePicker-Prefix.pch */, 282 | ); 283 | name = "Supporting Files"; 284 | sourceTree = ""; 285 | }; 286 | CD9AF192185E206A00A56B3F /* FacebookImagePickerTests */ = { 287 | isa = PBXGroup; 288 | children = ( 289 | CD9AF198185E206A00A56B3F /* FacebookImagePickerTests.m */, 290 | CD9AF193185E206A00A56B3F /* Supporting Files */, 291 | ); 292 | path = FacebookImagePickerTests; 293 | sourceTree = ""; 294 | }; 295 | CD9AF193185E206A00A56B3F /* Supporting Files */ = { 296 | isa = PBXGroup; 297 | children = ( 298 | CD9AF194185E206A00A56B3F /* FacebookImagePickerTests-Info.plist */, 299 | CD9AF195185E206A00A56B3F /* InfoPlist.strings */, 300 | ); 301 | name = "Supporting Files"; 302 | sourceTree = ""; 303 | }; 304 | FD7CCD7C7F39359FB6289E13 /* Pods */ = { 305 | isa = PBXGroup; 306 | children = ( 307 | DAF8C837E5551290087B7F7A /* Pods.debug.xcconfig */, 308 | 144025EE631714E88B7F3F86 /* Pods.release.xcconfig */, 309 | ); 310 | name = Pods; 311 | sourceTree = ""; 312 | }; 313 | /* End PBXGroup section */ 314 | 315 | /* Begin PBXNativeTarget section */ 316 | CD9AF169185E206A00A56B3F /* FacebookImagePicker */ = { 317 | isa = PBXNativeTarget; 318 | buildConfigurationList = CD9AF19C185E206A00A56B3F /* Build configuration list for PBXNativeTarget "FacebookImagePicker" */; 319 | buildPhases = ( 320 | 712C61FEADC04B7D80F95841 /* Check Pods Manifest.lock */, 321 | CD9AF166185E206A00A56B3F /* Sources */, 322 | CD9AF167185E206A00A56B3F /* Frameworks */, 323 | CD9AF168185E206A00A56B3F /* Resources */, 324 | 2ABCD2088C26466188B435FE /* Copy Pods Resources */, 325 | BCF23303496CDCB5CCE7D043 /* Embed Pods Frameworks */, 326 | ); 327 | buildRules = ( 328 | ); 329 | dependencies = ( 330 | ); 331 | name = FacebookImagePicker; 332 | productName = FacebookImagePicker; 333 | productReference = CD9AF16A185E206A00A56B3F /* FacebookImagePicker.app */; 334 | productType = "com.apple.product-type.application"; 335 | }; 336 | CD9AF18A185E206A00A56B3F /* FacebookImagePickerTests */ = { 337 | isa = PBXNativeTarget; 338 | buildConfigurationList = CD9AF19F185E206A00A56B3F /* Build configuration list for PBXNativeTarget "FacebookImagePickerTests" */; 339 | buildPhases = ( 340 | CD9AF187185E206A00A56B3F /* Sources */, 341 | CD9AF188185E206A00A56B3F /* Frameworks */, 342 | CD9AF189185E206A00A56B3F /* Resources */, 343 | ); 344 | buildRules = ( 345 | ); 346 | dependencies = ( 347 | CD9AF191185E206A00A56B3F /* PBXTargetDependency */, 348 | ); 349 | name = FacebookImagePickerTests; 350 | productName = FacebookImagePickerTests; 351 | productReference = CD9AF18B185E206A00A56B3F /* FacebookImagePickerTests.xctest */; 352 | productType = "com.apple.product-type.bundle.unit-test"; 353 | }; 354 | /* End PBXNativeTarget section */ 355 | 356 | /* Begin PBXProject section */ 357 | CD9AF162185E206A00A56B3F /* Project object */ = { 358 | isa = PBXProject; 359 | attributes = { 360 | LastUpgradeCheck = 0630; 361 | ORGANIZATIONNAME = "Deon Botha"; 362 | TargetAttributes = { 363 | CD9AF169185E206A00A56B3F = { 364 | DevelopmentTeam = 52629Y9DP9; 365 | }; 366 | CD9AF18A185E206A00A56B3F = { 367 | TestTargetID = CD9AF169185E206A00A56B3F; 368 | }; 369 | }; 370 | }; 371 | buildConfigurationList = CD9AF165185E206A00A56B3F /* Build configuration list for PBXProject "FacebookImagePicker" */; 372 | compatibilityVersion = "Xcode 3.2"; 373 | developmentRegion = English; 374 | hasScannedForEncodings = 0; 375 | knownRegions = ( 376 | en, 377 | Base, 378 | ); 379 | mainGroup = CD9AF161185E206A00A56B3F; 380 | productRefGroup = CD9AF16B185E206A00A56B3F /* Products */; 381 | projectDirPath = ""; 382 | projectRoot = ""; 383 | targets = ( 384 | CD9AF169185E206A00A56B3F /* FacebookImagePicker */, 385 | CD9AF18A185E206A00A56B3F /* FacebookImagePickerTests */, 386 | ); 387 | }; 388 | /* End PBXProject section */ 389 | 390 | /* Begin PBXResourcesBuildPhase section */ 391 | CD9AF168185E206A00A56B3F /* Resources */ = { 392 | isa = PBXResourcesBuildPhase; 393 | buildActionMask = 2147483647; 394 | files = ( 395 | CD73BF5E185F7F530009DE03 /* FacebookImagePicker.xcassets in Resources */, 396 | CD73BF55185F6C570009DE03 /* OLPhotoViewController.xib in Resources */, 397 | CD9AF186185E206A00A56B3F /* Images.xcassets in Resources */, 398 | CD73BF02185F26F60009DE03 /* OLAlbumViewController.xib in Resources */, 399 | CD9AF178185E206A00A56B3F /* InfoPlist.strings in Resources */, 400 | CD9AF181185E206A00A56B3F /* Main.storyboard in Resources */, 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | CD9AF189185E206A00A56B3F /* Resources */ = { 405 | isa = PBXResourcesBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | CD9AF197185E206A00A56B3F /* InfoPlist.strings in Resources */, 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | }; 412 | /* End PBXResourcesBuildPhase section */ 413 | 414 | /* Begin PBXShellScriptBuildPhase section */ 415 | 2ABCD2088C26466188B435FE /* Copy Pods Resources */ = { 416 | isa = PBXShellScriptBuildPhase; 417 | buildActionMask = 2147483647; 418 | files = ( 419 | ); 420 | inputPaths = ( 421 | ); 422 | name = "Copy Pods Resources"; 423 | outputPaths = ( 424 | ); 425 | runOnlyForDeploymentPostprocessing = 0; 426 | shellPath = /bin/sh; 427 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 428 | showEnvVarsInLog = 0; 429 | }; 430 | 712C61FEADC04B7D80F95841 /* Check Pods Manifest.lock */ = { 431 | isa = PBXShellScriptBuildPhase; 432 | buildActionMask = 2147483647; 433 | files = ( 434 | ); 435 | inputPaths = ( 436 | ); 437 | name = "Check Pods Manifest.lock"; 438 | outputPaths = ( 439 | ); 440 | runOnlyForDeploymentPostprocessing = 0; 441 | shellPath = /bin/sh; 442 | 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"; 443 | showEnvVarsInLog = 0; 444 | }; 445 | BCF23303496CDCB5CCE7D043 /* Embed Pods Frameworks */ = { 446 | isa = PBXShellScriptBuildPhase; 447 | buildActionMask = 2147483647; 448 | files = ( 449 | ); 450 | inputPaths = ( 451 | ); 452 | name = "Embed Pods Frameworks"; 453 | outputPaths = ( 454 | ); 455 | runOnlyForDeploymentPostprocessing = 0; 456 | shellPath = /bin/sh; 457 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; 458 | showEnvVarsInLog = 0; 459 | }; 460 | /* End PBXShellScriptBuildPhase section */ 461 | 462 | /* Begin PBXSourcesBuildPhase section */ 463 | CD9AF166185E206A00A56B3F /* Sources */ = { 464 | isa = PBXSourcesBuildPhase; 465 | buildActionMask = 2147483647; 466 | files = ( 467 | CD9AF184185E206A00A56B3F /* ViewController.m in Sources */, 468 | CD9AF17E185E206A00A56B3F /* AppDelegate.m in Sources */, 469 | CD73BEE9185EFFFB0009DE03 /* OLFacebookImagePickerConstants.m in Sources */, 470 | CD73BF01185F26F60009DE03 /* OLAlbumViewController.m in Sources */, 471 | 3D0D7AC91AC07B8400746FC8 /* UIImageView+FacebookFadeIn.m in Sources */, 472 | CD73BEE1185E221B0009DE03 /* OLFacebookImage.m in Sources */, 473 | CD73BF5C185F7B560009DE03 /* OLFacebookImagePickerCell.m in Sources */, 474 | 2E5BDC4C1CEDF3B600257B1A /* OLFacebookImageDownloadDelegate.m in Sources */, 475 | CD73BEDE185E220E0009DE03 /* OLFacebookAlbum.m in Sources */, 476 | CD73BEEE185F0BC20009DE03 /* OLFacebookPhotosForAlbumRequest.m in Sources */, 477 | 2E5BDC4D1CEDF3B600257B1A /* OLFacebookImageDownloader.m in Sources */, 478 | CD73BEF2185F22C00009DE03 /* OLFacebookImagePickerController.m in Sources */, 479 | CD73BF54185F6C570009DE03 /* OLPhotoViewController.m in Sources */, 480 | CD73BEE4185E22480009DE03 /* OLFacebookAlbumRequest.m in Sources */, 481 | CD9AF17A185E206A00A56B3F /* main.m in Sources */, 482 | ); 483 | runOnlyForDeploymentPostprocessing = 0; 484 | }; 485 | CD9AF187185E206A00A56B3F /* Sources */ = { 486 | isa = PBXSourcesBuildPhase; 487 | buildActionMask = 2147483647; 488 | files = ( 489 | CD9AF199185E206A00A56B3F /* FacebookImagePickerTests.m in Sources */, 490 | ); 491 | runOnlyForDeploymentPostprocessing = 0; 492 | }; 493 | /* End PBXSourcesBuildPhase section */ 494 | 495 | /* Begin PBXTargetDependency section */ 496 | CD9AF191185E206A00A56B3F /* PBXTargetDependency */ = { 497 | isa = PBXTargetDependency; 498 | target = CD9AF169185E206A00A56B3F /* FacebookImagePicker */; 499 | targetProxy = CD9AF190185E206A00A56B3F /* PBXContainerItemProxy */; 500 | }; 501 | /* End PBXTargetDependency section */ 502 | 503 | /* Begin PBXVariantGroup section */ 504 | CD9AF176185E206A00A56B3F /* InfoPlist.strings */ = { 505 | isa = PBXVariantGroup; 506 | children = ( 507 | CD9AF177185E206A00A56B3F /* en */, 508 | ); 509 | name = InfoPlist.strings; 510 | sourceTree = ""; 511 | }; 512 | CD9AF17F185E206A00A56B3F /* Main.storyboard */ = { 513 | isa = PBXVariantGroup; 514 | children = ( 515 | CD9AF180185E206A00A56B3F /* Base */, 516 | ); 517 | name = Main.storyboard; 518 | sourceTree = ""; 519 | }; 520 | CD9AF195185E206A00A56B3F /* InfoPlist.strings */ = { 521 | isa = PBXVariantGroup; 522 | children = ( 523 | CD9AF196185E206A00A56B3F /* en */, 524 | ); 525 | name = InfoPlist.strings; 526 | sourceTree = ""; 527 | }; 528 | /* End PBXVariantGroup section */ 529 | 530 | /* Begin XCBuildConfiguration section */ 531 | CD9AF19A185E206A00A56B3F /* Debug */ = { 532 | isa = XCBuildConfiguration; 533 | buildSettings = { 534 | ALWAYS_SEARCH_USER_PATHS = NO; 535 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 536 | CLANG_CXX_LIBRARY = "libc++"; 537 | CLANG_ENABLE_MODULES = YES; 538 | CLANG_ENABLE_OBJC_ARC = YES; 539 | CLANG_WARN_BOOL_CONVERSION = YES; 540 | CLANG_WARN_CONSTANT_CONVERSION = YES; 541 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 542 | CLANG_WARN_EMPTY_BODY = YES; 543 | CLANG_WARN_ENUM_CONVERSION = YES; 544 | CLANG_WARN_INT_CONVERSION = YES; 545 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 546 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 547 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 548 | COPY_PHASE_STRIP = NO; 549 | GCC_C_LANGUAGE_STANDARD = gnu99; 550 | GCC_DYNAMIC_NO_PIC = NO; 551 | GCC_OPTIMIZATION_LEVEL = 0; 552 | GCC_PREPROCESSOR_DEFINITIONS = ( 553 | "DEBUG=1", 554 | "$(inherited)", 555 | ); 556 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 557 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 558 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 559 | GCC_WARN_UNDECLARED_SELECTOR = YES; 560 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 561 | GCC_WARN_UNUSED_FUNCTION = YES; 562 | GCC_WARN_UNUSED_VARIABLE = YES; 563 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 564 | ONLY_ACTIVE_ARCH = YES; 565 | SDKROOT = iphoneos; 566 | }; 567 | name = Debug; 568 | }; 569 | CD9AF19B185E206A00A56B3F /* Release */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ALWAYS_SEARCH_USER_PATHS = NO; 573 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 574 | CLANG_CXX_LIBRARY = "libc++"; 575 | CLANG_ENABLE_MODULES = YES; 576 | CLANG_ENABLE_OBJC_ARC = YES; 577 | CLANG_WARN_BOOL_CONVERSION = YES; 578 | CLANG_WARN_CONSTANT_CONVERSION = YES; 579 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 580 | CLANG_WARN_EMPTY_BODY = YES; 581 | CLANG_WARN_ENUM_CONVERSION = YES; 582 | CLANG_WARN_INT_CONVERSION = YES; 583 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 584 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 585 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 586 | COPY_PHASE_STRIP = YES; 587 | ENABLE_NS_ASSERTIONS = NO; 588 | GCC_C_LANGUAGE_STANDARD = gnu99; 589 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 590 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 591 | GCC_WARN_UNDECLARED_SELECTOR = YES; 592 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 593 | GCC_WARN_UNUSED_FUNCTION = YES; 594 | GCC_WARN_UNUSED_VARIABLE = YES; 595 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 596 | SDKROOT = iphoneos; 597 | VALIDATE_PRODUCT = YES; 598 | }; 599 | name = Release; 600 | }; 601 | CD9AF19D185E206A00A56B3F /* Debug */ = { 602 | isa = XCBuildConfiguration; 603 | baseConfigurationReference = DAF8C837E5551290087B7F7A /* Pods.debug.xcconfig */; 604 | buildSettings = { 605 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 606 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 607 | CODE_SIGN_IDENTITY = "iPhone Developer"; 608 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 609 | GCC_PREFIX_HEADER = "FacebookImagePicker/FacebookImagePicker-Prefix.pch"; 610 | INFOPLIST_FILE = "FacebookImagePicker/FacebookImagePicker-Info.plist"; 611 | PRODUCT_NAME = "$(TARGET_NAME)"; 612 | WRAPPER_EXTENSION = app; 613 | }; 614 | name = Debug; 615 | }; 616 | CD9AF19E185E206A00A56B3F /* Release */ = { 617 | isa = XCBuildConfiguration; 618 | baseConfigurationReference = 144025EE631714E88B7F3F86 /* Pods.release.xcconfig */; 619 | buildSettings = { 620 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 621 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 622 | CODE_SIGN_IDENTITY = "iPhone Developer"; 623 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 624 | GCC_PREFIX_HEADER = "FacebookImagePicker/FacebookImagePicker-Prefix.pch"; 625 | INFOPLIST_FILE = "FacebookImagePicker/FacebookImagePicker-Info.plist"; 626 | PRODUCT_NAME = "$(TARGET_NAME)"; 627 | WRAPPER_EXTENSION = app; 628 | }; 629 | name = Release; 630 | }; 631 | CD9AF1A0185E206A00A56B3F /* Debug */ = { 632 | isa = XCBuildConfiguration; 633 | buildSettings = { 634 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/FacebookImagePicker.app/FacebookImagePicker"; 635 | FRAMEWORK_SEARCH_PATHS = ( 636 | "$(SDKROOT)/Developer/Library/Frameworks", 637 | "$(inherited)", 638 | "$(DEVELOPER_FRAMEWORKS_DIR)", 639 | ); 640 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 641 | GCC_PREFIX_HEADER = "FacebookImagePicker/FacebookImagePicker-Prefix.pch"; 642 | GCC_PREPROCESSOR_DEFINITIONS = ( 643 | "DEBUG=1", 644 | "$(inherited)", 645 | ); 646 | INFOPLIST_FILE = "FacebookImagePickerTests/FacebookImagePickerTests-Info.plist"; 647 | PRODUCT_NAME = "$(TARGET_NAME)"; 648 | TEST_HOST = "$(BUNDLE_LOADER)"; 649 | WRAPPER_EXTENSION = xctest; 650 | }; 651 | name = Debug; 652 | }; 653 | CD9AF1A1185E206A00A56B3F /* Release */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/FacebookImagePicker.app/FacebookImagePicker"; 657 | FRAMEWORK_SEARCH_PATHS = ( 658 | "$(SDKROOT)/Developer/Library/Frameworks", 659 | "$(inherited)", 660 | "$(DEVELOPER_FRAMEWORKS_DIR)", 661 | ); 662 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 663 | GCC_PREFIX_HEADER = "FacebookImagePicker/FacebookImagePicker-Prefix.pch"; 664 | INFOPLIST_FILE = "FacebookImagePickerTests/FacebookImagePickerTests-Info.plist"; 665 | PRODUCT_NAME = "$(TARGET_NAME)"; 666 | TEST_HOST = "$(BUNDLE_LOADER)"; 667 | WRAPPER_EXTENSION = xctest; 668 | }; 669 | name = Release; 670 | }; 671 | /* End XCBuildConfiguration section */ 672 | 673 | /* Begin XCConfigurationList section */ 674 | CD9AF165185E206A00A56B3F /* Build configuration list for PBXProject "FacebookImagePicker" */ = { 675 | isa = XCConfigurationList; 676 | buildConfigurations = ( 677 | CD9AF19A185E206A00A56B3F /* Debug */, 678 | CD9AF19B185E206A00A56B3F /* Release */, 679 | ); 680 | defaultConfigurationIsVisible = 0; 681 | defaultConfigurationName = Release; 682 | }; 683 | CD9AF19C185E206A00A56B3F /* Build configuration list for PBXNativeTarget "FacebookImagePicker" */ = { 684 | isa = XCConfigurationList; 685 | buildConfigurations = ( 686 | CD9AF19D185E206A00A56B3F /* Debug */, 687 | CD9AF19E185E206A00A56B3F /* Release */, 688 | ); 689 | defaultConfigurationIsVisible = 0; 690 | defaultConfigurationName = Release; 691 | }; 692 | CD9AF19F185E206A00A56B3F /* Build configuration list for PBXNativeTarget "FacebookImagePickerTests" */ = { 693 | isa = XCConfigurationList; 694 | buildConfigurations = ( 695 | CD9AF1A0185E206A00A56B3F /* Debug */, 696 | CD9AF1A1185E206A00A56B3F /* Release */, 697 | ); 698 | defaultConfigurationIsVisible = 0; 699 | defaultConfigurationName = Release; 700 | }; 701 | /* End XCConfigurationList section */ 702 | }; 703 | rootObject = CD9AF162185E206A00A56B3F /* Project object */; 704 | } 705 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import 11 | 12 | @implementation AppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | // Override point for customization after application launch. 17 | return [[FBSDKApplicationDelegate sharedInstance] application:application 18 | didFinishLaunchingWithOptions:launchOptions]; 19 | } 20 | 21 | - (void)applicationWillResignActive:(UIApplication *)application 22 | { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | - (void)applicationDidEnterBackground:(UIApplication *)application 28 | { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application 34 | { 35 | // 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. 36 | } 37 | 38 | - (void)applicationDidBecomeActive:(UIApplication *)application 39 | { 40 | // 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. 41 | } 42 | 43 | - (void)applicationWillTerminate:(UIApplication *)application 44 | { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | - (BOOL)application:(UIApplication *)application 49 | openURL:(NSURL *)url 50 | sourceApplication:(NSString *)sourceApplication 51 | annotation:(id)annotation { 52 | 53 | // Call FBAppCall's handleOpenURL:sourceApplication to handle Facebook app responses 54 | BOOL wasHandled = [[FBSDKApplicationDelegate sharedInstance] application:application 55 | openURL:url 56 | sourceApplication:sourceApplication 57 | annotation:annotation]; 58 | // You can add your app-specific url handling code here if needed 59 | 60 | return wasHandled; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/FacebookImagePicker-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | co.oceanlabs.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleURLSchemes 27 | 28 | fb189888614547873 29 | 30 | 31 | 32 | CFBundleVersion 33 | 1.0 34 | FacebookAppID 35 | 189888614547873 36 | FacebookDisplayName 37 | Image Picker 38 | LSApplicationQueriesSchemes 39 | 40 | fbauth2 41 | fbapi 42 | fb-messenger-api 43 | fbshareextension 44 | 45 | LSRequiresIPhoneOS 46 | 47 | NSAppTransportSecurity 48 | 49 | NSExceptionDomains 50 | 51 | akamaihd.net 52 | 53 | NSExceptionRequiresForwardSecrecy 54 | 55 | NSIncludesSubdomains 56 | 57 | 58 | facebook.com 59 | 60 | NSExceptionRequiresForwardSecrecy 61 | 62 | NSIncludesSubdomains 63 | 64 | 65 | fbcdn.net 66 | 67 | NSExceptionRequiresForwardSecrecy 68 | 69 | NSIncludesSubdomains 70 | 71 | 72 | 73 | 74 | UILaunchStoryboardName 75 | Main 76 | UIMainStoryboardFile 77 | Main 78 | UIRequiredDeviceCapabilities 79 | 80 | armv7 81 | 82 | UISupportedInterfaceOrientations 83 | 84 | UIInterfaceOrientationPortrait 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/FacebookImagePicker-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "OLFacebookAlbumRequest.h" 11 | #import "OLFacebookPhotosForAlbumRequest.h" 12 | #import "OLFacebookAlbum.h" 13 | #import "OLFacebookImage.h" 14 | #import "OLFacebookImagePickerController.h" 15 | #import 16 | #import 17 | 18 | @interface ViewController () 19 | @property (nonatomic, strong) OLFacebookAlbumRequest *albumRequest; 20 | @property (nonatomic, strong) NSArray *selected; 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | FBSDKLoginButton *loginButton = [[FBSDKLoginButton alloc] init]; 29 | loginButton.readPermissions = @[@"public_profile", @"user_photos"]; 30 | CGRect f = loginButton.frame; 31 | f.origin.x = (self.view.frame.size.width - f.size.width) / 2; 32 | f.origin.y = (self.view.frame.size.height - f.size.height) / 2; 33 | loginButton.frame = f; 34 | [self.view addSubview:loginButton]; 35 | } 36 | 37 | - (IBAction)onButtonFacebookImagePickerClicked:(id)sender { 38 | OLFacebookImagePickerController *picker = [[OLFacebookImagePickerController alloc] init]; 39 | picker.selected = self.selected; 40 | picker.delegate = self; 41 | [self presentViewController:picker animated:YES completion:nil]; 42 | } 43 | 44 | #pragma mark - OLFacebookImagePickerControllerDelegate methods 45 | 46 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFailWithError:(NSError *)error { 47 | [self dismissViewControllerAnimated:YES completion:^() { 48 | [[[UIAlertView alloc] initWithTitle:@"Oops" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; 49 | }]; 50 | } 51 | 52 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFinishPickingImages:(NSArray/**/ *)images { 53 | [self dismissViewControllerAnimated:YES completion:nil]; 54 | self.selected = images; 55 | NSLog(@"User did pick %lu images", (unsigned long) images.count); 56 | } 57 | 58 | - (void)facebookImagePickerDidCancelPickingImages:(OLFacebookImagePickerController *)imagePicker { 59 | [self dismissViewControllerAnimated:YES completion:nil]; 60 | NSLog(@"User cancelled facebook image picking"); 61 | } 62 | 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePicker/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePickerTests/FacebookImagePickerTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | co.oceanlabs.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePickerTests/FacebookImagePickerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FacebookImagePickerTests.m 3 | // FacebookImagePickerTests 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FacebookImagePickerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FacebookImagePickerTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /FacebookImagePicker/FacebookImagePickerTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLAlbumViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLAlbumViewController.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLAlbumViewController; 12 | @class OLFacebookImage; 13 | 14 | @protocol OLAlbumViewControllerDelegate 15 | - (void)albumViewControllerDoneClicked:(OLAlbumViewController *)albumController; 16 | - (void)albumViewController:(OLAlbumViewController *)albumController didFailWithError:(NSError *)error; 17 | @optional 18 | - (void)albumViewController:(OLAlbumViewController *)albumController didSelectImage:(OLFacebookImage *)image; 19 | - (BOOL)albumViewController:(OLAlbumViewController *)albumController shouldSelectImage:(OLFacebookImage *)image; 20 | @end 21 | 22 | @interface OLAlbumViewController : UIViewController 23 | @property (nonatomic, weak) id delegate; 24 | @property (nonatomic, strong) NSArray/**/ *selected; 25 | @property (nonatomic, assign) BOOL shouldDisplayLogoutButton; 26 | @end 27 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLAlbumViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLAlbumViewController.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLAlbumViewController.h" 10 | #import "OLFacebookAlbumRequest.h" 11 | #import "OLFacebookAlbum.h" 12 | #import "OLPhotoViewController.h" 13 | #import "UIImageView+FacebookFadeIn.h" 14 | #import 15 | #import 16 | #import 17 | 18 | static const NSUInteger kAlbumPreviewImageSize = 78; 19 | 20 | @interface OLAlbumCell : UITableViewCell 21 | @property (nonatomic, strong) OLFacebookAlbum *album; 22 | @end 23 | 24 | @implementation OLAlbumCell 25 | 26 | - (void)setAlbum:(OLFacebookAlbum *)album { 27 | static UIImage *placeholderImage = nil; 28 | if (!placeholderImage) { 29 | if ([UIImage respondsToSelector:@selector(imageNamed:inBundle:compatibleWithTraitCollection:)]) 30 | { 31 | placeholderImage = [UIImage imageNamed:@"album_placeholder" inBundle:[NSBundle bundleForClass:[OLAlbumViewController class]] compatibleWithTraitCollection:nil]; 32 | } 33 | else 34 | { 35 | placeholderImage = [UIImage imageNamed:@"album_placeholder"]; 36 | } 37 | } 38 | 39 | __weak OLAlbumCell *welf = self; 40 | [self.imageView setAndFadeInFacebookImageWithURL:album.coverPhotoURL placeholder:placeholderImage completionHandler:^{ 41 | if (!welf.imageView.superview){ 42 | [welf addSubview:welf.imageView]; 43 | } 44 | }]; 45 | self.imageView.clipsToBounds = YES; 46 | self.textLabel.text = album.name; 47 | self.detailTextLabel.text = [NSString stringWithFormat:@"%lu", (unsigned long)album.photoCount]; 48 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 49 | } 50 | 51 | - (void)layoutSubviews { 52 | [super layoutSubviews]; 53 | self.imageView.bounds = CGRectMake(0, 0, kAlbumPreviewImageSize, kAlbumPreviewImageSize); 54 | self.imageView.frame = CGRectMake(15, (self.frame.size.height - kAlbumPreviewImageSize) / 2, kAlbumPreviewImageSize, kAlbumPreviewImageSize); 55 | self.imageView.contentMode = UIViewContentModeScaleAspectFill; 56 | 57 | CGRect tmpFrame = self.textLabel.frame; 58 | tmpFrame.origin.x = CGRectGetMaxX(self.imageView.frame) + 15; 59 | self.textLabel.frame = tmpFrame; 60 | 61 | tmpFrame = self.detailTextLabel.frame; 62 | tmpFrame.origin.x = CGRectGetMaxX(self.imageView.frame) + 15; 63 | self.detailTextLabel.frame = tmpFrame; 64 | } 65 | 66 | @end 67 | 68 | @interface OLAlbumViewController () 69 | @property (nonatomic, strong) OLFacebookAlbumRequest *albumRequestForNextPage; 70 | @property (nonatomic, strong) OLFacebookAlbumRequest *inProgressRequest; 71 | @property (nonatomic, strong) NSMutableArray *albums; 72 | @property (nonatomic, weak) IBOutlet UIActivityIndicatorView *loadingIndicator; 73 | @property (nonatomic, weak) IBOutlet UITableView *tableView; 74 | @property (nonatomic, strong) UIView *loadingFooter; 75 | @property (nonatomic, strong) OLPhotoViewController *photoViewController; 76 | @property (nonatomic, strong) NSError *getAlbumError; 77 | 78 | @end 79 | 80 | @implementation OLAlbumViewController 81 | 82 | - (id)init { 83 | NSBundle *currentBundle = [NSBundle bundleForClass:[OLAlbumViewController class]]; 84 | if (self = [self initWithNibName:NSStringFromClass([OLAlbumViewController class]) bundle:currentBundle]) { 85 | self.title = @"Photos"; 86 | self.albums = [[NSMutableArray alloc] init]; 87 | _shouldDisplayLogoutButton = YES; 88 | } 89 | return self; 90 | } 91 | 92 | - (void)viewDidLoad { 93 | [super viewDidLoad]; 94 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 95 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(onButtonDoneClicked)]; 96 | 97 | if (self.shouldDisplayLogoutButton) { 98 | [self addLogoutButtonAnimated:NO]; 99 | } 100 | 101 | self.albumRequestForNextPage = [[OLFacebookAlbumRequest alloc] init]; 102 | [self loadNextAlbumPage]; 103 | 104 | UIView *loadingFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; 105 | UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 106 | activityIndicator.frame = CGRectMake((320 - activityIndicator.frame.size.width) / 2, (44 - activityIndicator.frame.size.height) / 2, activityIndicator.frame.size.width, activityIndicator.frame.size.height); 107 | [activityIndicator startAnimating]; 108 | [loadingFooter addSubview:activityIndicator]; 109 | self.loadingFooter = loadingFooter; 110 | } 111 | 112 | - (void)viewDidAppear:(BOOL)animated { 113 | [super viewDidAppear:animated]; 114 | if (self.getAlbumError) { 115 | self.loadingIndicator.hidden = YES; 116 | NSError *error = self.getAlbumError; 117 | self.getAlbumError = nil; 118 | [self.delegate albumViewController:self didFailWithError:error]; 119 | 120 | } 121 | } 122 | 123 | - (void)setShouldDisplayLogoutButton:(BOOL)shouldDisplayLogoutButton 124 | { 125 | _shouldDisplayLogoutButton = shouldDisplayLogoutButton; 126 | 127 | if (shouldDisplayLogoutButton && (self.navigationItem.leftBarButtonItem == nil)) { 128 | [self addLogoutButtonAnimated:YES]; 129 | } 130 | else if (!shouldDisplayLogoutButton && (self.navigationItem.leftBarButtonItem != nil)) { 131 | [self.navigationItem setLeftBarButtonItem:nil animated:YES]; 132 | } 133 | } 134 | 135 | - (void)addLogoutButtonAnimated:(BOOL)animated 136 | { 137 | [self.navigationItem setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Logout" style:UIBarButtonItemStylePlain target:self action:@selector(onButtonLogoutClicked)] 138 | animated:animated]; 139 | } 140 | 141 | - (void)loadNextAlbumPage { 142 | self.inProgressRequest = self.albumRequestForNextPage; 143 | self.albumRequestForNextPage = nil; 144 | [self.inProgressRequest getAlbums:^(NSArray/**/ *albums, NSError *error, OLFacebookAlbumRequest *nextPageRequest) { 145 | self.inProgressRequest = nil; 146 | self.loadingIndicator.hidden = YES; 147 | self.albumRequestForNextPage = nextPageRequest; 148 | 149 | if (error) { 150 | if (self.parentViewController.isBeingPresented) { 151 | self.loadingIndicator.hidden = NO; 152 | self.getAlbumError = error; // delay notification so that delegate can dismiss view controller safely if desired. 153 | } else { 154 | [self.delegate albumViewController:self didFailWithError:error]; 155 | } 156 | return; 157 | } 158 | 159 | NSMutableArray *paths = [[NSMutableArray alloc] init]; 160 | for (NSUInteger i = 0; i < albums.count; ++i) { 161 | [paths addObject:[NSIndexPath indexPathForRow:self.albums.count + i inSection:0]]; 162 | } 163 | 164 | [self.albums addObjectsFromArray:albums]; 165 | if (self.albums.count == albums.count) { 166 | // first insert request 167 | [self.tableView reloadData]; 168 | } else { 169 | [self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationFade]; 170 | } 171 | 172 | if (nextPageRequest) { 173 | self.tableView.tableFooterView = self.loadingFooter; 174 | } else { 175 | self.tableView.tableFooterView = nil; 176 | } 177 | 178 | }]; 179 | } 180 | 181 | - (void)updateSelectedFromPhotoViewController { 182 | if (self.photoViewController) { 183 | // we're coming back from a photo view so update the selected to reflect any changes the user made 184 | self.selected = self.photoViewController.selected; 185 | } 186 | } 187 | 188 | - (void)onButtonDoneClicked { 189 | [self.delegate albumViewControllerDoneClicked:self]; 190 | } 191 | 192 | - (void)onButtonLogoutClicked { 193 | [[FBSDKLoginManager new] logOut]; 194 | [self.delegate albumViewControllerDoneClicked:self]; 195 | } 196 | 197 | - (void)viewWillAppear:(BOOL)animated { 198 | [super viewWillAppear:animated]; 199 | [self updateSelectedFromPhotoViewController]; 200 | } 201 | 202 | #pragma mark - UITableViewDataSource methods 203 | 204 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 205 | return 1; 206 | } 207 | 208 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 209 | return self.albums.count; 210 | } 211 | 212 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 213 | static NSString *CellIdentifier = @"AlbumCell"; 214 | OLAlbumCell *cell = (OLAlbumCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 215 | if (cell == nil) { 216 | cell = [[OLAlbumCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 217 | } 218 | 219 | cell.album = [self.albums objectAtIndex:indexPath.row]; 220 | 221 | return cell; 222 | } 223 | 224 | #pragma mark - UITableViewDelegate methods 225 | 226 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 227 | return kAlbumPreviewImageSize + 12; 228 | } 229 | 230 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 231 | OLFacebookAlbum *album = [self.albums objectAtIndex:indexPath.row]; 232 | self.photoViewController = [[OLPhotoViewController alloc] initWithAlbum:album]; 233 | self.photoViewController.selected = self.selected; 234 | self.photoViewController.delegate = self; 235 | [self.navigationController pushViewController:self.photoViewController animated:YES]; 236 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 237 | } 238 | 239 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 240 | // this is actually the UICollectionView scrollView 241 | if (self.inProgressRequest == nil && scrollView.contentOffset.y >= self.tableView.contentSize.height - (self.tableView.frame.size.height + self.loadingFooter.frame.size.height)) { 242 | // we've reached the bottom, lets load the next page of albums. 243 | [self loadNextAlbumPage]; 244 | } 245 | } 246 | 247 | #pragma mark - OLPhotoViewControllerDelegate methods 248 | 249 | - (void)photoViewControllerDoneClicked:(OLPhotoViewController *)photoController { 250 | NSAssert(self.photoViewController != nil, @"oops"); 251 | [self updateSelectedFromPhotoViewController]; 252 | [self.delegate albumViewControllerDoneClicked:self]; 253 | } 254 | 255 | - (void)photoViewController:(OLPhotoViewController *)photoController didFailWithError:(NSError *)error { 256 | [self.delegate albumViewController:self didFailWithError:error]; 257 | } 258 | 259 | - (void)photoViewController:(OLPhotoViewController *)photoController didSelectImage:(OLFacebookImage *)image{ 260 | [self updateSelectedFromPhotoViewController]; 261 | if ([self.delegate respondsToSelector:@selector(albumViewController:didSelectImage:)]){ 262 | [self.delegate albumViewController:self didSelectImage:image]; 263 | } 264 | } 265 | 266 | - (void)photoViewController:(OLPhotoViewController *)photoController didDeSelectImage:(OLFacebookImage *)image{ 267 | [self updateSelectedFromPhotoViewController]; 268 | } 269 | 270 | - (BOOL)photoViewController:(OLPhotoViewController *)photoController shouldSelectImage:(OLFacebookImage *)image{ 271 | if ([self.delegate respondsToSelector:@selector(albumViewController:shouldSelectImage:)]){ 272 | return [self.delegate albumViewController:self shouldSelectImage:image]; 273 | } 274 | else{ 275 | return YES; 276 | } 277 | } 278 | 279 | @end 280 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLAlbumViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookAlbum.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookAlbum.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OLFacebookAlbum : NSObject 12 | @property (nonatomic, copy) NSString *name; 13 | @property (nonatomic, strong) NSURL *coverPhotoURL; 14 | @property (nonatomic, copy) NSString *albumId; 15 | @property (nonatomic, assign) NSUInteger photoCount; 16 | @end 17 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookAlbum.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookAlbum.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookAlbum.h" 10 | 11 | @implementation OLFacebookAlbum 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookAlbumRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookAlbumRequest.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLFacebookAlbumRequest; 12 | 13 | typedef void (^OLFacebookAlbumRequestHandler)(NSArray/**/ *albums, NSError *error, OLFacebookAlbumRequest *nextPageRequest); 14 | 15 | @interface OLFacebookAlbumRequest : NSObject 16 | - (void)cancel; 17 | - (void)getAlbums:(OLFacebookAlbumRequestHandler)handler; 18 | @end 19 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookAlbumRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookAlbumRequest.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookAlbumRequest.h" 10 | #import "OLFacebookImagePickerConstants.h" 11 | #import "OLFacebookAlbum.h" 12 | #import 13 | 14 | @interface OLFacebookAlbumRequest () 15 | @property (nonatomic, assign) BOOL cancelled; 16 | @property (nonatomic, strong) NSString *after; 17 | @end 18 | 19 | @implementation OLFacebookAlbumRequest 20 | 21 | + (void)handleFacebookError:(NSError *)error completionHandler:(OLFacebookAlbumRequestHandler)handler { 22 | NSString *message; 23 | if ([error.userInfo objectForKey:@"FBSDKErrorLocalizedDescriptionKey"]) { 24 | message = [error.userInfo objectForKey:@"FBSDKErrorLocalizedDescriptionKey"]; 25 | } else { 26 | message = @"Failed to access your Facebook photos. Please check your internet connectivity and try again."; 27 | } 28 | 29 | handler(nil, [NSError errorWithDomain:error.domain code:error.code userInfo:@{NSLocalizedDescriptionKey: message}], nil); 30 | } 31 | 32 | - (void)cancel { 33 | self.cancelled = YES; 34 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 35 | } 36 | 37 | - (void)getAlbums:(OLFacebookAlbumRequestHandler)handler { 38 | if ([FBSDKAccessToken currentAccessToken]) { 39 | // connection is open, perform the request 40 | [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 41 | NSString *graphPath = @"me/albums?limit=100&fields=id,name,count,cover_photo"; 42 | if (self.after) { 43 | graphPath = [graphPath stringByAppendingFormat:@"&after=%@", self.after]; 44 | } 45 | 46 | FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath parameters:nil]; 47 | [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { 48 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 49 | if (self.cancelled) { 50 | return; 51 | } 52 | if (error) { 53 | [OLFacebookAlbumRequest handleFacebookError:error completionHandler:handler]; 54 | return; 55 | } 56 | 57 | NSString *parsingErrorMessage = @"Failed to parse Facebook Response. Please check your internet connectivity and try again."; 58 | NSError *parsingError = [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerBadResponse userInfo:@{NSLocalizedDescriptionKey: parsingErrorMessage}]; 59 | id data = [result objectForKey:@"data"]; 60 | if (![data isKindOfClass:[NSArray class]]) { 61 | handler(nil, parsingError, nil); 62 | return; 63 | } 64 | 65 | NSMutableArray *albums = [[NSMutableArray alloc] init]; 66 | for (id album in data) { 67 | if (![album isKindOfClass:[NSDictionary class]]) { 68 | continue; 69 | } 70 | 71 | id albumId = [album objectForKey:@"id"]; 72 | id photoCount = [album objectForKey:@"count"]; 73 | id name = [album objectForKey:@"name"]; 74 | 75 | if (!([albumId isKindOfClass:[NSString class]] && [photoCount isKindOfClass:[NSNumber class]] 76 | && [name isKindOfClass:[NSString class]])) { 77 | continue; 78 | } 79 | 80 | OLFacebookAlbum *album = [[OLFacebookAlbum alloc] init]; 81 | album.albumId = albumId; 82 | album.photoCount = [photoCount unsignedIntegerValue]; 83 | album.name = name; 84 | album.coverPhotoURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=small&access_token=%@", album.albumId, [FBSDKAccessToken currentAccessToken].tokenString]]; 85 | [albums addObject:album]; 86 | } 87 | 88 | // get next page cursor 89 | OLFacebookAlbumRequest *nextPageRequest = nil; 90 | id paging = [result objectForKey:@"paging"]; 91 | if ([paging isKindOfClass:[NSDictionary class]]) { 92 | id cursors = [paging objectForKey:@"cursors"]; 93 | id next = [paging objectForKey:@"next"]; // next will be non nil if a next page exists 94 | if (next && [cursors isKindOfClass:[NSDictionary class]]) { 95 | id after = [cursors objectForKey:@"after"]; 96 | if ([after isKindOfClass:[NSString class]]) { 97 | nextPageRequest = [[OLFacebookAlbumRequest alloc] init]; 98 | nextPageRequest.after = after; 99 | } 100 | } 101 | } 102 | 103 | handler(albums, nil, nextPageRequest); 104 | }]; 105 | } 106 | else { 107 | NSString *message = @"No Facebook user authentication found."; 108 | handler(nil, [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerNoOpenSession userInfo:@{NSLocalizedDescriptionKey: message}], nil); 109 | } 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookImage.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OLFacebookImageURL : NSObject 12 | - (id)initWithURL:(NSURL *)url size:(CGSize)size; 13 | @property (nonatomic, readonly) NSURL *url; 14 | @property (nonatomic, readonly) CGSize imageSize; 15 | @end 16 | 17 | /** 18 | The OLFacebookImage class provides a simple model object representation of an Facebook album photo. 19 | */ 20 | @interface OLFacebookImage : NSObject 21 | 22 | /** 23 | Initialises a new OLFacebookImage object instance. 24 | 25 | @param thumbURL The URL to access the thumbnail image 26 | @param fullURL The URL to access the standard resolution image 27 | @param albumId The Facebook album id to which this photo belongs 28 | @param uid The Facebook photo unique id 29 | @return Returns an initialised OLFacebookImage instance 30 | */ 31 | - (id)initWithThumbURL:(NSURL *)thumbURL fullURL:(NSURL *)fullURL albumId:(NSString *)albumId uid:(NSString *)uid sourceImages:(NSArray/**/ *)sourceImages; 32 | 33 | - (NSURL *)bestURLForSize:(CGSize)size; 34 | 35 | /** 36 | The URL to access the thumb resolution image 37 | */ 38 | @property (nonatomic, readonly) NSURL *thumbURL; 39 | 40 | /** 41 | The URL to access the standard resolution image 42 | */ 43 | @property (nonatomic, readonly) NSURL *fullURL; 44 | 45 | /** 46 | The Facebook album id to which this photo belongs 47 | */ 48 | @property (nonatomic, readonly) NSString *albumId; 49 | 50 | /** 51 | The Facebook photo unique id 52 | */ 53 | @property (nonatomic, readonly) NSString *uid; 54 | 55 | @property (nonatomic, readonly) NSArray/**/ *sourceImages; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookImage.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 15/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImage.h" 10 | 11 | static NSString *const kKeyThumbURL = @"co.oceanlabs.FacebookImagePicker.kKeyThumbURL"; 12 | static NSString *const kKeyFullURL = @"co.oceanlabs.FacebookImagePicker.kKeyFullURL"; 13 | static NSString *const kKeyAlbumId = @"co.oceanlabs.FacebookImagePicker.kKeyAlbumId"; 14 | static NSString *const kKeyUid = @"co.oceanlabs.FacebookImagePicker.kKeyUid"; 15 | static NSString *const kKeySourceImages = @"co.oceanlabs.FacebookImagePicker.kKeySourceImages"; 16 | 17 | static NSString *const kKeyURL = @"co.oceanlabs.FacebookImagePicker.kKeyURL"; 18 | static NSString *const kKeyImageWidth = @"co.oceanlabs.FacebookImagePicker.kKeyImageWidth"; 19 | static NSString *const kKeyImageHeight = @"co.oceanlabs.FacebookImagePicker.kKeyImageHeight"; 20 | 21 | @implementation OLFacebookImageURL 22 | - (id)initWithURL:(NSURL *)url size:(CGSize)size { 23 | if (self = [super init]) { 24 | _url = url; 25 | _imageSize = size; 26 | } 27 | return self; 28 | } 29 | 30 | - (id)initWithCoder:(NSCoder *)aDecoder { 31 | if (self = [super init]) { 32 | _url = [aDecoder decodeObjectForKey:kKeyURL]; 33 | CGFloat w = [aDecoder decodeDoubleForKey:kKeyImageWidth]; 34 | CGFloat h = [aDecoder decodeDoubleForKey:kKeyImageHeight]; 35 | _imageSize = CGSizeMake(w, h); 36 | } 37 | 38 | return self; 39 | } 40 | 41 | - (void)encodeWithCoder:(NSCoder *)aCoder { 42 | [aCoder encodeObject:_url forKey:kKeyURL]; 43 | [aCoder encodeDouble:_imageSize.width forKey:kKeyImageWidth]; 44 | [aCoder encodeDouble:_imageSize.height forKey:kKeyImageHeight]; 45 | } 46 | 47 | - (id)copyWithZone:(NSZone *)zone { 48 | return [[OLFacebookImageURL allocWithZone:zone] initWithURL:_url size:_imageSize]; 49 | } 50 | 51 | @end 52 | 53 | @interface OLFacebookImage () 54 | 55 | @end 56 | 57 | @implementation OLFacebookImage 58 | - (id)initWithThumbURL:(NSURL *)thumbURL fullURL:(NSURL *)fullURL albumId:(NSString *)albumId uid:(NSString *)uid sourceImages:(NSArray/**/ *)sourceImages { 59 | if (self = [super init]) { 60 | _thumbURL = thumbURL; 61 | _fullURL = fullURL; 62 | _albumId = albumId; 63 | _uid = uid; 64 | _sourceImages = sourceImages; 65 | } 66 | 67 | return self; 68 | } 69 | 70 | - (NSURL *)bestURLForSize:(CGSize)size { 71 | if (self.sourceImages.count == 0) { 72 | return self.thumbURL; 73 | } 74 | 75 | OLFacebookImageURL *bestSeen = self.sourceImages[0]; 76 | for (OLFacebookImageURL *image in self.sourceImages) { 77 | if (image.imageSize.width >= size.width && image.imageSize.height >= size.height) { 78 | if (image.imageSize.width * image.imageSize.height < bestSeen.imageSize.width * bestSeen.imageSize.height) { 79 | bestSeen = image; 80 | } 81 | } 82 | } 83 | 84 | return bestSeen == nil ? self.thumbURL : bestSeen.url; 85 | } 86 | 87 | - (BOOL)isEqual:(id)object { 88 | if (![object isMemberOfClass:[OLFacebookImage class]]) { 89 | return NO; 90 | } 91 | 92 | return [self.uid isEqualToString:[object uid]]; 93 | } 94 | 95 | - (NSUInteger)hash { 96 | return self.uid.hash; 97 | } 98 | 99 | #pragma mark - NSCoding protocol methods 100 | 101 | - (void)encodeWithCoder:(NSCoder *)aCoder { 102 | [aCoder encodeObject:self.thumbURL forKey:kKeyThumbURL]; 103 | [aCoder encodeObject:self.fullURL forKey:kKeyFullURL]; 104 | [aCoder encodeObject:self.albumId forKey:kKeyAlbumId]; 105 | [aCoder encodeObject:self.uid forKey:kKeyUid]; 106 | [aCoder encodeObject:self.sourceImages forKey:kKeySourceImages]; 107 | } 108 | 109 | - (id)initWithCoder:(NSCoder *)aDecoder { 110 | if (self = [super init]) { 111 | _thumbURL = [aDecoder decodeObjectForKey:kKeyThumbURL]; 112 | _fullURL = [aDecoder decodeObjectForKey:kKeyFullURL]; 113 | _albumId = [aDecoder decodeObjectForKey:kKeyAlbumId]; 114 | _uid = [aDecoder decodeObjectForKey:kKeyUid]; 115 | _sourceImages = [aDecoder decodeObjectForKey:kKeySourceImages]; 116 | } 117 | 118 | return self; 119 | } 120 | 121 | #pragma mark - NSCopying protocol methods 122 | 123 | - (id)copyWithZone:(NSZone *)zone { 124 | OLFacebookImage *copy = [[OLFacebookImage allocWithZone:zone] initWithThumbURL:self.thumbURL fullURL:self.fullURL albumId:self.albumId uid:self.uid sourceImages:self.sourceImages]; 125 | return copy; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImageDownloadDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLImageDownloadDelegate.h 3 | // KitePrintSDK 4 | // 5 | // Created by Konstadinos Karayannis on 19/05/16. 6 | // Copyright © 2016 Kite.ly. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OLFacebookImageDownloadDelegate : NSObject 12 | 13 | @property (copy, nonatomic) void (^progressHandler)(NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite); 14 | @property (copy, nonatomic) void (^completionHandler)(NSData *data, NSURLResponse *response, NSError *error); 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImageDownloadDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLImageDownloadDelegate.m 3 | // KitePrintSDK 4 | // 5 | // Created by Konstadinos Karayannis on 19/05/16. 6 | // Copyright © 2016 Kite.ly. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImageDownloadDelegate.h" 10 | 11 | @implementation OLFacebookImageDownloadDelegate 12 | 13 | - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ 14 | if (self.progressHandler){ 15 | self.progressHandler(totalBytesWritten, totalBytesExpectedToWrite); 16 | } 17 | } 18 | 19 | - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ 20 | if (self.completionHandler){ 21 | self.completionHandler([NSData dataWithContentsOfURL:location], downloadTask.response, nil); 22 | } 23 | } 24 | 25 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ 26 | if (self.completionHandler){ 27 | self.completionHandler(nil, task.response, error); 28 | } 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImageDownloader.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLImageDownloader.h 3 | // KitePrintSDK 4 | // 5 | // Created by Konstadinos Karayannis on 17/05/16. 6 | // Copyright © 2016 Kite.ly. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OLFacebookImageDownloader : NSObject 12 | 13 | + (instancetype)sharedInstance; 14 | - (NSURLSessionDownloadTask *)downloadImageAtURL:(NSURL *)url withCompletionHandler:(void(^)(UIImage *image, NSError *error))handler; 15 | - (NSURLSessionDownloadTask *)downloadImageAtURL:(NSURL *)url progress:(void(^)(NSInteger progress, NSInteger total))progressHandler withCompletionHandler:(void(^)(UIImage *image, NSError *error))handler; 16 | - (BOOL)cachedDataExistForURL:(NSURL *)url; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImageDownloader.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLImageDownloader.m 3 | // KitePrintSDK 4 | // 5 | // Created by Konstadinos Karayannis on 17/05/16. 6 | // Copyright © 2016 Kite.ly. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImageDownloader.h" 10 | #import "OLFacebookImageDownloadDelegate.h" 11 | 12 | @interface OLFacebookImageDownloader () 13 | 14 | @end 15 | 16 | @implementation OLFacebookImageDownloader 17 | 18 | + (instancetype)sharedInstance { 19 | static dispatch_once_t once; 20 | static OLFacebookImageDownloader *sharedInstance; 21 | dispatch_once(&once, ^{ 22 | sharedInstance = [[self alloc] init]; 23 | }); 24 | return sharedInstance; 25 | } 26 | 27 | - (BOOL)cachedDataExistForURL:(NSURL *)url{ 28 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 29 | NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 30 | return cachedResponse.data != nil; 31 | } 32 | 33 | - (NSURLSessionDownloadTask *)downloadImageAtURL:(NSURL *)url withCompletionHandler:(void(^)(UIImage *image, NSError *error))handler{ 34 | return [self downloadImageAtURL:url progress:NULL withCompletionHandler:handler]; 35 | } 36 | 37 | - (NSURLSessionDownloadTask *)downloadImageAtURL:(NSURL *)url progress:(void(^)(NSInteger progress, NSInteger total))progressHandler withCompletionHandler:(void(^)(UIImage *image, NSError *error))handler{ 38 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 39 | OLFacebookImageDownloadDelegate *delegate = [[OLFacebookImageDownloadDelegate alloc] init]; 40 | delegate.progressHandler = progressHandler; 41 | 42 | 43 | NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 44 | if (cachedResponse.data){ 45 | handler([UIImage imageWithData:cachedResponse.data], nil); 46 | return nil; 47 | } 48 | 49 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 50 | configuration.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad; 51 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil]; 52 | 53 | delegate.completionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) { 54 | if (error){ 55 | dispatch_async(dispatch_get_main_queue(), ^{ 56 | handler(nil, error); 57 | }); 58 | } 59 | else if (data){ 60 | NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:nil storagePolicy:NSURLCacheStorageAllowed]; 61 | [configuration.URLCache storeCachedResponse:cachedResponse forRequest:request]; 62 | dispatch_async(dispatch_get_main_queue(), ^{ 63 | handler([UIImage imageWithData:data], nil); 64 | }); 65 | } 66 | }; 67 | 68 | NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; 69 | [downloadTask resume]; 70 | return downloadTask; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImagePickerCell.h 3 | // Ps 4 | // 5 | // Created by Deon Botha on 10/12/2013. 6 | // Copyright (c) 2013 dbotha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLFacebookImage; 12 | 13 | @interface OLFacebookImagePickerCell : UICollectionViewCell 14 | - (void)bind:(OLFacebookImage *)media; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ImagePickerCell.m 3 | // Ps 4 | // 5 | // Created by Deon Botha on 10/12/2013. 6 | // Copyright (c) 2013 dbotha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImagePickerCell.h" 10 | #import "UIImageView+FacebookFadeIn.h" 11 | #import "OLFacebookImage.h" 12 | 13 | #define kThumbnailLength 78.0f 14 | #define kThumbnailSize CGSizeMake(kThumbnailLength, kThumbnailLength) 15 | # 16 | 17 | @interface OLFacebookImagePickerCell () 18 | @property (nonatomic, copy) NSString *type; 19 | @property (nonatomic, copy) NSString *title; 20 | @property (nonatomic, assign) BOOL disabled; 21 | @property (nonatomic, strong) OLFacebookImage *facebookImage; 22 | @property (nonatomic, strong) UIImageView *imageView; 23 | @property (nonatomic, strong) UIImageView *checkImageView; 24 | @property (nonatomic, strong) UIView *selectedDisabledOverlayView; 25 | @end 26 | 27 | @implementation OLFacebookImagePickerCell 28 | 29 | static UIFont *titleFont = nil; 30 | 31 | static CGFloat titleHeight; 32 | static UIColor *titleColor; 33 | static UIImage *checkedIcon; 34 | static UIColor *selectedColor; 35 | static UIColor *disabledColor; 36 | 37 | + (void)initialize { 38 | titleFont = [UIFont systemFontOfSize:12]; 39 | titleHeight = 20.0f; 40 | titleColor = [UIColor whiteColor]; 41 | selectedColor = [UIColor colorWithWhite:1 alpha:0.3]; 42 | disabledColor = [UIColor colorWithWhite:1 alpha:0.9]; 43 | 44 | if ([UIImage respondsToSelector:@selector(imageNamed:inBundle:compatibleWithTraitCollection:)]) 45 | { 46 | checkedIcon = [UIImage imageNamed:@"CTAssetsPickerChecked" inBundle:[NSBundle bundleForClass:[OLFacebookImagePickerCell class]] compatibleWithTraitCollection:nil]; 47 | } 48 | else 49 | { 50 | checkedIcon = [UIImage imageNamed:@"CTAssetsPickerChecked"]; 51 | } 52 | } 53 | 54 | - (id)initWithFrame:(CGRect)frame { 55 | if (self = [super initWithFrame:frame]) { 56 | self.opaque = YES; 57 | self.backgroundColor = [UIColor colorWithRed:247 / 255.0 green:247 / 255.0 blue:247 / 255.0 alpha:1.0]; 58 | CGRect f = CGRectMake(0, 0, frame.size.width, frame.size.height); 59 | self.imageView = [[UIImageView alloc] initWithFrame:f]; 60 | self.imageView.contentMode = UIViewContentModeScaleAspectFill; 61 | self.imageView.clipsToBounds = YES; 62 | self.checkImageView = [[UIImageView alloc] initWithImage:checkedIcon]; 63 | self.selectedDisabledOverlayView = [[UIView alloc] initWithFrame:f]; 64 | self.selectedDisabledOverlayView.backgroundColor = selectedColor; 65 | self.selectedDisabledOverlayView.opaque = YES; 66 | self.selectedDisabledOverlayView.hidden = YES; 67 | 68 | self.checkImageView.frame = CGRectMake(f.size.width - checkedIcon.size.width, 0, self.checkImageView.frame.size.width, self.checkImageView.frame.size.height); 69 | self.checkImageView.hidden = YES; 70 | 71 | [self addSubview:self.imageView]; 72 | [self addSubview:self.selectedDisabledOverlayView]; 73 | [self addSubview:self.checkImageView]; 74 | } 75 | 76 | return self; 77 | } 78 | 79 | - (void)bind:(OLFacebookImage *)media { 80 | self.facebookImage = media; 81 | [self.imageView setAndFadeInFacebookImageWithURL:[media bestURLForSize:CGSizeMake(220, 220)] placeholder:nil completionHandler:NULL]; // opted for slightly larger than thumb url. Might be better for performance just to go with thumb. 82 | } 83 | 84 | - (void)setSelected:(BOOL)selected { 85 | [super setSelected:selected]; 86 | self.selectedDisabledOverlayView.hidden = !selected; 87 | self.checkImageView.hidden = !selected; 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookImagePickerConstants.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSString *const kOLErrorDomainFacebookImagePicker; 12 | extern const NSInteger kOLErrorCodeFacebookImagePickerBadResponse; 13 | extern const NSInteger kOLErrorCodeFacebookImagePickerNoOpenSession; 14 | 15 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerConstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookImagePickerConstants.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImagePickerConstants.h" 10 | 11 | NSString *const kOLErrorDomainFacebookImagePicker = @"co.oceanlabs.FacebookImagePicker.kOLErrorDomainFacebookImagePicker"; 12 | const NSInteger kOLErrorCodeFacebookImagePickerBadResponse = 99; 13 | const NSInteger kOLErrorCodeFacebookImagePickerNoOpenSession = 100; -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FacebookImagePickerController.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLFacebookImagePickerController; 12 | @class OLFacebookImage; 13 | 14 | @protocol OLFacebookImagePickerControllerDelegate 15 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFailWithError:(NSError *)error; 16 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFinishPickingImages:(NSArray/**/ *)images; 17 | - (void)facebookImagePickerDidCancelPickingImages:(OLFacebookImagePickerController *)imagePicker; 18 | @optional 19 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didSelectImage:(OLFacebookImage *)image; 20 | - (BOOL)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker shouldSelectImage:(OLFacebookImage *)image; 21 | @end 22 | 23 | 24 | /** 25 | The OLFacebookImagePickerController class provides a simple UI for a user to pick photos from their Facebook account. It 26 | provides an image picker interface that matches the iOS SDK's UIImagePickerController. It takes care of all 27 | authentication with Facebook as and when necessary. It will automatically renew auth tokens or prompt 28 | the user to re-authorize the app if needed. You need to have set up your application correctly to work with Facebook as per 29 | https://developers.facebook.com/docs/ios/getting-started 30 | */ 31 | @interface OLFacebookImagePickerController : UINavigationController 32 | 33 | /** 34 | The image picker’s delegate object. 35 | */ 36 | @property (nonatomic, weak) id delegate; 37 | 38 | /** 39 | Holds the currently user selected images in the picker UI. Setting this property will result in the corresponding images in the picker UI updating. 40 | */ 41 | @property (nonatomic, copy) NSArray/**/ *selected; 42 | 43 | @property (nonatomic, assign) BOOL shouldDisplayLogoutButton; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookImagePickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FacebookImagePickerController.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookImagePickerController.h" 10 | #import "OLAlbumViewController.h" 11 | #import 12 | //#import 13 | 14 | @interface OLFacebookImagePickerController () 15 | @property (nonatomic, strong) OLAlbumViewController *albumVC; 16 | @property (assign, nonatomic) BOOL haveSeenViewDidAppear; 17 | @end 18 | 19 | @implementation OLFacebookImagePickerController 20 | 21 | @dynamic delegate; 22 | 23 | - (id)init { 24 | UIViewController *vc = [[UIViewController alloc] init]; 25 | vc.view.backgroundColor = [UIColor whiteColor]; 26 | vc.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelButtonClicked)]; 27 | if (self = [super initWithRootViewController:vc]) { 28 | _shouldDisplayLogoutButton = YES; 29 | if ([FBSDKAccessToken currentAccessToken]){ 30 | [self showAlbumList]; 31 | } 32 | } 33 | 34 | return self; 35 | } 36 | 37 | - (void)cancelButtonClicked{ 38 | [self.delegate facebookImagePicker:self didFinishPickingImages:@[]]; 39 | } 40 | 41 | - (void)viewDidAppear:(BOOL)animated{ 42 | if (![FBSDKAccessToken currentAccessToken] && !self.haveSeenViewDidAppear){ 43 | self.haveSeenViewDidAppear = YES; 44 | 45 | //Workaround so that we dont include FBSDKLoginKit 46 | NSArray *permissions = @[@"public_profile", @"user_photos"]; 47 | Class FBSDKLoginManagerClass = NSClassFromString (@"FBSDKLoginManager"); 48 | id login = [[FBSDKLoginManagerClass alloc] init]; 49 | 50 | SEL aSelector = NSSelectorFromString(@"logInWithReadPermissions:fromViewController:handler:"); 51 | 52 | if([login respondsToSelector:aSelector]) { 53 | void (*imp)(id, SEL, id, id, id) = (void(*)(id,SEL,id,id, id))[login methodForSelector:aSelector]; 54 | if( imp ) imp(login, aSelector, permissions, self, ^(id result, NSError *error) { 55 | if (error) { 56 | [self.delegate facebookImagePicker:self didFailWithError:error]; 57 | } else if ([result isCancelled]) { 58 | [self.delegate facebookImagePicker:self didFinishPickingImages:@[]]; 59 | } else { 60 | [self showAlbumList]; 61 | } 62 | }); 63 | } 64 | } 65 | } 66 | 67 | - (void)showAlbumList{ 68 | OLAlbumViewController *albumController = [[OLAlbumViewController alloc] init]; 69 | self.albumVC = albumController; 70 | self.albumVC.delegate = self; 71 | self.albumVC.shouldDisplayLogoutButton = self.shouldDisplayLogoutButton; 72 | self.viewControllers = @[albumController]; 73 | } 74 | 75 | - (void)setSelected:(NSArray *)selected { 76 | self.albumVC.selected = selected; 77 | } 78 | 79 | - (NSArray *)selected { 80 | return self.albumVC.selected; 81 | } 82 | 83 | - (void)setShouldDisplayLogoutButton:(BOOL)shouldDisplayLogoutButton 84 | { 85 | _shouldDisplayLogoutButton = shouldDisplayLogoutButton; 86 | self.albumVC.shouldDisplayLogoutButton = self.shouldDisplayLogoutButton; 87 | } 88 | 89 | #pragma mark - OLAlbumViewControllerDelegate methods 90 | 91 | - (void)albumViewControllerDoneClicked:(OLAlbumViewController *)albumController { 92 | [self.delegate facebookImagePicker:self didFinishPickingImages:albumController.selected]; 93 | } 94 | 95 | - (void)albumViewController:(OLAlbumViewController *)albumController didFailWithError:(NSError *)error { 96 | [self.delegate facebookImagePicker:self didFailWithError:error]; 97 | } 98 | 99 | - (void)albumViewController:(OLAlbumViewController *)albumController didSelectImage:(OLFacebookImage *)image{ 100 | if ([self.delegate respondsToSelector:@selector(facebookImagePicker:didSelectImage:)]){ 101 | [self.delegate facebookImagePicker:self didSelectImage:image]; 102 | } 103 | } 104 | 105 | - (BOOL)albumViewController:(OLAlbumViewController *)albumController shouldSelectImage:(OLFacebookImage *)image{ 106 | if ([self.delegate respondsToSelector:@selector(facebookImagePicker:shouldSelectImage:)]){ 107 | return [self.delegate facebookImagePicker:self shouldSelectImage:image]; 108 | } 109 | else{ 110 | return YES; 111 | } 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookPhotosForAlbumRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookPhotosForAlbumRequest.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLFacebookAlbum; 12 | @class OLFacebookPhotosForAlbumRequest; 13 | 14 | typedef void (^OLFacebookPhotosForAlbumRequestHandler)(NSArray/**/ *photos, NSError *error, OLFacebookPhotosForAlbumRequest *nextPageRequest); 15 | 16 | @interface OLFacebookPhotosForAlbumRequest : NSObject 17 | 18 | - (id)initWithAlbum:(OLFacebookAlbum *)album; 19 | 20 | - (void)cancel; 21 | - (void)getPhotos:(OLFacebookPhotosForAlbumRequestHandler)handler; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLFacebookPhotosForAlbumRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLFacebookPhotosForAlbumRequest.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLFacebookPhotosForAlbumRequest.h" 10 | #import "OLFacebookAlbum.h" 11 | #import "OLFacebookImage.h" 12 | #import "OLFacebookImagePickerConstants.h" 13 | #import 14 | 15 | @interface OLFacebookPhotosForAlbumRequest () 16 | @property (nonatomic, assign) BOOL cancelled; 17 | @property (nonatomic, strong) OLFacebookAlbum *album; 18 | @property (nonatomic, strong) NSString *after; 19 | @end 20 | 21 | @implementation OLFacebookPhotosForAlbumRequest 22 | 23 | + (void)handleFacebookError:(NSError *)error completionHandler:(OLFacebookPhotosForAlbumRequestHandler)handler { 24 | NSString *message; 25 | if ([error.userInfo objectForKey:@"FBSDKErrorLocalizedDescriptionKey"]) { 26 | message = [error.userInfo objectForKey:@"FBSDKErrorLocalizedDescriptionKey"]; 27 | } else { 28 | message = @"Failed to access your Facebook photos. Please check your internet connectivity and try again."; 29 | } 30 | 31 | handler(nil, [NSError errorWithDomain:error.domain code:error.code userInfo:@{NSLocalizedDescriptionKey: message}], nil); 32 | } 33 | 34 | - (id)initWithAlbum:(OLFacebookAlbum *)album after:(NSString *)after { 35 | if (self = [super init]) { 36 | self.album = album; 37 | self.after = after; 38 | } 39 | 40 | return self; 41 | } 42 | 43 | - (id)initWithAlbum:(OLFacebookAlbum *)album { 44 | return [self initWithAlbum:album after:nil]; 45 | } 46 | 47 | - (void)cancel { 48 | self.cancelled = YES; 49 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 50 | } 51 | 52 | - (void)getPhotos:(OLFacebookPhotosForAlbumRequestHandler)handler { 53 | if ([FBSDKAccessToken currentAccessToken]) { 54 | // connection is open, perform the request 55 | [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 56 | NSString *graphPath = [NSString stringWithFormat:@"%@/photos?fields=picture,source,id,images&limit=100", self.album.albumId]; 57 | if (self.after) { 58 | graphPath = [graphPath stringByAppendingFormat:@"&after=%@", self.after]; 59 | } 60 | 61 | FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:graphPath parameters:nil]; 62 | [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { 63 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 64 | if (self.cancelled) { 65 | return; 66 | } 67 | if (error) { 68 | [OLFacebookPhotosForAlbumRequest handleFacebookError:error completionHandler:handler]; 69 | return; 70 | } 71 | 72 | NSString *parsingErrorMessage = @"Failed to parse Facebook Response. Please check your internet connectivity and try again."; 73 | NSError *parsingError = [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerBadResponse userInfo:@{NSLocalizedDescriptionKey: parsingErrorMessage}]; 74 | 75 | id data = [result objectForKey:@"data"]; 76 | if (![data isKindOfClass:[NSArray class]]) { 77 | handler(nil, parsingError, nil); 78 | return; 79 | } 80 | 81 | NSMutableArray *albumPhotos = [[NSMutableArray alloc] init]; 82 | for (id photo in data) { 83 | id thumbURLString = [photo objectForKey:@"picture"]; 84 | id fullURLString = [photo objectForKey:@"source"]; 85 | id uidString = [photo objectForKey:@"id"]; 86 | 87 | if (!([thumbURLString isKindOfClass:[NSString class]] && [fullURLString isKindOfClass:[NSString class]])) { 88 | continue; 89 | } 90 | 91 | NSMutableArray *sourceImages = [[NSMutableArray alloc] init]; 92 | if ([photo[@"images"] isKindOfClass:[NSArray class]]) { 93 | for (id image in photo[@"images"]) { 94 | id source = image[@"source"]; 95 | id width = image[@"width"]; 96 | id height = image[@"height"]; 97 | if ([source isKindOfClass:[NSString class]] && 98 | [width isKindOfClass:[NSNumber class]] && 99 | [height isKindOfClass:[NSNumber class]]) { 100 | [sourceImages addObject:[[OLFacebookImageURL alloc] initWithURL:[NSURL URLWithString:source] size:CGSizeMake([width doubleValue], [height doubleValue])]]; 101 | } 102 | } 103 | } 104 | 105 | OLFacebookImage *image = [[OLFacebookImage alloc] initWithThumbURL:[NSURL URLWithString:thumbURLString] fullURL:[NSURL URLWithString:fullURLString] albumId:self.album.albumId uid:uidString sourceImages:sourceImages]; 106 | [albumPhotos addObject:image]; 107 | } 108 | 109 | // get next page cursor 110 | OLFacebookPhotosForAlbumRequest *nextPageRequest = nil; 111 | id paging = [result objectForKey:@"paging"]; 112 | if ([paging isKindOfClass:[NSDictionary class]]) { 113 | id cursors = [paging objectForKey:@"cursors"]; 114 | id next = [paging objectForKey:@"next"]; // next will be non nil if a next page exists 115 | if (next && [cursors isKindOfClass:[NSDictionary class]]) { 116 | id after = [cursors objectForKey:@"after"]; 117 | if ([after isKindOfClass:[NSString class]]) { 118 | nextPageRequest = [[OLFacebookPhotosForAlbumRequest alloc] initWithAlbum:self.album after:after]; 119 | } 120 | } 121 | } 122 | 123 | handler(albumPhotos, nil, nextPageRequest); 124 | }]; 125 | } 126 | else { 127 | NSString *message = @"No Facebook user authentication found."; 128 | handler(nil, [NSError errorWithDomain:kOLErrorDomainFacebookImagePicker code:kOLErrorCodeFacebookImagePickerNoOpenSession userInfo:@{NSLocalizedDescriptionKey: message}], nil); 129 | } 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLPhotoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // OLPhotoViewController.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class OLPhotoViewController; 12 | @class OLFacebookAlbum; 13 | @class OLFacebookImage; 14 | 15 | @protocol OLPhotoViewControllerDelegate 16 | - (void)photoViewControllerDoneClicked:(OLPhotoViewController *)photoController; 17 | - (void)photoViewController:(OLPhotoViewController *)photoController didFailWithError:(NSError *)error; 18 | @optional 19 | - (void)photoViewController:(OLPhotoViewController *)photoController didSelectImage:(OLFacebookImage *)image; 20 | - (void)photoViewController:(OLPhotoViewController *)photoController didDeSelectImage:(OLFacebookImage *)image; 21 | - (BOOL)photoViewController:(OLPhotoViewController *)photoController shouldSelectImage:(OLFacebookImage *)image; 22 | @end 23 | 24 | @interface OLPhotoViewController : UIViewController 25 | 26 | - (id)initWithAlbum:(OLFacebookAlbum *)album; 27 | 28 | @property (nonatomic, weak) id delegate; 29 | @property (nonatomic, strong) NSArray/**/ *selected; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLPhotoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // OLPhotoViewController.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 16/12/2013. 6 | // Copyright (c) 2013 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "OLPhotoViewController.h" 10 | #import "OLFacebookAlbum.h" 11 | #import "OLFacebookImagePickerCell.h" 12 | #import "OLFacebookPhotosForAlbumRequest.h" 13 | #import "OLFacebookImage.h" 14 | #import "OLFacebookImagePickerController.h" 15 | 16 | #import 17 | 18 | static NSString *const kImagePickerCellReuseIdentifier = @"co.oceanlabs.facebookimagepicker.kImagePickerCellReuseIdentifier"; 19 | static NSString *const kSupplementaryViewFooterReuseIdentifier = @"co.oceanlabs.ps.kSupplementaryViewHeaderReuseIdentifier"; 20 | 21 | @interface SupplementaryView : UICollectionReusableView 22 | @end 23 | 24 | @interface OLPhotoViewController () 25 | @property (nonatomic, weak) IBOutlet UICollectionView *collectionView; 26 | @property (nonatomic, strong) OLFacebookAlbum *album; 27 | @property (nonatomic, strong) OLFacebookPhotosForAlbumRequest *nextPageRequest, *inProgressRequest; 28 | @property (nonatomic, weak) IBOutlet UIActivityIndicatorView *loadingIndicator; 29 | 30 | @property (nonatomic, strong) NSMutableArray/**/ *selectedImagesInFuturePages; // selected images that don't yet occur in collectionView.indexPathsForSelectedItems as the user needs to load more instagram pages first 31 | @property (nonatomic, strong) NSMutableArray *photos; 32 | @property (nonatomic, strong) NSArray *overflowPhotos; // We can only insert multiples of 4 images each request, overflow must be saved and inserted on a subsequent request. 33 | @end 34 | 35 | @implementation OLPhotoViewController 36 | 37 | - (id)initWithAlbum:(OLFacebookAlbum *)album { 38 | NSBundle *currentBundle = [NSBundle bundleForClass:[OLPhotoViewController class]]; 39 | if (self = [self initWithNibName:NSStringFromClass([OLPhotoViewController class]) bundle:currentBundle]) { 40 | self.album = album; 41 | self.title = album.name; 42 | self.photos = [[NSMutableArray alloc] init]; 43 | self.selectedImagesInFuturePages = [[NSMutableArray alloc] init]; 44 | self.overflowPhotos = @[]; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)viewDidLoad { 50 | [super viewDidLoad]; 51 | 52 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(onButtonDoneClicked)]; 53 | 54 | CGFloat itemSize = MIN([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width)/4.0 - 1.0; 55 | 56 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 57 | layout.itemSize = CGSizeMake(itemSize, itemSize); 58 | layout.sectionInset = UIEdgeInsetsMake(9.0, 0, 0, 0); 59 | layout.minimumInteritemSpacing = 1.0; 60 | layout.minimumLineSpacing = 1.0; 61 | layout.footerReferenceSize = CGSizeMake(0, 0); 62 | self.collectionView.collectionViewLayout = layout; 63 | self.collectionView.allowsMultipleSelection = YES; 64 | 65 | [self.collectionView registerClass:[OLFacebookImagePickerCell class] forCellWithReuseIdentifier:kImagePickerCellReuseIdentifier]; 66 | [self.collectionView registerClass:[SupplementaryView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:kSupplementaryViewFooterReuseIdentifier]; 67 | 68 | self.nextPageRequest = [[OLFacebookPhotosForAlbumRequest alloc] initWithAlbum:self.album]; 69 | [self loadNextPage]; 70 | } 71 | 72 | - (NSArray *)selected { 73 | NSMutableArray *selectedItems = [[NSMutableArray alloc] init]; 74 | NSArray *selectedPaths = self.collectionView.indexPathsForSelectedItems; 75 | for (NSIndexPath *path in selectedPaths) { 76 | OLFacebookImage *image = [self.photos objectAtIndex:path.item]; 77 | [selectedItems addObject:image]; 78 | } 79 | 80 | [selectedItems addObjectsFromArray:self.selectedImagesInFuturePages]; 81 | 82 | return selectedItems; 83 | } 84 | 85 | - (void)setSelected:(NSArray *)selected { 86 | // clear currently selected 87 | for (NSIndexPath *path in self.collectionView.indexPathsForSelectedItems) { 88 | [self.collectionView deselectItemAtIndexPath:path animated:NO]; 89 | } 90 | 91 | // select any items in the collection view as appropriate, any items that have yet to be downloaded (due to the user not scrolling far enough) 92 | // are stored for selecting later when we fetch future pages. 93 | NSMutableArray *selectedImagesInFuturePages = [[NSMutableArray alloc] init]; 94 | for (OLFacebookImage *image in selected) { 95 | NSUInteger itemIndex = [self.photos indexOfObject:image]; 96 | if (itemIndex == NSNotFound) { 97 | [selectedImagesInFuturePages addObject:image]; 98 | } else { 99 | [self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:itemIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone]; 100 | } 101 | } 102 | 103 | self.selectedImagesInFuturePages = selectedImagesInFuturePages; 104 | } 105 | 106 | - (void)loadNextPage { 107 | self.inProgressRequest = self.nextPageRequest; 108 | self.nextPageRequest = nil; 109 | [self.inProgressRequest getPhotos:^(NSArray *photos, NSError *error, OLFacebookPhotosForAlbumRequest *nextPageRequest) { 110 | self.inProgressRequest = nil; 111 | self.nextPageRequest = nextPageRequest; 112 | self.loadingIndicator.hidden = YES; 113 | 114 | if (error) { 115 | [self.delegate photoViewController:self didFailWithError:error]; 116 | return; 117 | } 118 | 119 | NSAssert(self.overflowPhotos.count < 4, @"oops"); 120 | NSUInteger photosStartCount = self.photos.count; 121 | [self.photos addObjectsFromArray:self.overflowPhotos]; 122 | if (nextPageRequest != nil) { 123 | // only insert multiple of 4 images so we fill complete rows 124 | NSInteger overflowCount = (self.photos.count + photos.count) % 4; 125 | [self.photos addObjectsFromArray:[photos subarrayWithRange:NSMakeRange(0, photos.count - overflowCount)]]; 126 | self.overflowPhotos = [photos subarrayWithRange:NSMakeRange(photos.count - overflowCount, overflowCount)]; 127 | } else { 128 | // we've exhausted all the users images so show the remainder 129 | [self.photos addObjectsFromArray:photos]; 130 | self.overflowPhotos = @[]; 131 | } 132 | 133 | // Insert new items 134 | NSMutableArray *addedItemPaths = [[NSMutableArray alloc] init]; 135 | for (NSUInteger itemIndex = photosStartCount; itemIndex < self.photos.count; ++itemIndex) { 136 | [addedItemPaths addObject:[NSIndexPath indexPathForItem:itemIndex inSection:0]]; 137 | } 138 | 139 | [self.collectionView insertItemsAtIndexPaths:addedItemPaths]; 140 | ((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).footerReferenceSize = CGSizeMake(0, nextPageRequest == nil ? 0 : 44); 141 | 142 | // If any of the items in the newly loaded page were previously selected then make them selected 143 | NSMutableArray *selectedItemsInThisPage = [[NSMutableArray alloc] init]; 144 | for (NSUInteger itemIndex = photosStartCount; itemIndex < self.photos.count; ++itemIndex) { 145 | OLFacebookImage *image = self.photos[itemIndex]; 146 | if ([self.selectedImagesInFuturePages indexOfObject:image] != NSNotFound) { 147 | [selectedItemsInThisPage addObject:image]; 148 | [self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:itemIndex inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone]; 149 | } 150 | } 151 | [self.selectedImagesInFuturePages removeObjectsInArray:selectedItemsInThisPage]; 152 | }]; 153 | 154 | } 155 | 156 | - (void)onButtonDoneClicked { 157 | [self.inProgressRequest cancel]; 158 | [self.delegate photoViewControllerDoneClicked:self]; 159 | } 160 | 161 | -(void) updateTitleWithSelectedIndexPaths:(NSArray *)indexPaths{ 162 | // Reset title to group name 163 | if (indexPaths.count == 0) 164 | { 165 | self.title = self.album.name; 166 | return; 167 | } 168 | 169 | NSString *format = (indexPaths.count > 1) ? NSLocalizedString(@"%ld Photos Selected", nil) : NSLocalizedString(@"%ld Photo Selected", nil); 170 | self.title = [NSString stringWithFormat:format, (unsigned long)indexPaths.count]; 171 | } 172 | 173 | #pragma mark - UICollectionViewDataSource methods 174 | 175 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 176 | return self.photos.count; 177 | } 178 | 179 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 180 | OLFacebookImagePickerCell *cell = (OLFacebookImagePickerCell *) [collectionView dequeueReusableCellWithReuseIdentifier:kImagePickerCellReuseIdentifier forIndexPath:indexPath]; 181 | OLFacebookImage *image = [self.photos objectAtIndex:indexPath.item]; 182 | [cell bind:image]; 183 | return cell; 184 | } 185 | 186 | - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 187 | SupplementaryView *v = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:kSupplementaryViewFooterReuseIdentifier forIndexPath:indexPath]; 188 | return v; 189 | } 190 | 191 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 192 | // this is actually the UICollectionView scrollView 193 | if (self.inProgressRequest == nil && scrollView.contentOffset.y >= self.collectionView.contentSize.height - self.collectionView.frame.size.height) { 194 | // we've reached the bottom, lets load the next page of facebook images. 195 | [self loadNextPage]; 196 | } 197 | } 198 | 199 | -(void) collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{ 200 | [self updateTitleWithSelectedIndexPaths:collectionView.indexPathsForSelectedItems]; 201 | if ([self.delegate respondsToSelector:@selector(photoViewController:didDeSelectImage:)]){ 202 | [self.delegate photoViewController:self didDeSelectImage:[self.photos objectAtIndex:indexPath.item]]; 203 | } 204 | } 205 | 206 | -(void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ 207 | [self updateTitleWithSelectedIndexPaths:collectionView.indexPathsForSelectedItems]; 208 | if ([self.delegate respondsToSelector:@selector(photoViewController:didSelectImage:)]){ 209 | [self.delegate photoViewController:self didSelectImage:[self.photos objectAtIndex:indexPath.item]]; 210 | } 211 | } 212 | 213 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{ 214 | if ([self.delegate respondsToSelector:@selector(photoViewController:shouldSelectImage:)]){ 215 | return [self.delegate photoViewController:self shouldSelectImage:[self.photos objectAtIndex:indexPath.item]]; 216 | } 217 | else{ 218 | return YES; 219 | } 220 | } 221 | 222 | @end 223 | 224 | #pragma mark - SupplementaryView 225 | 226 | @implementation SupplementaryView 227 | 228 | - (id)initWithFrame:(CGRect)frame { 229 | if (self = [super initWithFrame:frame]) { 230 | UIActivityIndicatorView *ai = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 231 | ai.frame = CGRectMake((frame.size.width - ai.frame.size.width) / 2, (frame.size.height - ai.frame.size.height) / 2, ai.frame.size.width, ai.frame.size.height); 232 | ai.color = [UIColor grayColor]; 233 | [ai startAnimating]; 234 | [self addSubview:ai]; 235 | } 236 | 237 | return self; 238 | } 239 | 240 | @end 241 | -------------------------------------------------------------------------------- /FacebookImagePicker/OLPhotoViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /FacebookImagePicker/Podfile: -------------------------------------------------------------------------------- 1 | pod 'FBSDKCoreKit', '~> 4.8.0' 2 | pod 'FBSDKLoginKit', '~> 4.8.0' 3 | -------------------------------------------------------------------------------- /FacebookImagePicker/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Bolts (1.5.1): 3 | - Bolts/AppLinks (= 1.5.1) 4 | - Bolts/Tasks (= 1.5.1) 5 | - Bolts/AppLinks (1.5.1): 6 | - Bolts/Tasks 7 | - Bolts/Tasks (1.5.1) 8 | - FBSDKCoreKit (4.8.0): 9 | - Bolts (~> 1.1) 10 | - FBSDKCoreKit/arc (= 4.8.0) 11 | - FBSDKCoreKit/no-arc (= 4.8.0) 12 | - FBSDKCoreKit/arc (4.8.0): 13 | - Bolts (~> 1.1) 14 | - FBSDKCoreKit/no-arc (4.8.0): 15 | - Bolts (~> 1.1) 16 | - FBSDKCoreKit/arc 17 | - FBSDKLoginKit (4.8.0): 18 | - FBSDKCoreKit 19 | 20 | DEPENDENCIES: 21 | - FBSDKCoreKit (~> 4.8.0) 22 | - FBSDKLoginKit (~> 4.8.0) 23 | 24 | SPEC CHECKSUMS: 25 | Bolts: a12663244b1d3351c738882e71902fc74db54f64 26 | FBSDKCoreKit: 66a935d17b6e00b6b64e604f2eb9b72c9ab7deb8 27 | FBSDKLoginKit: d893fcbb98d854496925e9ff73c67b896982d3c4 28 | 29 | COCOAPODS: 0.39.0 30 | -------------------------------------------------------------------------------- /FacebookImagePicker/UIImageView+FacebookFadeIn.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+FacebookFadeIn.h 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 23/03/2015. 6 | // Copyright (c) 2015 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImageView (FacebookFadeIn) 12 | - (void)setAndFadeInFacebookImageWithURL:(NSURL *)url; 13 | - (void)setAndFadeInFacebookImageWithURL:(NSURL *)url placeholder:(UIImage *)placeholder; 14 | -(void)setAndFadeInFacebookImageWithURL:(NSURL *)url placeholder:(UIImage *)placeholder completionHandler:(void(^)())handler; 15 | @end 16 | -------------------------------------------------------------------------------- /FacebookImagePicker/UIImageView+FacebookFadeIn.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+FacebookFadeIn.m 3 | // FacebookImagePicker 4 | // 5 | // Created by Deon Botha on 23/03/2015. 6 | // Copyright (c) 2015 Deon Botha. All rights reserved. 7 | // 8 | 9 | #import "UIImageView+FacebookFadeIn.h" 10 | #import "OLFacebookImageDownloader.h" 11 | #import "objc/runtime.h" 12 | 13 | static char tasksKey; 14 | 15 | @implementation UIImageView (FacebookFadeIn) 16 | - (void)setAndFadeInFacebookImageWithURL:(NSURL *)url { 17 | [self setAndFadeInFacebookImageWithURL:url placeholder:nil completionHandler:NULL]; 18 | } 19 | 20 | -(void)setAndFadeInFacebookImageWithURL:(NSURL *)url placeholder:(UIImage *)placeholder{ 21 | [self setAndFadeInFacebookImageWithURL:url placeholder:placeholder completionHandler:NULL]; 22 | } 23 | 24 | -(void)setAndFadeInFacebookImageWithURL:(NSURL *)url placeholder:(UIImage *)placeholder completionHandler:(void(^)())handler{ 25 | for (id key in self.tasks.allKeys){ 26 | if (![key isEqual:url]){ 27 | [self.tasks[key] cancel]; 28 | } 29 | } 30 | 31 | self.alpha = 0; 32 | NSURLSessionTask *task = [[OLFacebookImageDownloader sharedInstance] downloadImageAtURL:url withCompletionHandler:^(UIImage *image, NSError *error){ 33 | if ([self.tasks[url] state] == NSURLSessionTaskStateCanceling){ 34 | [self.tasks removeObjectForKey:url]; 35 | return; 36 | } 37 | [self.tasks removeObjectForKey:url]; 38 | self.image = image; 39 | [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 40 | self.alpha = 1; 41 | }completion:^(BOOL finished){ 42 | if (handler){ 43 | handler(); 44 | } 45 | }]; 46 | 47 | }]; 48 | self.tasks[url] = task; 49 | } 50 | 51 | - (NSMutableDictionary *)tasks{ 52 | NSMutableDictionary *tasks = objc_getAssociatedObject(self, &tasksKey); 53 | if (tasks){ 54 | return tasks; 55 | } 56 | tasks = [[NSMutableDictionary alloc] init]; 57 | objc_setAssociatedObject(self, &tasksKey, tasks, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 58 | return tasks; 59 | } 60 | 61 | @end 62 | 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2010-2015 Kite Tech Ltd. https://www.kite.ly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Facebook Image Picker 2 | 3 | A Facebook image picker providing a simple UI for a user to pick photos from a users Facebook account. It provides an image picker interface that matches the iOS SDK's UIImagePickerController. 4 | 5 | It takes care of all authentication with Facebook as and when necessary. It will automatically renew auth tokens or prompt the user to re-authorize the app if needed. 6 | 7 | ## Video Preview 8 | 9 | [![Preview](https://github.com/OceanLabs/FacebookImagePicker-iOS/raw/master/preview.png)](https://vimeo.com/135687088) 10 | 11 | ## Requirements 12 | 13 | * Xcode 6 and iOS SDK 7 14 | * iOS 7.0+ target deployment 15 | * FBSDKCoreKit, FBSDKLoginKit (>= 4.0) 16 | 17 | ## Installation 18 | ### CocoaPods 19 | 20 | [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like the Kite Print SDK in your projects. If you're using it just add the following to your Podfile: 21 | 22 | ```ruby 23 | pod "FacebookImagePicker" 24 | ``` 25 | 26 | ## Usage 27 | 28 | You need to have set up your application correctly to work with Facebook as per https://developers.facebook.com/docs/ios/getting-started 29 | 30 | To launch the Facebook Image Picker: 31 | 32 | ```objective-c 33 | #import 34 | 35 | OLFacebookImagePickerController *picker = [[OLFacebookImagePickerController alloc] init]; 36 | picker.delegate = self; 37 | [self presentViewController:picker animated:YES completion:nil]; 38 | ``` 39 | 40 | Implement the `OLFacebookImagePickerControllerDelegate` protocol: 41 | 42 | ```objective-c 43 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFinishPickingImages:(NSArray/**/ *)images { 44 | [self dismissViewControllerAnimated:YES completion:nil]; 45 | // do something with the OLFacebookImage image objects 46 | } 47 | 48 | - (void)facebookImagePickerDidCancelPickingImages:(OLFacebookImagePickerController *)imagePicker { 49 | [self dismissViewControllerAnimated:YES completion:nil]; 50 | } 51 | 52 | - (void)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker didFailWithError:(NSError *)error { 53 | // do something with the error such as display an alert to the user 54 | } 55 | 56 | ``` 57 | 58 | ## App Transport Security 59 | Xcode 7 and iOS 9 includes some new security features. In order to connect to Facebook you will need to add some more exceptions to your project's info plist file (in addition to the ones that your project might require). 60 | We need to add forward secrecy exceptions for Facebooks's CDNs. The following is what you need to copy your app's info plist, which includes anything that is needed by Kite as well: 61 | ``` 62 | NSAppTransportSecurity 63 | 64 | NSExceptionDomains 65 | 66 | akamaihd.net 67 | 68 | NSExceptionRequiresForwardSecrecy 69 | 70 | NSIncludesSubdomains 71 | 72 | 73 | facebook.com 74 | 75 | NSExceptionRequiresForwardSecrecy 76 | 77 | NSIncludesSubdomains 78 | 79 | 80 | fbcdn.net 81 | 82 | NSExceptionRequiresForwardSecrecy 83 | 84 | NSIncludesSubdomains 85 | 86 | 87 | 88 | 89 | ``` 90 | 91 | **Set maximum number of selections** 92 | 93 | Limit the number of assets to be picked. 94 | ```` objective-c 95 | - (BOOL)facebookImagePicker:(OLFacebookImagePickerController *)imagePicker shouldSelectImage:(OLFacebookImage *)image 96 | { 97 | // Allow 10 assets to be picked 98 | return (imagePicker.selected.count < 10); 99 | } 100 | ```` 101 | 102 | 103 | ### Sample Apps 104 | The project is bundled with a Sample App to highlight the libraries usage. Alternatively you can see the library in action in the following iOS apps: 105 | 106 | * [HuggleUp](https://itunes.apple.com/gb/app/huggleup-photo-printing-personalised/id977579943?mt=8) 107 | * Get in touch to list your app here 108 | 109 | ## License 110 | This project is available under the MIT license. See the [LICENSE](LICENSE) file for more info. 111 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OceanLabs/FacebookImagePicker-iOS/9fbcb9b8228c611156cedcf2baa387db5a078cf3/preview.png --------------------------------------------------------------------------------