├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── FDTake.podspec ├── LICENSE ├── Package.swift ├── README.md ├── Resources ├── FDTakeResources.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Resources │ ├── Info.plist │ ├── ar.lproj │ └── Localizable.strings │ ├── da.lproj │ └── Localizable.strings │ ├── de.lproj │ └── Localizable.strings │ ├── el.lproj │ └── Localizable.strings │ ├── en.lproj │ └── Localizable.strings │ ├── es.lproj │ └── Localizable.strings │ ├── fr.lproj │ └── Localizable.strings │ ├── he.lproj │ └── Localizable.strings │ ├── hu.lproj │ └── Localizable.strings │ ├── it.lproj │ └── Localizable.strings │ ├── nb.lproj │ └── Localizable.strings │ ├── nl.lproj │ └── Localizable.strings │ ├── pl.lproj │ └── Localizable.strings │ ├── pt-PT.lproj │ └── Localizable.strings │ ├── ru.lproj │ └── Localizable.strings │ ├── sv.lproj │ └── Localizable.strings │ ├── tr.lproj │ └── Localizable.strings │ ├── zh-Hans.lproj │ └── Localizable.strings │ └── zh-Hant.lproj │ └── Localizable.strings ├── Scripts └── travis-ci.sh ├── Sources └── FDTake │ ├── Bundle+Helpers.swift │ ├── FDTakeController.swift │ └── FDTakeControllerLocalizableStrings.swift ├── Tests ├── CheckCocoaPodsQualityIndexes.rb └── FDTakeTests │ └── FDTakeTests.swift └── iOS Example ├── Sources ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── Main.storyboard └── ViewController.swift ├── iOS Example.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── iOS Example.xcscheme └── iOS Example.xcworkspace ├── contents.xcworkspacedata └── xcshareddata └── IDEWorkspaceChecks.plist /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [fulldecent] 4 | custom: ["https://www.paypal.me/fulldecent", "https://amazon.com/hz/wishlist/ls/EE78A23EEGQB"] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | # OS X 6 | .DS_Store 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xcuserstate 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | .build/ 42 | .swiftpm 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | FDTake.framework.zip 71 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode11.2 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | - RUN_TESTS="YES" 8 | - BUILD_EXAMPLE="YES" 9 | - POD_LINT="NO" 10 | - POD_QUALITY_CHECK="NO" 11 | matrix: 12 | - DESTINATION="OS=13.2.2,name=iPhone 8 Plus" 13 | script: 14 | - Scripts/travis-ci.sh -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | `FDTake` adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | --- 6 | 7 | ## [Master](https://github.com/fulldecent/FDBarGuage/compare/3.0.0...master) 8 | 9 | #### Updated 10 | 11 | - Now targeting iOS 10.3.3 or later 12 | 13 | #### KNOWN ISSUES 14 | 15 | - Localization is broken, discuss at https://github.com/fulldecent/FDTake/pull/99 16 | 17 | --- 18 | 19 | ## [3.0.0](https://github.com/fulldecent/FDBarGuage/compare/3.0.0) 20 | 21 | #### Updated 22 | 23 | - Switched to target Swift 5. 24 | 25 | --- 26 | 27 | ## [2.0.3](https://github.com/fulldecent/FDBarGuage/compare/2.0.3) 28 | 29 | #### Fixed 30 | 31 | - Fixed resources including the Podspec 32 | - Added by [JoelGerboreLaser](https://github.com/JoelGerboreLaser) in regards to issue 33 | [#115](https://github.com/fulldecent/FDTake/pull/115). 34 | 35 | --- 36 | 37 | ## [2.0.2](https://github.com/fulldecent/FDBarGuage/compare/2.0.2) 38 | 39 | #### Updated 40 | 41 | - Updated to Swift 4 visibility inference 42 | 43 | --- 44 | 45 | ## [2.0.1](https://github.com/fulldecent/FDBarGuage/compare/2.0.1) 46 | #### Updated 47 | 48 | - Refactored to remove deprecated popover controller 49 | - Updated to Xcode recommended settings 50 | - Updated application strings to follow Apple HIG 51 | 52 | ------ 53 | 54 | ## [2.0.0](https://github.com/fulldecent/FDBarGuage/compare/2.0.0) 55 | 56 | #### Updated 57 | 58 | - Updated for Swift 4 59 | 60 | ------ 61 | 62 | ## [1.0.0](https://github.com/fulldecent/FDBarGuage/releases/tag/1.0.0) 63 | 64 | Released on 2016-09-28. 65 | 66 | Release 1.0 because this is already used in a lot of places. It's time. 67 | 68 | --- 69 | 70 | ## [0.4.2](https://github.com/fulldecent/FDBarGuage/releases/tag/0.4.2) 71 | Released on 2016-09-17. 72 | 73 | Version bump to trigger CocoaPods quality check 74 | 75 | --- 76 | 77 | ## [0.4.1](https://github.com/fulldecent/FDBarGuage/releases/tag/0.4.1) 78 | Released on 2016-09-17. 79 | 80 | #### Added 81 | - Support for Swift Package Manager 82 | - Added by [William Entriken](https://github.com/fulldecent) in regards to issue 83 | [#87](https://github.com/fulldecent/FDBarGuage/issues/87). 84 | - Test cases 85 | - Added by [William Entriken](https://github.com/fulldecent) in regards to issue 86 | [#72](https://github.com/fulldecent/FDBarGuage/issues/72). 87 | 88 | #### KNOWN ISSUES 89 | - Localization is broken, discuss at https://github.com/fulldecent/FDTake/pull/99 90 | 91 | --- 92 | 93 | ## [0.4.0](https://github.com/fulldecent/FDBarGuage/releases/tag/0.4.0) 94 | Released on 2016-09-17. 95 | 96 | #### Added 97 | - Automated CocoaPods Quality Indexes testing 98 | - Added by [Hayden Holligan](https://github.com/haydenholligan) in regards to issue 99 | [#95](https://github.com/fulldecent/FDTake/issues/95). 100 | 101 | #### Changed 102 | - Updated to Swift 3 103 | - Added by [Anthony Miller](https://github.com/AnthonyMDev) and [William Entriken](https://github.com/fulldecent) in regards to issue 104 | [#98](https://github.com/fulldecent/FDTake/issues/98). 105 | 106 | #### KNOWN ISSUES 107 | - Localization is broken, discuss at https://github.com/fulldecent/FDTake/pull/99 108 | 109 | --- 110 | 111 | ## [0.3.3](https://github.com/fulldecent/FDBarGuage/releases/tag/0.3.3) 112 | Released on 2016-06-27. 113 | 114 | #### Added 115 | - Change Log 116 | - Added by [William Entriken](https://github.com/fulldecent) in regards to issue 117 | [#90](https://github.com/fulldecent/FDBarGuage/issues/90). 118 | - Tracking README score 119 | - Added by [William Entriken](https://github.com/fulldecent) 120 | - Full API documentation with headerdoc 121 | - Added by [William Entriken](https://github.com/fulldecent) 122 | - Contributing guidelines and release process documentation 123 | - Added by [William Entriken](https://github.com/fulldecent) in regards to issue 124 | [#93](https://github.com/fulldecent/FDBarGuage/issues/93). 125 | 126 | #### Fixed 127 | - Crash of the iPad example when present window is tapped 128 | - Added by [Lily](https://github.com/Lily418) in regards to issue 129 | [#84](https://github.com/fulldecent/FDTake/issues/84) 130 | 131 | --- 132 | 133 | ## [0.3.2](https://github.com/fulldecent/FDBarGuage/releases/tag/0.3.2) 134 | Released on 2016-02-04. 135 | 136 | #### Fixed 137 | - Public API method visibility 138 | - by [William Entriken](https://github.com/fulldecent) 139 | 140 | --- 141 | 142 | ## [0.3.1](https://github.com/fulldecent/FDBarGuage/releases/tag/0.3.1) 143 | Released on 2016-02-03. 144 | 145 | #### Added 146 | - Support for tvOS (not tested) 147 | - Added by [William Entriken](https://github.com/fulldecent) 148 | 149 | #### Updated 150 | - Delegate method names 151 | - Added by [William Entriken](https://github.com/fulldecent) 152 | - iOS supports version 8+ 153 | - Added by [William Entriken](https://github.com/fulldecent) 154 | 155 | --- 156 | 157 | ## [0.3.0](https://github.com/fulldecent/FDBarGuage/releases/tag/0.3.0) 158 | Released on 2015-12-28. 159 | 160 | #### Fixed 161 | - Example of a project storyboard 162 | - Added by [William Entriken](https://github.com/fulldecent) 163 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributors are welcome. Please use issues and pull requests to contribute to the project. And update [CHANGELOG.md](CHANGELOG.md) when committing. 4 | 5 | ## Making a Change 6 | 7 | When you commit a change, please add a note to [CHANGELOG.md](CHANGELOG.md). 8 | 9 | ## Release Process 10 | 11 | 1. Confirm the build is [passing in travis](https://travis-ci.org/fulldecent/FDTake) 12 | 1. This automatically checks that the Podfile is building 13 | 2. Push a release commit 14 | 1. Create a new Master section at the top 15 | 2. Rename the old Master section like: 16 | ## [1.0.5](https://github.com/fulldecent/FDTake/releases/tag/1.0.5) 17 | Released on 2016-02-14. 18 | 3. Update the Podspec version number 19 | 3. Create a GitHub release 20 | 1. Tag the release (like `1.0.5`) 21 | 2. Paste notes from [CHANGELOG.md](CHANGELOG.md) 22 | 3. Push the Podspec to CocoaPods 23 | 1. `pod trunk push` 24 | 4. Create Carthage binaries 25 | 1. `carthage build --no-skip-current` 26 | 2. `carthage archive FDTake` 27 | 3. Add to the GitHub release 28 | -------------------------------------------------------------------------------- /FDTake.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "FDTake" 3 | s.version = "3.0.0" 4 | s.summary = "Easily take a photo or video or choose from library" 5 | s.description = <<-DESC 6 | `FDTake` helps you quickly to have the user take or choose an existing photo or video. 7 | DESC 8 | s.homepage = "https://github.com/fulldecent/FDTake" 9 | s.screenshots = "https://i.imgur.com/SpSJzmS.png" 10 | s.license = "MIT" 11 | s.author = { "William Entriken" => "github.com@phor.net" } 12 | s.source = { :git => "https://github.com/fulldecent/FDTake.git", :tag => s.version.to_s } 13 | s.social_media_url = 'https://twitter.com/fulldecent' 14 | s.platform = :ios, '10.0' 15 | s.requires_arc = true 16 | s.swift_version = '5.0' 17 | s.source_files = 'Sources/FDTake/**/*.swift' 18 | s.resource_bundles = { 19 | 'Resources' => [ 20 | 'Sources/FDTake/Resources/*.lproj' 21 | ] 22 | } 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 William Entriken 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "FDTake", 7 | platforms: [.iOS(.v10)], 8 | products: [ 9 | .library( 10 | name: "FDTake", 11 | targets: ["FDTake"] 12 | ) 13 | ], 14 | dependencies: [], 15 | targets: [ 16 | .target( 17 | name: "FDTake", 18 | dependencies: [] 19 | ), 20 | .testTarget( 21 | name: "FDTakeTests", 22 | dependencies: ["FDTake"] 23 | ) 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FDTake 2 | 3 | [![CI Status](http://img.shields.io/travis/fulldecent/FDTake.svg?style=flat)](https://travis-ci.org/fulldecent/FDTake) 4 | [![Version](https://img.shields.io/cocoapods/v/FDTake.svg?style=flat)](http://cocoapods.org/pods/FDTake) 5 | [![License](https://img.shields.io/cocoapods/l/FDTake.svg?style=flat)](http://cocoapods.org/pods/FDTake) 6 | [![Platform](https://img.shields.io/cocoapods/p/FDTake.svg?style=flat)](http://cocoapods.org/pods/FDTake) 7 | [![Readme Score](http://readme-score-api.herokuapp.com/score.svg?url=fulldecent/FDTake)](http://clayallsopp.github.io/readme-score?url=fulldecent/FDTake) 8 | 9 | Easily take a photo or video or choose from library 10 | 11 | **:beer: Author's tip jar: https://amazon.com/hz/wishlist/ls/EE78A23EEGQB** 12 | 13 | ## Usage 14 | 15 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 16 | 17 | To use it in your project, add an `FDTakeController` to your view controller and implement: 18 | 19 | fdTakeController.didGetPhoto = { 20 | (_ photo: UIImage, _ info: [AnyHashable : Any]) in 21 | } 22 | 23 | then call: 24 | 25 | fdTakeController.present() 26 | 27 | The full API is: 28 | 29 | ```swift 30 | /// Public initializer 31 | public override init() 32 | 33 | /// Convenience method for getting a photo 34 | open class func getPhotoWithCallback(getPhotoWithCallback callback: @escaping (_ photo: UIImage, _ info: [AnyHashable : Any]) -> Void) -> <> 35 | 36 | /// Convenience method for getting a video 37 | open class func getVideoWithCallback(getVideoWithCallback callback: @escaping (_ video: URL, _ info: [AnyHashable : Any]) -> Void) 38 | 39 | /// Whether to allow selecting a photo 40 | open var allowsPhoto: Bool 41 | 42 | /// Whether to allow selecting a video 43 | open var allowsVideo: Bool 44 | 45 | /// Whether to allow capturing a photo/video with the camera 46 | open var allowsTake: Bool 47 | 48 | /// Whether to allow selecting existing media 49 | open var allowsSelectFromLibrary: Bool 50 | 51 | /// Whether to allow editing the media after capturing/selection 52 | open var allowsEditing: Bool 53 | 54 | /// Whether to use full screen camera preview on the iPad 55 | open var iPadUsesFullScreenCamera: Bool 56 | 57 | /// Enable selfie mode by default 58 | open var defaultsToFrontCamera: Bool 59 | 60 | /// The UIBarButtonItem to present from (may be replaced by overloaded methods) 61 | open var presentingBarButtonItem: UIBarButtonItem? 62 | 63 | /// The UIView to present from (may be replaced by overloaded methods) 64 | open var presentingView: UIView? 65 | 66 | /// The UIRect to present from (may be replaced by overloaded methods) 67 | open var presentingRect: CGRect? 68 | 69 | /// The UITabBar to present from (may be replaced by overloaded methods) 70 | open var presentingTabBar: UITabBar? 71 | 72 | /// The UIViewController to present from (may be replaced by overloaded methods) 73 | open lazy var presentingViewController: UIViewController { get set } 74 | 75 | /// A photo was selected 76 | open var didGetPhoto: ((_ photo: UIImage, _ info: [AnyHashable : Any]) -> Void)? 77 | 78 | /// A video was selected 79 | open var didGetVideo: ((_ video: URL, _ info: [AnyHashable : Any]) -> Void)? 80 | 81 | /// The user did not attempt to select a photo 82 | open var didDeny: (() -> Void)? 83 | 84 | /// The user started selecting a photo or took a photo and then hit cancel 85 | open var didCancel: (() -> Void)? 86 | 87 | /// A photo or video was selected but the ImagePicker had NIL for EditedImage and OriginalImage 88 | open var didFail: (() -> Void)? 89 | 90 | /// Custom UI text (skips localization) 91 | open var cancelText: String? 92 | 93 | /// Custom UI text (skips localization) 94 | open var chooseFromLibraryText: String? 95 | 96 | /// Custom UI text (skips localization) 97 | open var chooseFromPhotoRollText: String? 98 | 99 | /// Custom UI text (skips localization) 100 | open var noSourcesText: String? 101 | 102 | /// Custom UI text (skips localization) 103 | open var takePhotoText: String? 104 | 105 | /// Custom UI text (skips localization) 106 | open var takeVideoText: String? 107 | 108 | /// Presents the user with an option to take a photo or choose a photo from the library 109 | open func present() 110 | 111 | /// Dismisses the displayed view. Especially handy if the sheet is displayed while suspending the app, 112 | open func dismiss() 113 | ``` 114 | 115 | Other available options are documented at CocoaDocs for FDTake. 116 | 117 | 118 | ## How it works 119 | 120 | 1. See if device has camera 121 | 2. Create action sheet with appropriate options ("Take Photo" or "Choose from Library"), as available 122 | 3. Localize "Take Photo" and "Choose from Library" into user's language 123 | 4. Wait for response 124 | 5. Bring up image picker with selected image picking method 125 | 6. Default to selfie mode if so configured 126 | 7. Get response, extract image from a dictionary 127 | 8. Dismiss picker, send image to delegate 128 | 129 | 130 | ## Support 131 | 132 | * Supports iPhones, iPods, iPads and tvOS (but not tested) 133 | * Supported languages: 134 | - English 135 | - Chinese Simplified 136 | - Turkish (thanks Suleyman Melikoglu) 137 | - French (thanks Guillaume Algis) 138 | - Dutch (thanks Mathijs Kadijk) 139 | - Chinese Traditional (thanks Qing Ao) 140 | - German (thanks Lars Häuser) 141 | - Russian (thanks Alexander Zubkov) 142 | - Norwegian (thanks Sindre Sorhus) 143 | - Arabic (thanks HadiIOS) 144 | - Polish (thanks Jacek Kwiecień) 145 | - Spanish (thanks David Jorge) 146 | - Hebrew (thanks Asaf Siman-Tov) 147 | - Danish (thanks kaspernissen) 148 | - Sweedish (thanks Paul Peelen) 149 | - Portugese (thanks Natan Rolnik) 150 | - Greek (thanks Konstantinos) 151 | - Italian (thanks Giuseppe Filograno) 152 | - Hungarian (thanks Andras Kadar) 153 | - Please help translate `FDTake.strings` to more languages 154 | * Pure Swift support and iOS 8+ required 155 | * Compile testing running on Travis CI 156 | * In progress: functional test cases ([please help](https://github.com/fulldecent/FDTake/issues/72)) 157 | * In progress: UI test cases ([please help](https://github.com/fulldecent/FDTake/issues/72)) 158 | 159 | 160 | ## Installation 161 | 162 | Add this to your project using Swift Package Manager. In Xcode that is simply: File > Swift Packages > Add Package Dependency... and you're done. Alternative installation options are shown below for legacy projects. 163 | 164 | ### CocoaPods 165 | 166 | If you are already using [CocoaPods](http://cocoapods.org), just add 'FDTake' to your `Podfile` then run `pod install`. 167 | 168 | ### Carthage 169 | 170 | If you are already using [Carthage](https://github.com/Carthage/Carthage), just add to your `Cartfile`: 171 | 172 | ```ogdl 173 | github "fulldecent/FDTake" 174 | ``` 175 | 176 | Then run `carthage update` to build the framework and drag the built `FDTake`.framework into your Xcode project. 177 | 178 | 179 | ## Author 180 | 181 | William Entriken, github.com@phor.net 182 | 183 | ## Project scope 184 | 185 | This is a mature project and we do not expect to add new features unless something has already become state-of-the-art in other applications. Please be prepared to cite screenshots of other apps before making a feature request. 186 | 187 | We support targets for the latest released versions of Xcode, Carthage, CocoaPods and Swift Package Manager. If there are incompatabilities, for example CocoaPods not supporting the latest version of Xcode, then we will only support the latest released versions/combinations that are supported. If you would like to support pre-release versions of these packages, please open a pull request, not an issue. 188 | 189 | ## License 190 | 191 | FDTake is available under the MIT license. See the LICENSE file for more info. 192 | 193 | ## Contributing 194 | 195 | This project's layout is based on https://github.com/fulldecent/swift4-module-template If you would like to change the layout, please change that project FIRST. Also you may appreciate that project has "recipes" -- you don't just change the code, you explain why you are doing things. As a maintainer this makes my job MUCH simpler. In a similar respect, if you are introducing non-minor changes, it will be VERY helpful if you could please reference to another project (like AlamoFire) that has seen and discussed the types of design challenges you are touching.) Thanks again and we all really do appreciate your contributions. 196 | -------------------------------------------------------------------------------- /Resources/FDTakeResources.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C4ED9827238EF83C00691F4F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C4ED9825238EF83C00691F4F /* Localizable.strings */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | C493CF94238EF7E5004F13C5 /* FDTakeResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FDTakeResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 15 | C493CF97238EF7E5004F13C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 16 | C4ED9826238EF83C00691F4F /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; 17 | C4ED982C238EF85200691F4F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; 18 | C4ED982D238EF85D00691F4F /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 19 | C4ED982E238EF86400691F4F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 20 | C4ED982F238EF86B00691F4F /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = ""; }; 21 | C4ED9830238EF87500691F4F /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/Localizable.strings; sourceTree = ""; }; 22 | C4ED9831238EF87A00691F4F /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 23 | C4ED9832238EF88100691F4F /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 24 | C4ED9833238EF88A00691F4F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; }; 25 | C4ED9834238EF89100691F4F /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 26 | C4ED9835238EF89A00691F4F /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; 27 | C4ED9836238EF8A100691F4F /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; 28 | C4ED9837238EF8A700691F4F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 29 | C4ED9838238EF8AE00691F4F /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; 30 | C4ED9839238EF8B600691F4F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 31 | C4ED983A238EF8BD00691F4F /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; 32 | C4ED983B238EF8C400691F4F /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 33 | C4ED983C238EF8D000691F4F /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = ""; }; 34 | C4ED983D238EF8E300691F4F /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | C493CF91238EF7E5004F13C5 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | C493CF8B238EF7E5004F13C5 = { 49 | isa = PBXGroup; 50 | children = ( 51 | C493CF96238EF7E5004F13C5 /* Resources */, 52 | C493CF95238EF7E5004F13C5 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | C493CF95238EF7E5004F13C5 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | C493CF94238EF7E5004F13C5 /* FDTakeResources.bundle */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | C493CF96238EF7E5004F13C5 /* Resources */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | C4ED9825238EF83C00691F4F /* Localizable.strings */, 68 | C493CF97238EF7E5004F13C5 /* Info.plist */, 69 | ); 70 | path = Resources; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | C493CF93238EF7E5004F13C5 /* FDTakeResources */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = C493CF9A238EF7E5004F13C5 /* Build configuration list for PBXNativeTarget "FDTakeResources" */; 79 | buildPhases = ( 80 | C493CF90238EF7E5004F13C5 /* Sources */, 81 | C493CF91238EF7E5004F13C5 /* Frameworks */, 82 | C493CF92238EF7E5004F13C5 /* Resources */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = FDTakeResources; 89 | productName = FDTakeResources; 90 | productReference = C493CF94238EF7E5004F13C5 /* FDTakeResources.bundle */; 91 | productType = "com.apple.product-type.bundle"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | C493CF8C238EF7E5004F13C5 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastUpgradeCheck = 1140; 100 | ORGANIZATIONNAME = "William Entriken"; 101 | TargetAttributes = { 102 | C493CF93238EF7E5004F13C5 = { 103 | CreatedOnToolsVersion = 11.2.1; 104 | }; 105 | }; 106 | }; 107 | buildConfigurationList = C493CF8F238EF7E5004F13C5 /* Build configuration list for PBXProject "FDTakeResources" */; 108 | compatibilityVersion = "Xcode 9.3"; 109 | developmentRegion = en; 110 | hasScannedForEncodings = 0; 111 | knownRegions = ( 112 | en, 113 | Base, 114 | ar, 115 | da, 116 | de, 117 | hu, 118 | el, 119 | "zh-Hant", 120 | "zh-Hans", 121 | tr, 122 | fr, 123 | nl, 124 | he, 125 | es, 126 | nb, 127 | it, 128 | sv, 129 | ru, 130 | "pt-PT", 131 | pl, 132 | ); 133 | mainGroup = C493CF8B238EF7E5004F13C5; 134 | productRefGroup = C493CF95238EF7E5004F13C5 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | C493CF93238EF7E5004F13C5 /* FDTakeResources */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | C493CF92238EF7E5004F13C5 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | C4ED9827238EF83C00691F4F /* Localizable.strings in Resources */, 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | /* End PBXResourcesBuildPhase section */ 153 | 154 | /* Begin PBXSourcesBuildPhase section */ 155 | C493CF90238EF7E5004F13C5 /* Sources */ = { 156 | isa = PBXSourcesBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXSourcesBuildPhase section */ 163 | 164 | /* Begin PBXVariantGroup section */ 165 | C4ED9825238EF83C00691F4F /* Localizable.strings */ = { 166 | isa = PBXVariantGroup; 167 | children = ( 168 | C4ED9826238EF83C00691F4F /* ar */, 169 | C4ED982C238EF85200691F4F /* da */, 170 | C4ED982D238EF85D00691F4F /* de */, 171 | C4ED982E238EF86400691F4F /* en */, 172 | C4ED982F238EF86B00691F4F /* hu */, 173 | C4ED9830238EF87500691F4F /* el */, 174 | C4ED9831238EF87A00691F4F /* zh-Hant */, 175 | C4ED9832238EF88100691F4F /* zh-Hans */, 176 | C4ED9833238EF88A00691F4F /* tr */, 177 | C4ED9834238EF89100691F4F /* fr */, 178 | C4ED9835238EF89A00691F4F /* nl */, 179 | C4ED9836238EF8A100691F4F /* he */, 180 | C4ED9837238EF8A700691F4F /* es */, 181 | C4ED9838238EF8AE00691F4F /* nb */, 182 | C4ED9839238EF8B600691F4F /* it */, 183 | C4ED983A238EF8BD00691F4F /* sv */, 184 | C4ED983B238EF8C400691F4F /* ru */, 185 | C4ED983C238EF8D000691F4F /* pt-PT */, 186 | C4ED983D238EF8E300691F4F /* pl */, 187 | ); 188 | name = Localizable.strings; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXVariantGroup section */ 192 | 193 | /* Begin XCBuildConfiguration section */ 194 | C493CF98238EF7E5004F13C5 /* Debug */ = { 195 | isa = XCBuildConfiguration; 196 | buildSettings = { 197 | ALWAYS_SEARCH_USER_PATHS = NO; 198 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 199 | CLANG_ANALYZER_NONNULL = YES; 200 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 202 | CLANG_CXX_LIBRARY = "libc++"; 203 | CLANG_ENABLE_MODULES = YES; 204 | CLANG_ENABLE_OBJC_ARC = YES; 205 | CLANG_ENABLE_OBJC_WEAK = YES; 206 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 207 | CLANG_WARN_BOOL_CONVERSION = YES; 208 | CLANG_WARN_COMMA = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 213 | CLANG_WARN_EMPTY_BODY = YES; 214 | CLANG_WARN_ENUM_CONVERSION = YES; 215 | CLANG_WARN_INFINITE_RECURSION = YES; 216 | CLANG_WARN_INT_CONVERSION = YES; 217 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 219 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 220 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 222 | CLANG_WARN_STRICT_PROTOTYPES = YES; 223 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 224 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 225 | CLANG_WARN_UNREACHABLE_CODE = YES; 226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = dwarf; 229 | ENABLE_STRICT_OBJC_MSGSEND = YES; 230 | ENABLE_TESTABILITY = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_DYNAMIC_NO_PIC = NO; 233 | GCC_NO_COMMON_BLOCKS = YES; 234 | GCC_OPTIMIZATION_LEVEL = 0; 235 | GCC_PREPROCESSOR_DEFINITIONS = ( 236 | "DEBUG=1", 237 | "$(inherited)", 238 | ); 239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 241 | GCC_WARN_UNDECLARED_SELECTOR = YES; 242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 243 | GCC_WARN_UNUSED_FUNCTION = YES; 244 | GCC_WARN_UNUSED_VARIABLE = YES; 245 | MACOSX_DEPLOYMENT_TARGET = 10.15; 246 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 247 | MTL_FAST_MATH = YES; 248 | ONLY_ACTIVE_ARCH = YES; 249 | SDKROOT = macosx; 250 | }; 251 | name = Debug; 252 | }; 253 | C493CF99238EF7E5004F13C5 /* Release */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 260 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 261 | CLANG_CXX_LIBRARY = "libc++"; 262 | CLANG_ENABLE_MODULES = YES; 263 | CLANG_ENABLE_OBJC_ARC = YES; 264 | CLANG_ENABLE_OBJC_WEAK = YES; 265 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 266 | CLANG_WARN_BOOL_CONVERSION = YES; 267 | CLANG_WARN_COMMA = YES; 268 | CLANG_WARN_CONSTANT_CONVERSION = YES; 269 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 270 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 271 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 272 | CLANG_WARN_EMPTY_BODY = YES; 273 | CLANG_WARN_ENUM_CONVERSION = YES; 274 | CLANG_WARN_INFINITE_RECURSION = YES; 275 | CLANG_WARN_INT_CONVERSION = YES; 276 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 277 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 278 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 279 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 280 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 281 | CLANG_WARN_STRICT_PROTOTYPES = YES; 282 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 283 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 284 | CLANG_WARN_UNREACHABLE_CODE = YES; 285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 286 | COPY_PHASE_STRIP = NO; 287 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 288 | ENABLE_NS_ASSERTIONS = NO; 289 | ENABLE_STRICT_OBJC_MSGSEND = YES; 290 | GCC_C_LANGUAGE_STANDARD = gnu11; 291 | GCC_NO_COMMON_BLOCKS = YES; 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | MACOSX_DEPLOYMENT_TARGET = 10.15; 299 | MTL_ENABLE_DEBUG_INFO = NO; 300 | MTL_FAST_MATH = YES; 301 | SDKROOT = macosx; 302 | }; 303 | name = Release; 304 | }; 305 | C493CF9B238EF7E5004F13C5 /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | CODE_SIGN_STYLE = Automatic; 309 | COMBINE_HIDPI_IMAGES = YES; 310 | INFOPLIST_FILE = Resources/Info.plist; 311 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; 312 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 313 | MACOSX_DEPLOYMENT_TARGET = 10.6; 314 | PRODUCT_BUNDLE_IDENTIFIER = net.phor.FDTakeResources; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SDKROOT = iphoneos; 317 | SKIP_INSTALL = YES; 318 | TARGETED_DEVICE_FAMILY = "1,2"; 319 | TVOS_DEPLOYMENT_TARGET = 9.0; 320 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 321 | WRAPPER_EXTENSION = bundle; 322 | }; 323 | name = Debug; 324 | }; 325 | C493CF9C238EF7E5004F13C5 /* Release */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | CODE_SIGN_STYLE = Automatic; 329 | COMBINE_HIDPI_IMAGES = YES; 330 | INFOPLIST_FILE = Resources/Info.plist; 331 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; 332 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 333 | MACOSX_DEPLOYMENT_TARGET = 10.6; 334 | PRODUCT_BUNDLE_IDENTIFIER = net.phor.FDTakeResources; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | SDKROOT = iphoneos; 337 | SKIP_INSTALL = YES; 338 | TARGETED_DEVICE_FAMILY = "1,2"; 339 | TVOS_DEPLOYMENT_TARGET = 9.0; 340 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 341 | WRAPPER_EXTENSION = bundle; 342 | }; 343 | name = Release; 344 | }; 345 | /* End XCBuildConfiguration section */ 346 | 347 | /* Begin XCConfigurationList section */ 348 | C493CF8F238EF7E5004F13C5 /* Build configuration list for PBXProject "FDTakeResources" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | C493CF98238EF7E5004F13C5 /* Debug */, 352 | C493CF99238EF7E5004F13C5 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | C493CF9A238EF7E5004F13C5 /* Build configuration list for PBXNativeTarget "FDTakeResources" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | C493CF9B238EF7E5004F13C5 /* Debug */, 361 | C493CF9C238EF7E5004F13C5 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = C493CF8C238EF7E5004F13C5 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /Resources/FDTakeResources.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Resources/FDTakeResources.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Resources/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | NSHumanReadableCopyright 22 | Copyright © 2019 William Entriken. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Resources/Resources/ar.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "إلغاء"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "إختر من المكتبة"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "إختر من معرض الصور"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "لا يوجد مصدر متاح لإختيار الصورة"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "التقط صورة"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "التقط فيديو"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/da.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Annuller"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Vælg fra bibliotek"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Vælg fra kamerarulle"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Der er ikke muligt at vælge et billede"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Tag billede"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Optag video"; 18 | 19 | -------------------------------------------------------------------------------- /Resources/Resources/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Abbrechen"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Foto von Bibliothek auswählen"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Photo von Album auswählen"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Keine Dateien vorhanden"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Photo aufnehmen"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Video aufnehmen"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/el.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Ακύρωση"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Επιλέξτε απο την βιβλιοθήκη"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Επιλέξτε απο το άλμπουμ της κάμερας"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Δεν υπάρχουν διαθέσιμες πηγές για να επιλέξετε μια φωτογραφία"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Τραβήξτε Φωτογραφία"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Τραβήξτε Βίντεο"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Cancel"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Choose from Library"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Choose from Photo Roll"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "There are no sources available to select a photo"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Take Photo"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Take Video"; 18 | 19 | "lastTakenMedia" = "Last photo or video taken"; 20 | -------------------------------------------------------------------------------- /Resources/Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Cancelar"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Elegir de la galería"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Elegir del carrete"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "No hay fuentes disponibles para elegir una foto"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Hacer foto"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Grabar vídeo"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Annuler"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Choisir une photo de la bibliothèque"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Choisir une photo de la pellicule"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Aucune source disponible pour le choix de la photo"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Prendre une photo"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Prendre une vidéo"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/he.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "ביטול"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "בחר מתיקייה"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "​בחר תמונה ​קיימת"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "חסרים משאבים כדי לבחור תמונה"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "צלם תמונה"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "צלם וידאו"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/hu.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Mégsem"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Választás Fotótárból"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Választás a Fénykép Tekercsből"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Nincs megfelelő forrás a fotó kiválasztásához."; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Fotó készítése"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Videó készítése"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Annulla"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Scegli dalla libreria"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Scegli dal rullino foto"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Non ci sono sorgenti disponibili per selezionare una foto"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Scatta foto"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Registra video"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/nb.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Avbryt"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Velg eksisterende"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Velg fra kamerarull"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Det er ingen tilgjengelige kilder for å velge et bilde"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Ta bilde"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Ta video"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/nl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Annuleer"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Kies bestaande"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Kies uit filmrol"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "There are no sources available to select a photo"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Maak foto"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Maak video"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/pl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Anuluj"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Wybierz z galerii"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Wybierz z rolki aparatu"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Brak źródła, z którego można by wybrać zdjęcie"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Zrób zdjęcie"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Nagraj film"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/pt-PT.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Cancelar"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Escolher existente"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Escolher do rolo da câmera"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Não há fontes disponíveis para selecionar uma foto"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Tirar foto"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Filmar vídeo"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Отмена"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Выберите из библиотеки"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Выберите из фотопленки"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Нет доступных источников для выбора фото"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Сфотографировать"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Снять видео"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/sv.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "Avbryt"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Välj befintlig"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Ta bild eller video"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Det finns inga tillgängliga källor för att välja ett foto"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Ta bild"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Ta video"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/tr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "İptal"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "Kütüphaneden seç"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "Kameradan seç"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "Resim seçimi için hiçbir kaynak bulunamadı."; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "Fotoğraf çek."; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "Bir video çekin."; 18 | 19 | "lastTakenMedia" = "Son çekilmiş video ya da fotoğrafı seç"; 20 | -------------------------------------------------------------------------------- /Resources/Resources/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "取消"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "从相册选择"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "从相册选择"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "没有照片可选"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "拍照"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "拍视频"; 18 | -------------------------------------------------------------------------------- /Resources/Resources/zh-Hant.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Decline to proceed with operation */ 2 | "cancel" = "取消"; 3 | 4 | /* Option to select photo from library */ 5 | "chooseFromLibrary" = "從相簿選擇"; 6 | 7 | /* Option to select photo from photo roll */ 8 | "chooseFromPhotoRoll" = "從相簿選擇"; 9 | 10 | /* There are no sources available to select a photo */ 11 | "noSources" = "沒有照片可選"; 12 | 13 | /* Option to take photo using camera */ 14 | "takePhoto" = "拍照"; 15 | 16 | /* Option to take video using camera */ 17 | "takeVideo" = "錄影"; 18 | -------------------------------------------------------------------------------- /Scripts/travis-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | EXAMPLE_SCHEME="iOS Example" 4 | EXAMPLE_WORKSPACE="iOS Example/iOS Example.xcworkspace" 5 | IOS_FRAMEWORK_SCHEME="FDTake" 6 | 7 | set -o pipefail 8 | 9 | if [ $RUN_TESTS == "YES" ]; then 10 | xcodebuild -scheme "$IOS_FRAMEWORK_SCHEME" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 11 | else 12 | xcodebuild -scheme "$IOS_FRAMEWORK_SCHEME" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty; 13 | fi 14 | 15 | # Build Framework in Release and Run Tests if specified 16 | if [ $RUN_TESTS == "YES" ]; then 17 | xcodebuild -scheme "$IOS_FRAMEWORK_SCHEME" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 18 | else 19 | xcodebuild -scheme "$IOS_FRAMEWORK_SCHEME" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES build | xcpretty; 20 | fi 21 | 22 | if [ $BUILD_EXAMPLE == "YES" ]; then 23 | xcodebuild -workspace "$EXAMPLE_WORKSPACE" -scheme "$EXAMPLE_SCHEME" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty; 24 | fi 25 | 26 | # Run `pod lib lint` if specified 27 | if [ $POD_LINT == "YES" ]; then 28 | pod lib lint 29 | fi 30 | 31 | if [ $POD_QUALITY_CHECK == "YES" ]; then 32 | ruby Tests/CheckCocoaPodsQualityIndexes.rb FDTake 33 | fi -------------------------------------------------------------------------------- /Sources/FDTake/Bundle+Helpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bundle+Helpers.swift 3 | // FDTake 4 | // 5 | // Created by Yaroslav Zhurakovskiy on 20.11.2019. 6 | // Copyright © 2019 William Entriken. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Bundle { 12 | static var framework: Bundle { 13 | return Bundle(for: FDTakeController.self) 14 | } 15 | 16 | static var resources: Bundle? { 17 | guard let path = Bundle.main.path(forResource: "FDTakeResources", ofType: "bundle") else { 18 | return nil 19 | } 20 | return Bundle(path: path) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/FDTake/FDTakeController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FDTakeController.swift 3 | // FDTake 4 | // 5 | // Copyright © 2015 William Entriken. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import MobileCoreServices 10 | import UIKit 11 | import Photos 12 | 13 | /// A class for selecting and taking photos 14 | open class FDTakeController: NSObject { 15 | 16 | // MARK: - Initializers & Class Convenience Methods 17 | 18 | /// Convenience method for getting a photo 19 | open class func getPhotoWithCallback(getPhotoWithCallback callback: @escaping (_ photo: UIImage, _ info: [AnyHashable: Any]) -> Void) { 20 | let fdTake = FDTakeController() 21 | fdTake.allowsVideo = false 22 | fdTake.didGetPhoto = callback 23 | fdTake.present() 24 | } 25 | 26 | /// Convenience method for getting a video 27 | open class func getVideoWithCallback(getVideoWithCallback callback: @escaping (_ video: URL, _ info: [AnyHashable: Any]) -> Void) { 28 | let fdTake = FDTakeController() 29 | fdTake.allowsPhoto = false 30 | fdTake.didGetVideo = callback 31 | fdTake.present() 32 | } 33 | 34 | 35 | // MARK: - Configuration options 36 | 37 | /// Whether to allow selecting a photo 38 | open var allowsPhoto = true 39 | 40 | /// Whether to allow selecting a video 41 | open var allowsVideo = true 42 | 43 | /// Whether to allow capturing a photo/video with the camera 44 | open var allowsTake = true 45 | 46 | /// Whether to allow selecting existing media 47 | open var allowsSelectFromLibrary = true 48 | 49 | /// Whether to allow editing the media after capturing/selection 50 | open var allowsEditing = false 51 | 52 | /// Whether to use full screen camera preview on the iPad 53 | open var iPadUsesFullScreenCamera = false 54 | 55 | /// Enable selfie mode by default 56 | open var defaultsToFrontCamera = false 57 | 58 | /// The UIBarButtonItem to present from (may be replaced by overloaded methods) 59 | open var presentingBarButtonItem: UIBarButtonItem? = nil 60 | 61 | /// The UIView to present from (may be replaced by overloaded methods) 62 | open var presentingView: UIView? = nil 63 | 64 | /// The UIRect to present from (may be replaced by overloaded methods) 65 | open var presentingRect: CGRect? = nil 66 | 67 | /// The UITabBar to present from (may be replaced by overloaded methods) 68 | open var presentingTabBar: UITabBar? = nil 69 | 70 | /// The UIViewController to present from (may be replaced by overloaded methods) 71 | open lazy var presentingViewController: UIViewController = { 72 | return UIApplication.shared.keyWindow!.rootViewController! 73 | }() 74 | 75 | 76 | // MARK: - Callbacks 77 | 78 | /// A photo was selected 79 | open var didGetPhoto: ((_ photo: UIImage, _ info: [AnyHashable: Any]) -> Void)? 80 | 81 | /// A video was selected 82 | open var didGetVideo: ((_ video: URL, _ info: [AnyHashable: Any]) -> Void)? 83 | 84 | // Last media fetched 85 | open var didGetLastMedia: ((PHAsset?) -> Void)? 86 | 87 | /// The user did not attempt to select a photo 88 | open var didDeny: (() -> Void)? 89 | 90 | /// The user started selecting a photo or took a photo and then hit cancel 91 | open var didCancel: (() -> Void)? 92 | 93 | /// A photo or video was selected but the ImagePicker had NIL for EditedImage and OriginalImage 94 | open var didFail: (() -> Void)? 95 | 96 | 97 | // MARK: - Localization overrides 98 | 99 | /// Custom UI text (skips localization) 100 | open var cancelText: String? = nil 101 | 102 | /// Custom UI text (skips localization) 103 | open var chooseFromLibraryText: String? = nil 104 | 105 | /// Custom UI text (skips localization) 106 | open var chooseFromPhotoRollText: String? = nil 107 | 108 | /// Custom UI text (skips localization) 109 | open var noSourcesText: String? = nil 110 | 111 | /// Custom UI text (skips localization) 112 | open var takePhotoText: String? = nil 113 | 114 | /// Custom UI text (skips localization) 115 | open var takeVideoText: String? = nil 116 | 117 | /// Custom UI text (skips localization) 118 | open var lastVideoOrPhoto: String? = nil 119 | 120 | 121 | // MARK: - Private 122 | 123 | private lazy var imagePicker: UIImagePickerController = { 124 | [unowned self] in 125 | let retval = UIImagePickerController() 126 | retval.delegate = self 127 | retval.allowsEditing = true 128 | return retval 129 | }() 130 | 131 | private var alertController: UIAlertController? = nil 132 | 133 | // This is a hack required on iPad if you want to select a photo and you already have a popup on the screen 134 | // see: https://stackoverflow.com/a/35209728/300224 135 | private func topViewController(rootViewController: UIViewController) -> UIViewController { 136 | var rootViewController = UIApplication.shared.keyWindow!.rootViewController! 137 | repeat { 138 | guard let presentedViewController = rootViewController.presentedViewController else { 139 | return rootViewController 140 | } 141 | 142 | if let navigationController = rootViewController.presentedViewController as? UINavigationController { 143 | rootViewController = navigationController.topViewController ?? navigationController 144 | 145 | } else { 146 | rootViewController = presentedViewController 147 | } 148 | } while true 149 | } 150 | 151 | private func fetchLatestMedia() -> PHAsset? { 152 | var asset: PHAsset? 153 | let options = PHFetchOptions() 154 | options.includeAssetSourceTypes = .typeUserLibrary 155 | PHAsset.fetchAssets(with: options).enumerateObjects(options: .concurrent) { (assetReturned, _, _) in 156 | asset = assetReturned 157 | } 158 | return asset 159 | } 160 | // MARK: - Localization 161 | 162 | private func localizedString(for string: FDTakeControllerLocalizableStrings) -> String { 163 | let bundleLocalization = string.localizedString 164 | 165 | switch string { 166 | case .cancel: 167 | return self.cancelText ?? bundleLocalization 168 | case .chooseFromLibrary: 169 | return self.chooseFromLibraryText ?? bundleLocalization 170 | case .chooseFromPhotoRoll: 171 | return self.chooseFromPhotoRollText ?? bundleLocalization 172 | case .noSources: 173 | return self.noSourcesText ?? bundleLocalization 174 | case .takePhoto: 175 | return self.takePhotoText ?? bundleLocalization 176 | case .takeVideo: 177 | return self.takeVideoText ?? bundleLocalization 178 | case .lastTakenMedia: 179 | return self.lastVideoOrPhoto ?? bundleLocalization 180 | } 181 | } 182 | 183 | 184 | /// Presents the user with an option to take a photo or choose a photo from the library 185 | open func present() { 186 | //TODO: maybe encapsulate source selection? 187 | var titleToSource = [(buttonTitle: FDTakeControllerLocalizableStrings, source: UIImagePickerController.SourceType)]() 188 | 189 | if self.allowsTake && UIImagePickerController.isSourceTypeAvailable(.camera) { 190 | if self.allowsPhoto { 191 | titleToSource.append((buttonTitle: .takePhoto, source: .camera)) 192 | } 193 | if self.allowsVideo { 194 | titleToSource.append((buttonTitle: .takeVideo, source: .camera)) 195 | } 196 | } 197 | if self.allowsSelectFromLibrary { 198 | if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { 199 | titleToSource.append((buttonTitle: .chooseFromLibrary, source: .photoLibrary)) 200 | titleToSource.append((buttonTitle: .lastTakenMedia, source: .photoLibrary)) 201 | } else if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) { 202 | titleToSource.append((buttonTitle: .chooseFromPhotoRoll, source: .savedPhotosAlbum)) 203 | } 204 | } 205 | 206 | guard titleToSource.count > 0 else { 207 | let str = localizedString(for: .noSources) 208 | 209 | //TODO: Encapsulate this 210 | //TODO: There has got to be a better way to do this 211 | let alert = UIAlertController(title: nil, message: str, preferredStyle: .alert) 212 | alert.addAction(UIAlertAction(title: localizedString(for: .cancel), style: .default, handler: nil)) 213 | 214 | // http://stackoverflow.com/a/34487871/300224 215 | let alertWindow = UIWindow(frame: UIScreen.main.bounds) 216 | alertWindow.rootViewController = UIViewController() 217 | alertWindow.windowLevel = UIWindow.Level.alert + 1; 218 | alertWindow.makeKeyAndVisible() 219 | alertWindow.rootViewController?.present(alert, animated: true, completion: nil) 220 | return 221 | } 222 | 223 | var popOverPresentRect : CGRect = self.presentingRect ?? CGRect(x: 0, y: 0, width: 1, height: 1) 224 | if popOverPresentRect.size.height == 0 || popOverPresentRect.size.width == 0 { 225 | popOverPresentRect = CGRect(x: 0, y: 0, width: 1, height: 1) 226 | } 227 | 228 | alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) 229 | for (title, source) in titleToSource { 230 | let action = UIAlertAction(title: localizedString(for: title), style: .default) { 231 | (UIAlertAction) -> Void in 232 | self.imagePicker.sourceType = source 233 | if source == .camera && self.defaultsToFrontCamera && UIImagePickerController.isCameraDeviceAvailable(.front) { 234 | self.imagePicker.cameraDevice = .front 235 | } 236 | // set the media type: photo or video 237 | self.imagePicker.allowsEditing = self.allowsEditing 238 | var mediaTypes = [String]() 239 | if self.allowsPhoto { 240 | mediaTypes.append(String(kUTTypeImage)) 241 | } 242 | if self.allowsVideo { 243 | mediaTypes.append(String(kUTTypeMovie)) 244 | } 245 | self.imagePicker.mediaTypes = mediaTypes 246 | 247 | if title == .lastTakenMedia { 248 | let media = self.fetchLatestMedia() 249 | self.didGetLastMedia?(media) 250 | } else { 251 | //TODO: Need to encapsulate popover code 252 | var popOverPresentRect: CGRect = self.presentingRect ?? CGRect(x: 0, y: 0, width: 1, height: 1) 253 | if popOverPresentRect.size.height == 0 || popOverPresentRect.size.width == 0 { 254 | popOverPresentRect = CGRect(x: 0, y: 0, width: 1, height: 1) 255 | } 256 | let topVC = self.topViewController(rootViewController: self.presentingViewController) 257 | 258 | if UI_USER_INTERFACE_IDIOM() == .phone || (source == .camera && self.iPadUsesFullScreenCamera) { 259 | topVC.present(self.imagePicker, animated: true, completion: nil) 260 | } else { 261 | // On iPad use pop-overs. 262 | self.imagePicker.modalPresentationStyle = .popover 263 | self.imagePicker.popoverPresentationController?.sourceRect = popOverPresentRect 264 | topVC.present(self.imagePicker, animated: true, completion: nil) 265 | } 266 | } 267 | 268 | } 269 | alertController!.addAction(action) 270 | } 271 | let cancelAction = UIAlertAction(title: localizedString(for: .cancel), style: .cancel) { 272 | (UIAlertAction) -> Void in 273 | self.didCancel?() 274 | } 275 | alertController!.addAction(cancelAction) 276 | 277 | let topVC = topViewController(rootViewController: presentingViewController) 278 | 279 | alertController?.modalPresentationStyle = .popover 280 | if let presenter = alertController!.popoverPresentationController { 281 | presenter.sourceView = presentingView; 282 | if let presentingRect = self.presentingRect { 283 | presenter.sourceRect = presentingRect 284 | } 285 | //WARNING: on ipad this fails if no SOURCEVIEW AND SOURCE RECT is provided 286 | } 287 | topVC.present(alertController!, animated: true, completion: nil) 288 | } 289 | 290 | /// Dismisses the displayed view. Especially handy if the sheet is displayed while suspending the app, 291 | open func dismiss() { 292 | alertController?.dismiss(animated: true, completion: nil) 293 | imagePicker.dismiss(animated: true, completion: nil) 294 | } 295 | } 296 | 297 | extension FDTakeController : UIImagePickerControllerDelegate, UINavigationControllerDelegate { 298 | public func imagePickerController( 299 | _ picker: UIImagePickerController, 300 | didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any] 301 | ) { 302 | UIApplication.shared.isStatusBarHidden = true 303 | switch info[.mediaType] as! CFString { 304 | case kUTTypeImage: 305 | let imageToSave: UIImage 306 | if let editedImage = info[.editedImage] as? UIImage { 307 | imageToSave = editedImage 308 | } else if let originalImage = info[.originalImage] as? UIImage { 309 | imageToSave = originalImage 310 | } else { 311 | self.didCancel?() 312 | return 313 | } 314 | self.didGetPhoto?(imageToSave, info) 315 | if UI_USER_INTERFACE_IDIOM() == .pad { 316 | self.imagePicker.dismiss(animated: true) 317 | } 318 | case kUTTypeMovie: 319 | self.didGetVideo?(info[.mediaURL] as! URL, info) 320 | default: 321 | break 322 | } 323 | 324 | picker.dismiss(animated: true, completion: nil) 325 | } 326 | 327 | /// Conformance for image picker delegate 328 | public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 329 | UIApplication.shared.isStatusBarHidden = true 330 | picker.dismiss(animated: true, completion: nil) 331 | self.didDeny?() 332 | } 333 | } 334 | 335 | -------------------------------------------------------------------------------- /Sources/FDTake/FDTakeControllerLocalizableStrings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FDTakeControllerLocalizableStrings.swift 3 | // FDTake 4 | // 5 | // Created by Yaroslav Zhurakovskiy on 20.11.2019. 6 | // Copyright © 2019 William Entriken. All rights reserved. 7 | // 8 | import Foundation 9 | 10 | /// User interface strings 11 | enum FDTakeControllerLocalizableStrings: String { 12 | /// Decline to proceed with operation 13 | case cancel = "cancel" 14 | 15 | /// Option to select photo from library 16 | case chooseFromLibrary = "chooseFromLibrary" 17 | 18 | /// Option to select photo from photo roll 19 | case chooseFromPhotoRoll = "chooseFromPhotoRoll" 20 | 21 | /// There are no sources available to select a photo 22 | case noSources = "noSources" 23 | 24 | /// Option to take photo using camera 25 | case takePhoto = "takePhoto" 26 | 27 | /// Option to take video using camera 28 | case takeVideo = "takeVideo" 29 | 30 | /// Option to choose last taken photo or video 31 | case lastTakenMedia = "lastTakenMedia" 32 | 33 | var defaultLocalizedString: String { 34 | switch self { 35 | case .cancel: 36 | return "🛑" 37 | case .chooseFromLibrary: 38 | return "📕" 39 | case .chooseFromPhotoRoll: 40 | return "📒" 41 | case .noSources: 42 | return "📵" 43 | case .takePhoto: 44 | return "📷" 45 | case .takeVideo: 46 | return "🎥" 47 | case .lastTakenMedia: 48 | return "📷" 49 | } 50 | } 51 | 52 | var localizedString: String { 53 | let bundle = Bundle.resources ?? Bundle.main 54 | return bundle.localizedString( 55 | forKey: rawValue, 56 | value: defaultLocalizedString, 57 | table: nil 58 | ) 59 | } 60 | 61 | func comment() -> String { 62 | switch self { 63 | case .cancel: 64 | return "Decline to proceed with operation" 65 | case .chooseFromLibrary: 66 | return "Option to select photo/video from library" 67 | case .chooseFromPhotoRoll: 68 | return "Option to select photo from photo roll" 69 | case .noSources: 70 | return "There are no sources available to select a photo" 71 | case .takePhoto: 72 | return "Option to take photo using camera" 73 | case .takeVideo: 74 | return "Option to take video using camera" 75 | case .lastTakenMedia: 76 | return "Option to choose last taken video or photo" 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Tests/CheckCocoaPodsQualityIndexes.rb: -------------------------------------------------------------------------------- 1 | #!/bin/ruby 2 | 3 | # 4 | # CheckCocoaPodsQualityIndexes.rb 5 | # by William Entriken, version 1.0.1 6 | # Part of https://github.com/fulldecent/swift3-module-template 7 | # 8 | # This validates that all controllable quality metrics receive maximum score 9 | # from CocoaPods's scoring quality algorithm 10 | # 11 | # Usage: ruby CheckCocoaPodsQualityIndexes.rb PODNAME 12 | # 13 | 14 | require "json" 15 | require "uri" 16 | require "net/http" 17 | 18 | pod_name = ARGV.shift 19 | 20 | puts "Reviewing CocoaPods's quality metrics for #{pod_name}" 21 | puts "Metrics documentation: https://guides.cocoapods.org/making/quality-indexes.html" 22 | puts "Modifiers from: https://cocoadocs-api-cocoapods-org.herokuapp.com/pods/#{pod_name}/stats" 23 | puts "Raw data from: http://metrics.cocoapods.org/api/v1/pods/#{pod_name}" 24 | puts "NOTE: You must pust a new version to CocoaPods to get new metrics!" 25 | puts "" 26 | 27 | uri = URI.parse('https://cocoadocs-api-cocoapods-org.herokuapp.com/pods/FDTake/stats') 28 | http = Net::HTTP.new(uri.host, uri.port) 29 | http.use_ssl = true if uri.scheme == 'https' 30 | request = Net::HTTP::Get.new uri 31 | response = http.request(request) 32 | 33 | if !response.is_a? Net::HTTPOK 34 | puts "HTTP fetching error!" 35 | exit 1 36 | end 37 | 38 | passing = true 39 | for metric in JSON.parse(response.body)['metrics'] 40 | if ['Verified Owner', 'Very Popular', 'Popular'].include? metric['title'] 41 | puts "SKIPPED\tYou cannot control: " + metric['title'] 42 | next 43 | end 44 | if metric['modifier'] >= 0 45 | if metric['applies_for_pod'] 46 | puts "GOOD\tEarned points for: " + metric['title'] 47 | else 48 | puts "BAD\tMissed points for: " + metric['title'] 49 | passing = false 50 | end 51 | else 52 | if metric['applies_for_pod'] 53 | puts "BAD\tLost points for: " + metric['title'] 54 | passing = false 55 | else 56 | puts "GOOD\tAvoided penalty for: " + metric['title'] 57 | end 58 | end 59 | end 60 | 61 | exit passing ? 0 : 1 62 | -------------------------------------------------------------------------------- /Tests/FDTakeTests/FDTakeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FDTakeTests.swift 3 | // FDTakeTests 4 | // 5 | // Created by William Entriken on Sep 17, 2016. 6 | // Copyright © 2016 William Entriken. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import FDTake 11 | 12 | class FDTakeTests: XCTestCase { 13 | var fdTake: FDTakeController! = nil 14 | 15 | override func setUp() { 16 | super.setUp() 17 | fdTake = FDTakeController() 18 | } 19 | 20 | override func tearDown() { 21 | // Put teardown code here. This method is called after the invocation of each test method in the class. 22 | super.tearDown() 23 | } 24 | 25 | func testLocalization() { 26 | fdTake.cancelText = "bob" 27 | XCTAssertEqual(fdTake.cancelText, "bob") 28 | fdTake.chooseFromLibraryText = "bob" 29 | XCTAssertEqual(fdTake.chooseFromLibraryText, "bob") 30 | fdTake.chooseFromPhotoRollText = "bob" 31 | XCTAssertEqual(fdTake.chooseFromPhotoRollText, "bob") 32 | fdTake.noSourcesText = "bob" 33 | XCTAssertEqual(fdTake.noSourcesText, "bob") 34 | fdTake.takePhotoText = "bob" 35 | XCTAssertEqual(fdTake.takePhotoText, "bob") 36 | fdTake.takeVideoText = "bob" 37 | XCTAssertEqual(fdTake.takeVideoText, "bob") 38 | } 39 | 40 | func testOthersParams() { 41 | fdTake.allowsPhoto = false 42 | XCTAssertEqual(fdTake.allowsPhoto, false) 43 | 44 | fdTake.allowsVideo = false 45 | XCTAssertEqual(fdTake.allowsVideo, false) 46 | 47 | fdTake.allowsTake = false 48 | XCTAssertEqual(fdTake.allowsTake, false) 49 | 50 | fdTake.allowsSelectFromLibrary = false 51 | XCTAssertEqual(fdTake.allowsSelectFromLibrary, false) 52 | 53 | fdTake.allowsEditing = false 54 | XCTAssertEqual(fdTake.allowsEditing, false) 55 | 56 | fdTake.allowsSelectFromLibrary = false 57 | XCTAssertEqual(fdTake.allowsSelectFromLibrary, false) 58 | 59 | fdTake.iPadUsesFullScreenCamera = false 60 | XCTAssertEqual(fdTake.iPadUsesFullScreenCamera, false) 61 | 62 | fdTake.defaultsToFrontCamera = false 63 | XCTAssertEqual(fdTake.defaultsToFrontCamera, false) 64 | 65 | fdTake.defaultsToFrontCamera = false 66 | XCTAssertEqual(fdTake.defaultsToFrontCamera, false) 67 | 68 | fdTake.defaultsToFrontCamera = false 69 | XCTAssertEqual(fdTake.defaultsToFrontCamera, false) 70 | 71 | fdTake.presentingBarButtonItem = nil 72 | XCTAssertEqual(fdTake.presentingBarButtonItem, nil) 73 | 74 | fdTake.presentingView = nil 75 | XCTAssertEqual(fdTake.presentingView, nil) 76 | 77 | fdTake.presentingRect = nil 78 | XCTAssertEqual(fdTake.presentingRect, nil) 79 | 80 | fdTake.presentingTabBar = nil 81 | XCTAssertEqual(fdTake.presentingTabBar, nil) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /iOS Example/Sources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS Example 4 | // 5 | // Created by William Entriken on Sep 17, 2016. 6 | // Copyright © 2016 William Entriken. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /iOS Example/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /iOS Example/Sources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /iOS Example/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | Test camera usage 25 | NSPhotoLibraryUsageDescription 26 | Test photo library usage 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /iOS Example/Sources/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 40 | 41 | 42 | 43 | 44 | 51 | 52 | 53 | 54 | 55 | 62 | 63 | 64 | 65 | 66 | 73 | 74 | 75 | 76 | 77 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 99 | 107 | 115 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /iOS Example/Sources/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // FDTake 4 | // 5 | // Created by William Entriken on 12/27/2015. 6 | // Copyright (c) 2015 William Entriken. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import FDTake 11 | import Photos 12 | 13 | class ViewController: UIViewController { 14 | 15 | @IBOutlet weak var languageLabel: UILabel! 16 | var fdTakeController = FDTakeController() 17 | var player = AVPlayer() 18 | var playerLayer = AVPlayerLayer() 19 | 20 | @IBOutlet weak var allowsPhoto: UISwitch! 21 | @IBOutlet weak var allowsVideo: UISwitch! 22 | @IBOutlet weak var allowsTake: UISwitch! 23 | @IBOutlet weak var allowsSelectFromLibrary: UISwitch! 24 | @IBOutlet weak var allowsEditing: UISwitch! 25 | @IBOutlet weak var defaultsToFrontCamera: UISwitch! 26 | @IBOutlet weak var iPadFullScreenCamera: UISwitch! 27 | @IBOutlet weak var fetchedImageView: UIImageView! 28 | @IBOutlet weak var fetchedVideoView: UIView! 29 | 30 | override func viewDidAppear(_ animated: Bool) { 31 | super.viewDidAppear(animated) 32 | self.languageLabel.text = NSLocale.preferredLanguages.first! 33 | } 34 | 35 | private func resetFDTakeController () -> Void { 36 | fdTakeController = FDTakeController() 37 | fdTakeController.allowsPhoto = allowsPhoto.isOn 38 | fdTakeController.allowsVideo = allowsVideo.isOn 39 | fdTakeController.allowsTake = allowsTake.isOn 40 | fdTakeController.allowsSelectFromLibrary = allowsSelectFromLibrary.isOn 41 | fdTakeController.allowsEditing = allowsEditing.isOn 42 | fdTakeController.defaultsToFrontCamera = defaultsToFrontCamera.isOn 43 | fdTakeController.iPadUsesFullScreenCamera = iPadFullScreenCamera.isOn 44 | fdTakeController.didDeny = { 45 | let alert = UIAlertController(title: "Denied", message: "User did not select a photo/video", preferredStyle: .alert) 46 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 47 | self.present(alert, animated: true, completion: nil) 48 | } 49 | fdTakeController.didCancel = { 50 | let alert = UIAlertController(title: "Cancelled", message: "User did cancel while selecting", preferredStyle: .alert) 51 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 52 | self.present(alert, animated: true, completion: nil) 53 | } 54 | fdTakeController.didFail = { 55 | let alert = UIAlertController(title: "Failed", message: "User selected but API failed", preferredStyle: .alert) 56 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 57 | self.present(alert, animated: true, completion: nil) 58 | } 59 | fdTakeController.didGetPhoto = { 60 | (photo: UIImage, info: [AnyHashable : Any]) -> Void in 61 | let alert = UIAlertController(title: "Got photo", message: "User selected photo", preferredStyle: .alert) 62 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 63 | 64 | // http://stackoverflow.com/a/34487871/300224 65 | let alertWindow = UIWindow(frame: UIScreen.main.bounds) 66 | alertWindow.rootViewController = UIViewController() 67 | alertWindow.windowLevel = UIWindow.Level.alert + 1; 68 | alertWindow.makeKeyAndVisible() 69 | alertWindow.rootViewController?.present(alert, animated: true, completion: nil) 70 | } 71 | 72 | fdTakeController.didGetVideo = { 73 | (video: URL, info: [AnyHashable : Any]) in 74 | let alert = UIAlertController(title: "Got photo", message: "User selected photo", preferredStyle: .alert) 75 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 76 | 77 | // http://stackoverflow.com/a/34487871/300224 78 | let alertWindow = UIWindow(frame: UIScreen.main.bounds) 79 | alertWindow.rootViewController = UIViewController() 80 | alertWindow.windowLevel = UIWindow.Level.alert + 1; 81 | alertWindow.makeKeyAndVisible() 82 | alertWindow.rootViewController?.present(alert, animated: true, completion: nil) 83 | } 84 | fdTakeController.didGetLastMedia = { [weak self] media in 85 | guard let mediaValue = media, let `self` = self else { return } 86 | if mediaValue.mediaType == .image { 87 | PHImageManager.default().requestImage(for: mediaValue, targetSize: self.fetchedImageView.frame.size, contentMode: .aspectFill, options: nil) { (image, info) in 88 | self.fetchedImageView.image = image 89 | } 90 | } else if mediaValue.mediaType == .video { 91 | PHImageManager.default().requestAVAsset(forVideo: mediaValue, options: nil) { (asset, audio, info) in 92 | guard let urlAsset = asset as? AVURLAsset else {return} 93 | DispatchQueue.main.async { 94 | self.player = AVPlayer(url: urlAsset.url) 95 | self.playerLayer = AVPlayerLayer(player: self.player) 96 | self.playerLayer.frame = self.fetchedVideoView.bounds 97 | self.playerLayer.removeFromSuperlayer() 98 | self.fetchedVideoView.layer.addSublayer(self.playerLayer) 99 | self.player.play() 100 | } 101 | 102 | } 103 | } else { 104 | print("do nothing") 105 | } 106 | 107 | } 108 | } 109 | 110 | @IBAction func presentFromButton(_ sender: UIButton) { 111 | resetFDTakeController() 112 | fdTakeController.presentingView = sender 113 | fdTakeController.present() 114 | } 115 | 116 | @IBAction func presentFromWindow() { 117 | resetFDTakeController() 118 | fdTakeController.presentingView = self.view 119 | fdTakeController.present() 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C4012D2A238F01A5005BC7B3 /* FDTakeResources.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = C4012D27238F0195005BC7B3 /* FDTakeResources.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 11 | C4ED9847238EFA3F00691F4F /* FDTake.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D95E1C891D88F39300F94976 /* FDTake.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | C4EEAC1D2385316D00177742 /* FDTake in Frameworks */ = {isa = PBXBuildFile; productRef = C4EEAC1C2385316D00177742 /* FDTake */; }; 13 | D95E1C451D88E71A00F94976 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D95E1C441D88E71A00F94976 /* AppDelegate.swift */; }; 14 | D95E1C471D88E71A00F94976 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D95E1C461D88E71A00F94976 /* ViewController.swift */; }; 15 | D95E1C4C1D88E71A00F94976 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D95E1C4B1D88E71A00F94976 /* Assets.xcassets */; }; 16 | D95E1C4F1D88E71A00F94976 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */; }; 17 | D9D7F7BD1D8DAF1900A0DA5B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D9D7F7BC1D8DAF1900A0DA5B /* Main.storyboard */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | C4012D26238F0195005BC7B3 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = C4012D22238F0195005BC7B3 /* FDTakeResources.xcodeproj */; 24 | proxyType = 2; 25 | remoteGlobalIDString = C493CF94238EF7E5004F13C5; 26 | remoteInfo = FDTakeResources; 27 | }; 28 | C4012D28238F019F005BC7B3 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = C4012D22238F0195005BC7B3 /* FDTakeResources.xcodeproj */; 31 | proxyType = 1; 32 | remoteGlobalIDString = C493CF93238EF7E5004F13C5; 33 | remoteInfo = FDTakeResources; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXCopyFilesBuildPhase section */ 38 | C48C0E95238EFE96003871B2 /* CopyFiles */ = { 39 | isa = PBXCopyFilesBuildPhase; 40 | buildActionMask = 12; 41 | dstPath = ""; 42 | dstSubfolderSpec = 7; 43 | files = ( 44 | C4012D2A238F01A5005BC7B3 /* FDTakeResources.bundle in CopyFiles */, 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | D9D7F7C11D8DC32F00A0DA5B /* Embed Frameworks */ = { 49 | isa = PBXCopyFilesBuildPhase; 50 | buildActionMask = 8; 51 | dstPath = ""; 52 | dstSubfolderSpec = 10; 53 | files = ( 54 | C4ED9847238EFA3F00691F4F /* FDTake.framework in Embed Frameworks */, 55 | ); 56 | name = "Embed Frameworks"; 57 | runOnlyForDeploymentPostprocessing = 1; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | C4012D22238F0195005BC7B3 /* FDTakeResources.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = FDTakeResources.xcodeproj; path = ../Resources/FDTakeResources.xcodeproj; sourceTree = ""; }; 63 | D95E1C411D88E71A00F94976 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | D95E1C441D88E71A00F94976 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 65 | D95E1C461D88E71A00F94976 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 66 | D95E1C4B1D88E71A00F94976 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 67 | D95E1C4E1D88E71A00F94976 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 68 | D95E1C501D88E71A00F94976 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | D95E1C891D88F39300F94976 /* FDTake.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FDTake.framework; path = "../build/Debug-iphoneos/FDTake.framework"; sourceTree = ""; }; 70 | D9D7F7BC1D8DAF1900A0DA5B /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | D95E1C3E1D88E71A00F94976 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | C4EEAC1D2385316D00177742 /* FDTake in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXFrameworksBuildPhase section */ 83 | 84 | /* Begin PBXGroup section */ 85 | C4012D23238F0195005BC7B3 /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | C4012D27238F0195005BC7B3 /* FDTakeResources.bundle */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | D95E1C381D88E71A00F94976 = { 94 | isa = PBXGroup; 95 | children = ( 96 | D95E1C431D88E71A00F94976 /* Sources */, 97 | D95E1C421D88E71A00F94976 /* Products */, 98 | D95E1C881D88F39300F94976 /* Frameworks */, 99 | C4012D22238F0195005BC7B3 /* FDTakeResources.xcodeproj */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | D95E1C421D88E71A00F94976 /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | D95E1C411D88E71A00F94976 /* iOS Example.app */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | D95E1C431D88E71A00F94976 /* Sources */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | D95E1C441D88E71A00F94976 /* AppDelegate.swift */, 115 | D95E1C461D88E71A00F94976 /* ViewController.swift */, 116 | D95E1C4B1D88E71A00F94976 /* Assets.xcassets */, 117 | D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */, 118 | D9D7F7BC1D8DAF1900A0DA5B /* Main.storyboard */, 119 | D95E1C501D88E71A00F94976 /* Info.plist */, 120 | ); 121 | path = Sources; 122 | sourceTree = ""; 123 | }; 124 | D95E1C881D88F39300F94976 /* Frameworks */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | D95E1C891D88F39300F94976 /* FDTake.framework */, 128 | ); 129 | name = Frameworks; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXNativeTarget section */ 135 | D95E1C401D88E71A00F94976 /* iOS Example */ = { 136 | isa = PBXNativeTarget; 137 | buildConfigurationList = D95E1C531D88E71A00F94976 /* Build configuration list for PBXNativeTarget "iOS Example" */; 138 | buildPhases = ( 139 | D95E1C3D1D88E71A00F94976 /* Sources */, 140 | D95E1C3E1D88E71A00F94976 /* Frameworks */, 141 | D95E1C3F1D88E71A00F94976 /* Resources */, 142 | D9D7F7C11D8DC32F00A0DA5B /* Embed Frameworks */, 143 | C48C0E95238EFE96003871B2 /* CopyFiles */, 144 | ); 145 | buildRules = ( 146 | ); 147 | dependencies = ( 148 | C4012D29238F019F005BC7B3 /* PBXTargetDependency */, 149 | ); 150 | name = "iOS Example"; 151 | packageProductDependencies = ( 152 | C4EEAC1C2385316D00177742 /* FDTake */, 153 | ); 154 | productName = "iOS Example"; 155 | productReference = D95E1C411D88E71A00F94976 /* iOS Example.app */; 156 | productType = "com.apple.product-type.application"; 157 | }; 158 | /* End PBXNativeTarget section */ 159 | 160 | /* Begin PBXProject section */ 161 | D95E1C391D88E71A00F94976 /* Project object */ = { 162 | isa = PBXProject; 163 | attributes = { 164 | LastSwiftUpdateCheck = 0800; 165 | LastUpgradeCheck = 1020; 166 | ORGANIZATIONNAME = "William Entriken"; 167 | TargetAttributes = { 168 | D95E1C401D88E71A00F94976 = { 169 | CreatedOnToolsVersion = 8.0; 170 | LastSwiftMigration = 1020; 171 | ProvisioningStyle = Automatic; 172 | }; 173 | }; 174 | }; 175 | buildConfigurationList = D95E1C3C1D88E71A00F94976 /* Build configuration list for PBXProject "iOS Example" */; 176 | compatibilityVersion = "Xcode 3.2"; 177 | developmentRegion = en; 178 | hasScannedForEncodings = 0; 179 | knownRegions = ( 180 | en, 181 | Base, 182 | de, 183 | he, 184 | ar, 185 | el, 186 | "zh-Hans", 187 | nb, 188 | es, 189 | da, 190 | it, 191 | sv, 192 | "zh-Hant", 193 | hu, 194 | tr, 195 | pl, 196 | ru, 197 | fr, 198 | nl, 199 | "pt-PT", 200 | ); 201 | mainGroup = D95E1C381D88E71A00F94976; 202 | productRefGroup = D95E1C421D88E71A00F94976 /* Products */; 203 | projectDirPath = ""; 204 | projectReferences = ( 205 | { 206 | ProductGroup = C4012D23238F0195005BC7B3 /* Products */; 207 | ProjectRef = C4012D22238F0195005BC7B3 /* FDTakeResources.xcodeproj */; 208 | }, 209 | ); 210 | projectRoot = ""; 211 | targets = ( 212 | D95E1C401D88E71A00F94976 /* iOS Example */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXReferenceProxy section */ 218 | C4012D27238F0195005BC7B3 /* FDTakeResources.bundle */ = { 219 | isa = PBXReferenceProxy; 220 | fileType = wrapper.cfbundle; 221 | path = FDTakeResources.bundle; 222 | remoteRef = C4012D26238F0195005BC7B3 /* PBXContainerItemProxy */; 223 | sourceTree = BUILT_PRODUCTS_DIR; 224 | }; 225 | /* End PBXReferenceProxy section */ 226 | 227 | /* Begin PBXResourcesBuildPhase section */ 228 | D95E1C3F1D88E71A00F94976 /* Resources */ = { 229 | isa = PBXResourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | D9D7F7BD1D8DAF1900A0DA5B /* Main.storyboard in Resources */, 233 | D95E1C4F1D88E71A00F94976 /* LaunchScreen.storyboard in Resources */, 234 | D95E1C4C1D88E71A00F94976 /* Assets.xcassets in Resources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXResourcesBuildPhase section */ 239 | 240 | /* Begin PBXSourcesBuildPhase section */ 241 | D95E1C3D1D88E71A00F94976 /* Sources */ = { 242 | isa = PBXSourcesBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | D95E1C471D88E71A00F94976 /* ViewController.swift in Sources */, 246 | D95E1C451D88E71A00F94976 /* AppDelegate.swift in Sources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXSourcesBuildPhase section */ 251 | 252 | /* Begin PBXTargetDependency section */ 253 | C4012D29238F019F005BC7B3 /* PBXTargetDependency */ = { 254 | isa = PBXTargetDependency; 255 | name = FDTakeResources; 256 | targetProxy = C4012D28238F019F005BC7B3 /* PBXContainerItemProxy */; 257 | }; 258 | /* End PBXTargetDependency section */ 259 | 260 | /* Begin PBXVariantGroup section */ 261 | D95E1C4D1D88E71A00F94976 /* LaunchScreen.storyboard */ = { 262 | isa = PBXVariantGroup; 263 | children = ( 264 | D95E1C4E1D88E71A00F94976 /* Base */, 265 | ); 266 | name = LaunchScreen.storyboard; 267 | sourceTree = ""; 268 | }; 269 | /* End PBXVariantGroup section */ 270 | 271 | /* Begin XCBuildConfiguration section */ 272 | D95E1C511D88E71A00F94976 /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_COMMA = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 287 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 288 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 289 | CLANG_WARN_EMPTY_BODY = YES; 290 | CLANG_WARN_ENUM_CONVERSION = YES; 291 | CLANG_WARN_INFINITE_RECURSION = YES; 292 | CLANG_WARN_INT_CONVERSION = YES; 293 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 294 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 295 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 297 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 298 | CLANG_WARN_STRICT_PROTOTYPES = YES; 299 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 300 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 301 | CLANG_WARN_UNREACHABLE_CODE = YES; 302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 304 | COPY_PHASE_STRIP = NO; 305 | DEBUG_INFORMATION_FORMAT = dwarf; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | ENABLE_TESTABILITY = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu99; 309 | GCC_DYNAMIC_NO_PIC = NO; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_OPTIMIZATION_LEVEL = 0; 312 | GCC_PREPROCESSOR_DEFINITIONS = ( 313 | "DEBUG=1", 314 | "$(inherited)", 315 | ); 316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 317 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 318 | GCC_WARN_UNDECLARED_SELECTOR = YES; 319 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 320 | GCC_WARN_UNUSED_FUNCTION = YES; 321 | GCC_WARN_UNUSED_VARIABLE = YES; 322 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 323 | MTL_ENABLE_DEBUG_INFO = YES; 324 | ONLY_ACTIVE_ARCH = YES; 325 | SDKROOT = iphoneos; 326 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 327 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 328 | TARGETED_DEVICE_FAMILY = "1,2"; 329 | }; 330 | name = Debug; 331 | }; 332 | D95E1C521D88E71A00F94976 /* Release */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | ALWAYS_SEARCH_USER_PATHS = NO; 336 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 337 | CLANG_ANALYZER_NONNULL = YES; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_COMMA = YES; 345 | CLANG_WARN_CONSTANT_CONVERSION = YES; 346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 349 | CLANG_WARN_EMPTY_BODY = YES; 350 | CLANG_WARN_ENUM_CONVERSION = YES; 351 | CLANG_WARN_INFINITE_RECURSION = YES; 352 | CLANG_WARN_INT_CONVERSION = YES; 353 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 355 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 356 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 357 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 358 | CLANG_WARN_STRICT_PROTOTYPES = YES; 359 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 360 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 361 | CLANG_WARN_UNREACHABLE_CODE = YES; 362 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 363 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 364 | COPY_PHASE_STRIP = NO; 365 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 366 | ENABLE_NS_ASSERTIONS = NO; 367 | ENABLE_STRICT_OBJC_MSGSEND = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu99; 369 | GCC_NO_COMMON_BLOCKS = YES; 370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 372 | GCC_WARN_UNDECLARED_SELECTOR = YES; 373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 374 | GCC_WARN_UNUSED_FUNCTION = YES; 375 | GCC_WARN_UNUSED_VARIABLE = YES; 376 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 377 | MTL_ENABLE_DEBUG_INFO = NO; 378 | SDKROOT = iphoneos; 379 | SWIFT_COMPILATION_MODE = wholemodule; 380 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 381 | TARGETED_DEVICE_FAMILY = "1,2"; 382 | VALIDATE_PRODUCT = YES; 383 | }; 384 | name = Release; 385 | }; 386 | D95E1C541D88E71A00F94976 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | DEVELOPMENT_TEAM = ""; 391 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; 392 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 393 | LD_RUNPATH_SEARCH_PATHS = ( 394 | "$(inherited)", 395 | "@executable_path/Frameworks", 396 | ); 397 | PRODUCT_BUNDLE_IDENTIFIER = "net.phor.iOS-Example"; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | SWIFT_VERSION = 5.0; 400 | }; 401 | name = Debug; 402 | }; 403 | D95E1C551D88E71A00F94976 /* Release */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 407 | DEVELOPMENT_TEAM = ""; 408 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; 409 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 410 | LD_RUNPATH_SEARCH_PATHS = ( 411 | "$(inherited)", 412 | "@executable_path/Frameworks", 413 | ); 414 | PRODUCT_BUNDLE_IDENTIFIER = "net.phor.iOS-Example"; 415 | PRODUCT_NAME = "$(TARGET_NAME)"; 416 | SWIFT_VERSION = 5.0; 417 | }; 418 | name = Release; 419 | }; 420 | /* End XCBuildConfiguration section */ 421 | 422 | /* Begin XCConfigurationList section */ 423 | D95E1C3C1D88E71A00F94976 /* Build configuration list for PBXProject "iOS Example" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | D95E1C511D88E71A00F94976 /* Debug */, 427 | D95E1C521D88E71A00F94976 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | D95E1C531D88E71A00F94976 /* Build configuration list for PBXNativeTarget "iOS Example" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | D95E1C541D88E71A00F94976 /* Debug */, 436 | D95E1C551D88E71A00F94976 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | /* End XCConfigurationList section */ 442 | 443 | /* Begin XCSwiftPackageProductDependency section */ 444 | C4EEAC1C2385316D00177742 /* FDTake */ = { 445 | isa = XCSwiftPackageProductDependency; 446 | productName = FDTake; 447 | }; 448 | /* End XCSwiftPackageProductDependency section */ 449 | }; 450 | rootObject = D95E1C391D88E71A00F94976 /* Project object */; 451 | } 452 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcodeproj/xcshareddata/xcschemes/iOS Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /iOS Example/iOS Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------