├── gemfile ├── Resources └── boardingPass.gif ├── .swiftlint.yml ├── BoardingPass.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── mskiba.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── BoardingPass.xcscheme └── project.pbxproj ├── BoardingPass ├── Assets │ ├── BoardingPass.h │ └── Info.plist ├── HorizontalSlideAnimatedTransition.swift ├── BoardingInformation.swift ├── BoardingPassCompatibility.swift └── BoardingNavigationController.swift ├── BoardingPassTests ├── Assets │ └── Info.plist └── BoardingPassTests.swift ├── BoardingPassExample ├── App Delegate │ └── AppDelegate.swift ├── Onboarding Demo │ ├── Process View Controllers │ │ ├── SecondViewController.swift │ │ ├── ThirdViewController.swift │ │ ├── FirstViewController.swift │ │ └── ActionableViewController.swift │ ├── Completed View Controller │ │ └── CompletedViewController.swift │ └── OnboardingWrapperViewController.swift └── Assets │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Info.plist │ └── Base.lproj │ └── LaunchScreen.storyboard ├── BoardingPass.podspec ├── LICENSE ├── .travis.yml ├── .gitignore ├── Gemfile.lock ├── CONTRIBUTING.md └── README.md /gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'cocoapods', '~> 1.1' 4 | -------------------------------------------------------------------------------- /Resources/boardingPass.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rightpoint/BoardingPass/HEAD/Resources/boardingPass.gif -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | statement_position: 2 | statement_mode: uncuddled_else 3 | 4 | trailing_comma: 5 | mandatory_comma: true 6 | 7 | disabled_rules: 8 | - line_length 9 | -------------------------------------------------------------------------------- /BoardingPass.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BoardingPass/Assets/BoardingPass.h: -------------------------------------------------------------------------------- 1 | // 2 | // BoardingPass.h 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/19/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for BoardingPass. 12 | FOUNDATION_EXPORT double BoardingPassVersionNumber; 13 | 14 | //! Project version string for BoardingPass. 15 | FOUNDATION_EXPORT const unsigned char BoardingPassVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /BoardingPassTests/Assets/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /BoardingPassExample/App Delegate/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // BoardingPassExample 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | window = UIWindow(frame: UIScreen.main.bounds) 19 | 20 | window?.rootViewController = OnboardingNavigationViewController.sampleOnboarding() 21 | window?.makeKeyAndVisible() 22 | window?.tintColor = UIColor.red 23 | return true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/Process View Controllers/SecondViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BoardingPass 11 | 12 | class SecondViewController: ActionableViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | navigationItem.title = NSLocalizedString("Second", comment: "Second View controller title") 17 | } 18 | 19 | } 20 | 21 | extension SecondViewController: BackgroundColorProvider { 22 | 23 | var backgroundColor: UIColor { 24 | return UIColor(white: 0.5, alpha: 1) 25 | } 26 | 27 | var currentProgress: Progress { 28 | return Progress(completedUnitCount: 2, totalUnitCount: 4) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /BoardingPassTests/BoardingPassTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BoardingPassTests.swift 3 | // BoardingPassTests 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class BoardingPassTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | // Use XCTAssert and related functions to verify your tests produce the correct results. 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /BoardingPass/Assets/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.2.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/Process View Controllers/ThirdViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ThirdViewController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BoardingPass 11 | 12 | class ThirdViewController: ActionableViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | navigationItem.title = NSLocalizedString("Third", comment: "Third View controller title") 17 | } 18 | 19 | } 20 | 21 | extension ThirdViewController: BackgroundColorProvider { 22 | 23 | var backgroundColor: UIColor { 24 | return .lightGray 25 | } 26 | 27 | var currentProgress: Progress { 28 | return Progress(completedUnitCount: 3, totalUnitCount: 4) 29 | } 30 | 31 | } 32 | 33 | extension ThirdViewController: BoardingInformation { 34 | 35 | var nextViewController: UIViewController? { 36 | return CompletedViewController() 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /BoardingPass.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BoardingPass' 3 | s.version = '0.2.1' 4 | s.summary = 'A navigation controller interactive pan to push and pop.' 5 | 6 | s.description = <<-DESC 7 | BoardingPass is a subclass of `UINavigationController` with interactive push 8 | and pop gestures. It offers behaviors similar to `UIPageViewController`, 9 | but with all of the familiar behaviors of navigation controller, and the 10 | ability to add fancy effects by animating alongside transitions. 11 | DESC 12 | 13 | s.homepage = 'https://github.com/Raizlabs/BoardingPass' 14 | s.license = { :type => 'MIT', :file => 'LICENSE' } 15 | s.author = { 'Michael Skiba' => 'mike.skiba@raizlabs.com' } 16 | s.source = { :git => 'https://github.com/Raizlabs/BoardingPass.git', :tag => s.version.to_s } 17 | s.social_media_url = 'https://twitter.com/atelierclkwrk' 18 | 19 | s.ios.deployment_target = '9.0' 20 | 21 | s.source_files = 'BoardingPass/**/*' 22 | 23 | s.frameworks = 'Foundation', 'UIKit' 24 | 25 | end 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Raizlabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /BoardingPass.xcodeproj/xcuserdata/mskiba.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | BoardingPass.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | BoardingPassExample.xcscheme 13 | 14 | orderHint 15 | 2 16 | 17 | BoardingPassTests.xcscheme 18 | 19 | isShown 20 | 21 | orderHint 22 | 1 23 | 24 | 25 | SuppressBuildableAutocreation 26 | 27 | 72BE8D651D3EC55E005720FB 28 | 29 | primary 30 | 31 | 32 | 72BE8D741D3FBC05005720FB 33 | 34 | primary 35 | 36 | 37 | 72BE8D831D3FBCDE005720FB 38 | 39 | primary 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - LC_CTYPE=en_US.UTF-8 4 | 5 | branches: 6 | only: 7 | - develop 8 | - master 9 | 10 | os: osx 11 | language: objective-c 12 | matrix: 13 | exclude: 14 | - os: osx 15 | include: 16 | - osx_image: xcode8 17 | env: 18 | - XCODE_ACTION="clean test" 19 | XCODE_TOOLCHAIN="swift" 20 | XCODE_DESTINATION="platform=iOS Simulator,id=237D7619-4A4E-4624-8925-67A42A8A690A" 21 | - osx_image: xcode8 22 | env: 23 | - JOB=CARTHAGE 24 | script: 25 | - brew update 1> /dev/null 2> /dev/null 26 | - brew outdated carthage || brew upgrade carthage 27 | - carthage build --no-skip-current 28 | - test -d Carthage/Build/iOS/BoardingPass.framework || exit 1 29 | - osx_image: xcode8 30 | env: 31 | - JOB=COCOAPODS 32 | script: 33 | - bundle exec pod lib lint --sources="https://github.com/Raizlabs/BoardingPass" 34 | 35 | before_script: 36 | - killall "Simulator" || echo "No matching processes belonging to you were found" 37 | 38 | script: 39 | - travis_retry xcodebuild ${XCODE_ACTION} 40 | -toolchain ${XCODE_TOOLCHAIN} 41 | -project BoardingPass.xcodeproj 42 | -scheme BoardingPass 43 | -destination "${XCODE_DESTINATION}" 44 | -------------------------------------------------------------------------------- /BoardingPassExample/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /BoardingPassExample/Assets/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 | 0.2.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/Process View Controllers/FirstViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BoardingPass 11 | 12 | class FirstViewController: ActionableViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | navigationItem.title = NSLocalizedString("First", comment: "First View controller title") 17 | } 18 | 19 | } 20 | 21 | extension FirstViewController: BackgroundColorProvider { 22 | 23 | var backgroundColor: UIColor { 24 | return .darkGray 25 | } 26 | 27 | var currentProgress: Progress { 28 | return Progress(completedUnitCount: 1, totalUnitCount: 4) 29 | } 30 | 31 | } 32 | 33 | extension Progress { 34 | convenience init(completedUnitCount: Int64, totalUnitCount: Int64) { 35 | self.init(totalUnitCount: totalUnitCount) 36 | self.completedUnitCount = completedUnitCount 37 | } 38 | } 39 | 40 | extension UIButton { 41 | 42 | convenience init(title: String, font: UIFont) { 43 | self.init(type:.system) 44 | setTitle(title, for: UIControlState()) 45 | titleLabel?.font = font 46 | } 47 | 48 | } 49 | 50 | extension UIBarButtonItem { 51 | static var backButton: UIBarButtonItem { 52 | return UIBarButtonItem(title: NSLocalizedString("Back", comment: "generic back button title"), style: .plain, target: nil, action: nil) 53 | } 54 | 55 | static var skipButton: UIBarButtonItem { 56 | return UIBarButtonItem(title: NSLocalizedString("Skip", comment: "generic skip button title"), style: .plain, target: nil, action: nil) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /BoardingPassExample/Assets/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 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (2.3.5) 5 | activesupport (4.2.8) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | claide (1.0.1) 11 | cocoapods (1.2.0) 12 | activesupport (>= 4.0.2, < 5) 13 | claide (>= 1.0.1, < 2.0) 14 | cocoapods-core (= 1.2.0) 15 | cocoapods-deintegrate (>= 1.0.1, < 2.0) 16 | cocoapods-downloader (>= 1.1.3, < 2.0) 17 | cocoapods-plugins (>= 1.0.0, < 2.0) 18 | cocoapods-search (>= 1.0.0, < 2.0) 19 | cocoapods-stats (>= 1.0.0, < 2.0) 20 | cocoapods-trunk (>= 1.1.2, < 2.0) 21 | cocoapods-try (>= 1.1.0, < 2.0) 22 | colored (~> 1.2) 23 | escape (~> 0.0.4) 24 | fourflusher (~> 2.0.1) 25 | gh_inspector (~> 1.0) 26 | molinillo (~> 0.5.5) 27 | nap (~> 1.0) 28 | ruby-macho (~> 0.2.5) 29 | xcodeproj (>= 1.4.1, < 2.0) 30 | cocoapods-core (1.2.0) 31 | activesupport (>= 4.0.2, < 5) 32 | fuzzy_match (~> 2.0.4) 33 | nap (~> 1.0) 34 | cocoapods-deintegrate (1.0.1) 35 | cocoapods-downloader (1.1.3) 36 | cocoapods-plugins (1.0.0) 37 | nap 38 | cocoapods-search (1.0.0) 39 | cocoapods-stats (1.0.0) 40 | cocoapods-trunk (1.1.2) 41 | nap (>= 0.8, < 2.0) 42 | netrc (= 0.7.8) 43 | cocoapods-try (1.1.0) 44 | colored (1.2) 45 | escape (0.0.4) 46 | fourflusher (2.0.1) 47 | fuzzy_match (2.0.4) 48 | gh_inspector (1.0.3) 49 | i18n (0.8.1) 50 | minitest (5.10.1) 51 | molinillo (0.5.6) 52 | nanaimo (0.2.3) 53 | nap (1.1.0) 54 | netrc (0.7.8) 55 | ruby-macho (0.2.6) 56 | thread_safe (0.3.6) 57 | tzinfo (1.2.2) 58 | thread_safe (~> 0.1) 59 | xcodeproj (1.4.2) 60 | CFPropertyList (~> 2.3.3) 61 | activesupport (>= 3) 62 | claide (>= 1.0.1, < 2.0) 63 | colored (~> 1.2) 64 | nanaimo (~> 0.2.3) 65 | 66 | PLATFORMS 67 | ruby 68 | 69 | DEPENDENCIES 70 | cocoapods (~> 1.1) 71 | 72 | BUNDLED WITH 73 | 1.14.5 74 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/Completed View Controller/CompletedViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompletedViewController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BoardingPass 11 | 12 | class CompletedViewController: UIViewController { 13 | 14 | weak var onboardingDelegate: OnboardingViewControllerDelegate? 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | navigationItem.hidesBackButton = true 19 | navigationItem.title = NSLocalizedString("Completed", comment: "completed onboarding title") 20 | let resetButton = UIButton(title: NSLocalizedString("Reset", comment: "Reset button title"), font: .onboardingFont) 21 | resetButton.addTarget(self, action: #selector(handleResetTapped), for: .touchUpInside) 22 | view.addSubview(resetButton) 23 | let constraints: [NSLayoutConstraint] = [ 24 | resetButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), 25 | bottomLayoutGuide.topAnchor.constraint(equalTo: resetButton.bottomAnchor, constant: 10), 26 | ] 27 | resetButton.translatesAutoresizingMaskIntoConstraints = false 28 | NSLayoutConstraint.activate(constraints) 29 | } 30 | 31 | override func viewWillAppear(_ animated: Bool) { 32 | super.viewWillAppear(animated) 33 | let factory: AnimationFactory = { [unowned self] (_, _) in 34 | return self.animation 35 | } 36 | perform(coordinatedAnimations: factory) 37 | } 38 | } 39 | 40 | extension CompletedViewController: BackgroundColorProvider { 41 | 42 | var backgroundColor: UIColor { 43 | return .white 44 | } 45 | 46 | var currentProgress: Progress { 47 | return Progress(completedUnitCount: 4, totalUnitCount: 4) 48 | } 49 | 50 | } 51 | 52 | private extension CompletedViewController { 53 | @objc func handleResetTapped(_ sender: UIButton) { 54 | guard let origin = navigationController?.viewControllers.first else { 55 | return 56 | } 57 | _ = navigationController?.popToViewController(origin, animated: true) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/Process View Controllers/ActionableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActionableViewController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/27/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import BoardingPass 11 | 12 | class ActionableViewController: UIViewController { 13 | 14 | weak var onboardingDelegate: OnboardingViewControllerDelegate? 15 | 16 | override func viewDidLoad() { 17 | navigationItem.backBarButtonItem = UIBarButtonItem.backButton 18 | navigationItem.rightBarButtonItem = UIBarButtonItem.skipButton 19 | navigationItem.rightBarButtonItem?.target = self 20 | navigationItem.rightBarButtonItem?.action = #selector(handleSkipTapped) 21 | let nextButton = UIButton(title: NSLocalizedString("Next", comment: "Next button title"), font: .onboardingFont) 22 | nextButton.addTarget(self, action: #selector(handleNextTapped), for: .touchUpInside) 23 | view.addSubview(nextButton) 24 | let constraints: [NSLayoutConstraint] = [ 25 | nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), 26 | bottomLayoutGuide.topAnchor.constraint(equalTo: nextButton.bottomAnchor, constant: 10), 27 | ] 28 | nextButton.translatesAutoresizingMaskIntoConstraints = false 29 | NSLayoutConstraint.activate(constraints) 30 | } 31 | 32 | override func viewWillAppear(_ animated: Bool) { 33 | super.viewWillAppear(animated) 34 | let factory: AnimationFactory? 35 | if let backgroundColorProvider = self as? BackgroundColorProvider { 36 | factory = { [unowned backgroundColorProvider] (_, _) in 37 | return backgroundColorProvider.animation 38 | } 39 | } 40 | else { 41 | factory = nil 42 | } 43 | perform(coordinatedAnimations: factory) 44 | } 45 | } 46 | 47 | private extension ActionableViewController { 48 | @objc func handleNextTapped(_ sender: UIButton) { 49 | (navigationController as? BoardingNavigationController)?.pushToNextViewController(animated: true) 50 | } 51 | 52 | @objc func handleSkipTapped(_ sender: UIButton) { 53 | navigationController?.pushViewController(CompletedViewController(), animated: true) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /BoardingPass/HorizontalSlideAnimatedTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HorizontalSlideAnimatedTransition.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class HorizontalSlideAnimatedTransiton: NSObject { 12 | 13 | enum TransitionType { 14 | case push, pop 15 | } 16 | 17 | let slideType: TransitionType 18 | 19 | #if swift(>=3.0) 20 | 21 | /** 22 | Initializes a HorizontalSlideAnimatedTransiton for handling a pan gesture on a UINavigationController 23 | 24 | - parameter navigationOperation: The the navigation operation bieng animated 25 | */ 26 | public init(navigationOperation: UINavigationControllerOperation) { 27 | switch navigationOperation { 28 | case .none, .push: 29 | slideType = .push 30 | case .pop: 31 | slideType = .pop 32 | } 33 | super.init() 34 | } 35 | #else 36 | 37 | /** 38 | Initializes a HorizontalSlideAnimatedTransiton for handling a pan gesture on a UINavigationController 39 | 40 | - parameter navigationOperation: The the navigation operation bieng animated 41 | */ 42 | public init(navigationOperation: UINavigationControllerOperation) { 43 | switch navigationOperation { 44 | case .None, .Push: 45 | slideType = .push 46 | case .Pop: 47 | slideType = .pop 48 | } 49 | super.init() 50 | } 51 | #endif 52 | 53 | } 54 | 55 | extension HorizontalSlideAnimatedTransiton: UIViewControllerAnimatedTransitioning { 56 | 57 | public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 58 | 59 | guard let presented = transitionContext.viewController(forKey: UITransitionContextToViewControllerKey), 60 | let presenting = transitionContext.viewController(forKey: UITransitionContextFromViewControllerKey) else { 61 | transitionContext.completeTransition(false) 62 | return 63 | } 64 | 65 | // Optional for backward compatibility 66 | let container: UIView? = transitionContext.containerView 67 | 68 | container?.addSubview(presented.view) 69 | let width: CGFloat 70 | switch slideType { 71 | case .push: 72 | width = container?.frame.width ?? 0 73 | case .pop: 74 | width = -(container?.frame.width ?? 0) 75 | } 76 | presented.view.transform = CGAffineTransform(translationX: width, y: 0) 77 | let animations = { 78 | presenting.view.transform = CGAffineTransform(translationX: -width, y: 0) 79 | presented.view.transform = CGAffineTransform.identity 80 | } 81 | let completion = { (completed: Bool) in 82 | if completed { 83 | presented.view.transform = CGAffineTransform.identity 84 | } 85 | else { 86 | presenting.view.transform = CGAffineTransform.identity 87 | } 88 | transitionContext.completeTransition(completed) 89 | } 90 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, 91 | options: [.beginFromCurrentState], 92 | animations: animations, completion: completion) 93 | } 94 | 95 | public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 96 | return 0.4 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /BoardingPass.xcodeproj/xcshareddata/xcschemes/BoardingPass.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /BoardingPass/BoardingInformation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BoardingInformation.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol BoardingInformation { 12 | 13 | /// Used to determine the next view controller to push in the stack, a nil value means there is no next view, 14 | /// so no swipe left for next gesture will be allowed 15 | var nextViewController: UIViewController? { get } 16 | /// Used to determine the previous view controller to pop to, the default value of the previous view controller 17 | /// in the navigation stack. A nil value will explicitly disable the swipe right for previous view gesture. 18 | var previousViewController: UIViewController? { get } 19 | 20 | } 21 | 22 | #if swift(>=3.0) 23 | public typealias AnimationFactory = (_ container: UIViewController?, _ animated: Bool) -> (() -> Void) 24 | public typealias ContextualAnimation = (_ context: UIViewControllerTransitionCoordinatorContext) -> Void 25 | #else 26 | public typealias AnimationFactory = (UIViewController?, Bool) -> (() -> Void) 27 | public typealias ContextualAnimation = (UIViewControllerTransitionCoordinatorContext) -> Void 28 | #endif 29 | 30 | public extension UIViewController { 31 | 32 | /** 33 | A function for handling an animation that may or may not be performed alongside an animation context 34 | 35 | - parameter animation: A closure that takes a view controller and an animated flag and returns an animation block 36 | to perform perform, either alongside a context if one exists, with a fallback of applying 37 | it to the view 38 | - parameter completion: A closure that takes a view controller and an animated flag, and returns an animation block 39 | to perform alongside a context, with a fallback of applying it to the view 40 | - parameter cancellation: A cancellation action to handle restoration of any state that isn't properly rolled back 41 | if the animation block is cancelled 42 | */ 43 | final public func perform(coordinatedAnimations animation: AnimationFactory? = nil, 44 | completion: AnimationFactory? = nil, 45 | cancellation: ContextualAnimation? = nil) { 46 | let parentController = self.parent 47 | let animationInContext: ContextualAnimation = { (context: UIViewControllerTransitionCoordinatorContext) in 48 | animation?(parentController, context.isAnimated)() 49 | } 50 | let completionInContext = { (context: UIViewControllerTransitionCoordinatorContext) in 51 | if context.isCancelled { 52 | cancellation?(context) 53 | } 54 | else { 55 | completion?(parentController, context.isAnimated)() 56 | } 57 | } 58 | if let coordinator = transitionCoordinator { 59 | coordinator.animateAlongsideTransition(in: parent?.view, animation: animationInContext, completion: completionInContext) 60 | } 61 | else { 62 | animation?(parentController, false)() 63 | completion?(parentController, false)() 64 | } 65 | } 66 | } 67 | 68 | public extension BoardingInformation { 69 | 70 | var nextViewController: UIViewController? { 71 | return nil 72 | } 73 | var previousViewController: UIViewController? { 74 | guard let viewController = self as? UIViewController else { 75 | return nil 76 | } 77 | return viewController.navigationController?.viewController(beforeController: viewController) 78 | } 79 | 80 | var allowGestures: Bool { 81 | return true 82 | } 83 | 84 | } 85 | 86 | private extension UINavigationController { 87 | 88 | func viewController(beforeController viewController: UIViewController) -> UIViewController? { 89 | guard let index = viewControllers.index(of: viewController) else { 90 | return nil 91 | } 92 | guard index > 0 else { 93 | return nil 94 | } 95 | #if swift(>=3.0) 96 | return viewControllers[index.advanced(by: -1)] 97 | #else 98 | return viewControllers[index.predecessor()] 99 | #endif 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /BoardingPassExample/Onboarding Demo/OnboardingWrapperViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OnboardingNavigationViewController.swift 3 | // BoardingPassExample 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import BoardingPass 10 | 11 | extension UIFont { 12 | static let onboardingFont: UIFont = UIFont.systemFont(ofSize: 26.0) 13 | } 14 | 15 | protocol BackgroundColorProvider: class { 16 | 17 | weak var onboardingDelegate: OnboardingViewControllerDelegate? { get set } 18 | var backgroundColor: UIColor { get } 19 | var currentProgress: Progress { get } 20 | 21 | } 22 | 23 | extension BackgroundColorProvider { 24 | 25 | var animation: (() -> Void) { 26 | return { [unowned self] in 27 | self.onboardingDelegate?.backgroundColor = self.backgroundColor 28 | self.onboardingDelegate?.progress = self.currentProgress 29 | } 30 | } 31 | 32 | } 33 | 34 | protocol OnboardingViewControllerDelegate: class { 35 | 36 | var backgroundColor: UIColor? { get set } 37 | var progress: Progress { get set } 38 | 39 | } 40 | 41 | class OnboardingNavigationViewController: BoardingNavigationController, OnboardingViewControllerDelegate { 42 | 43 | // We're creating a non-standard progress slider because the UIProgressView 44 | // has a visual glitch when the animation is cancelled, probably due to 45 | // CALayer animations 46 | let progressSlider = UIView() 47 | var progress = Progress() { 48 | didSet { 49 | let progressAmount = CGFloat(progress.fractionCompleted) 50 | var newTransform = CGAffineTransform.identity 51 | newTransform = newTransform.translatedBy(x: (-view.frame.width + (view.frame.width * progressAmount)) / 2, y: 0) 52 | newTransform = newTransform.scaledBy(x: progressAmount, y: 1) 53 | progressSlider.transform = newTransform 54 | } 55 | } 56 | 57 | var backgroundColor: UIColor? { 58 | get { 59 | return view.backgroundColor 60 | } 61 | set { 62 | view.backgroundColor = newValue 63 | } 64 | } 65 | 66 | static func sampleOnboarding() -> BoardingNavigationController { 67 | let viewControllers = [ 68 | FirstViewController(), 69 | SecondViewController(), 70 | ThirdViewController(), 71 | ] 72 | let onboarding = OnboardingNavigationViewController(viewControllersToPresent: viewControllers) 73 | return onboarding 74 | } 75 | 76 | func beginOnboarding() { 77 | let viewControllers = [UIColor.red, UIColor.green, UIColor.blue].map { color -> UIViewController in 78 | let viewController = UIViewController() 79 | viewController.view.backgroundColor = color 80 | return viewController 81 | } 82 | let onboarding = BoardingNavigationController(viewControllersToPresent: viewControllers) 83 | present(onboarding, animated: true, completion: nil) 84 | } 85 | 86 | override func viewDidLoad() { 87 | super.viewDidLoad() 88 | navigationBar.addSubview(progressSlider) 89 | progressSlider.frame.size.height = 4 90 | progressSlider.frame.size.width = navigationBar.frame.width 91 | progressSlider.frame.origin.x = navigationBar.frame.origin.x 92 | progressSlider.frame.origin.y = navigationBar.frame.maxY - progressSlider.frame.height 93 | progressSlider.backgroundColor = .red 94 | view.backgroundColor = UIColor.white 95 | } 96 | 97 | override func pushViewController(_ viewController: UIViewController, animated: Bool) { 98 | super.pushViewController(viewController, animated: animated) 99 | (viewController as? BackgroundColorProvider)?.onboardingDelegate = self 100 | } 101 | 102 | override func popViewController(animated: Bool) -> UIViewController? { 103 | let viewController = super.popViewController(animated: animated) 104 | (viewController as? BackgroundColorProvider)?.onboardingDelegate = self 105 | return viewController 106 | } 107 | 108 | override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? { 109 | let poppedViewControllers = super.popToViewController(viewController, animated: animated) 110 | (viewController as? BackgroundColorProvider)?.onboardingDelegate = self 111 | return poppedViewControllers 112 | } 113 | 114 | override func setViewControllers(_ viewControllers: [UIViewController], animated: Bool) { 115 | super.setViewControllers(viewControllers, animated: animated) 116 | for viewController in viewControllers { 117 | (viewController as? BackgroundColorProvider)?.onboardingDelegate = self 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /BoardingPass/BoardingPassCompatibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BoardingPassCompatibility.swift 3 | // BoardingPass 4 | // 5 | // Created by Adam Tierney on 9/19/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | #if swift(>=3.0) 12 | 13 | let UITransitionContextToViewControllerKey: UITransitionContextViewControllerKey = UITransitionContextViewControllerKey.to 14 | let UITransitionContextFromViewControllerKey: UITransitionContextViewControllerKey = UITransitionContextViewControllerKey.from 15 | 16 | #else 17 | 18 | extension UIViewController { 19 | @nonobjc var parent: UIViewController? { 20 | return parentViewController 21 | } 22 | 23 | @nonobjc var transitionCoordinator: UIViewControllerTransitionCoordinator? { 24 | return transitionCoordinator() 25 | } 26 | } 27 | 28 | // MARK: - Animations 29 | 30 | extension UIViewAnimationOptions { 31 | @nonobjc static var beginFromCurrentState = UIViewAnimationOptions.BeginFromCurrentState 32 | } 33 | 34 | extension UIView { 35 | @nonobjc class func animate(withDuration duration: NSTimeInterval, delay: NSTimeInterval, options: UIViewAnimationOptions, animations: () -> Void, completion: ((Bool) -> Void)?) { 36 | animateWithDuration(duration, delay: delay, options: options, animations: animations, completion: completion) 37 | } 38 | } 39 | 40 | // MARK: - Transitions 41 | 42 | extension UIViewControllerContextTransitioning { 43 | 44 | func viewController(forKey key: String) -> UIViewController? { 45 | return viewControllerForKey(key) 46 | } 47 | 48 | var containerView: UIView? { 49 | return containerView() 50 | } 51 | } 52 | 53 | public typealias TimeInterval = NSTimeInterval 54 | extension HorizontalSlideAnimatedTransiton { 55 | 56 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 57 | animateTransition(using: transitionContext) 58 | } 59 | 60 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 61 | return transitionDuration(using: transitionContext) 62 | } 63 | 64 | } 65 | 66 | extension UIViewControllerTransitionCoordinator { 67 | func animateAlongsideTransition(in view: UIView?, 68 | animation theAnimation: ( (UIViewControllerTransitionCoordinatorContext) -> Void)?, 69 | completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool { 70 | return animateAlongsideTransitionInView(view, animation: theAnimation, completion: completion) 71 | } 72 | } 73 | 74 | extension UIViewControllerTransitionCoordinatorContext { 75 | @nonobjc var isAnimated: Bool { 76 | return isAnimated() 77 | } 78 | 79 | @nonobjc var isCancelled: Bool { 80 | return isCancelled() 81 | } 82 | } 83 | 84 | extension UIPercentDrivenInteractiveTransition { 85 | @nonobjc func cancel() { 86 | cancelInteractiveTransition() 87 | } 88 | 89 | @nonobjc func update(percentComplete: CGFloat) { 90 | updateInteractiveTransition(percentComplete) 91 | } 92 | 93 | @nonobjc func finish() { 94 | finishInteractiveTransition() 95 | } 96 | } 97 | 98 | extension UIPanGestureRecognizer { 99 | @nonobjc var isEnabled: Bool { 100 | set(newVal) { 101 | enabled = newVal 102 | } 103 | get { 104 | return enabled 105 | } 106 | } 107 | 108 | @nonobjc func translation(in view: UIView?) -> CGPoint { 109 | return translationInView(view) 110 | } 111 | 112 | @nonobjc func velocity(in view: UIView?) -> CGPoint { 113 | return velocityInView(view) 114 | } 115 | } 116 | 117 | // MARK: - Transform 118 | 119 | extension CGAffineTransform { 120 | @nonobjc static let identity: CGAffineTransform = CGAffineTransformIdentity 121 | 122 | init(translationX: CGFloat, y: CGFloat) { 123 | self = CGAffineTransformMakeTranslation(translationX, y) 124 | } 125 | } 126 | 127 | // MARK: - Dispatch 128 | 129 | struct DispatchQueue { 130 | @nonobjc static var main = DispatchQueue() 131 | func async(work: () -> Swift.Void) { 132 | dispatch_async(dispatch_get_main_queue(), { 133 | work() 134 | }) 135 | } 136 | } 137 | 138 | // MARK: - Array 139 | 140 | extension Array where Element: Equatable { 141 | 142 | func index(of element: Element) -> Int? { 143 | return indexOf(element) 144 | } 145 | 146 | mutating func insert(newElement: Element, at: Int) { 147 | insert(newElement, atIndex: at) 148 | } 149 | 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BoardingPass 2 | > Navigate Your View Stack with Interactive Swipe Gestures 3 | 4 | [![Build Status](https://travis-ci.org/Raizlabs/BoardingPass.svg?branch=develop)](https://travis-ci.org/Raizlabs/BoardingPass) 5 | [![Version](https://img.shields.io/cocoapods/v/BoardingPass.svg?style=flat)](http://cocoapods.org/pods/BoardingPass) 6 | [![License](https://img.shields.io/cocoapods/l/BoardingPass.svg?style=flat)](http://cocoapods.org/pods/BoardingPass) 7 | [![Platform](https://img.shields.io/cocoapods/p/BoardingPass.svg?style=flat)](http://cocoapods.org/pods/BoardingPass) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | 10 | BoardingPass is a subclass of `UINavigationController` with interactive push and pop gestures. It offers behaviors similar to `UIPageViewController`, but with all of the familiar behaviors of navigation controllers, and the ability to easily animate property changes alongside the transitions. 11 | 12 | ![BoardingPass](Resources/boardingPass.gif) 13 | 14 | ## Features 15 | 16 | - [x] Interactive swipe and pan transitions 17 | - [x] Navigation Controller push and pop use slide animation as well 18 | - [x] Supports animating other properties alongside the transition 19 | - [x] Fine grained control over when the push and pop gestures should be active. 20 | 21 | ## Requirements 22 | 23 | - iOS 9.0+ 24 | - Xcode 8.0+ 25 | 26 | ## Installation with CocoaPods 27 | 28 | BoardingPass is available through [CocoaPods](http://cocoapods.org). To install 29 | it, simply add the following line to your Podfile: 30 | 31 | ```ruby 32 | pod 'BoardingPass' 33 | ``` 34 | 35 | ## Installation with Carthage 36 | Create a `Cartfile` that lists the framework and run `carthage update`. Follow the [instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios) to add `$(SRCROOT)/Carthage/Build/iOS/BoardingPass.framework` to an iOS project. 37 | 38 | ```ogdl 39 | github "Raizlabs/BoardingPass" 40 | ``` 41 | 42 | #### Manually 43 | 1. Download all of the `.swift` files in `BoardingPass/` and drop them into your project. 44 | 2. Congratulations! 45 | 46 | ## Usage example 47 | 48 | To see a complete example of using the gallery, take a look at the [sample project](https://github.com/Raizlabs/BoardingPass/blob/develop/BoardingPassExample/Onboarding%20Demo/OnboardingWrapperViewController.swift). 49 | 50 | ### Simple Boarding 51 | 52 | At it's simplest, a `BoardingNavigationController` can be initialized with an array of view controllers, and that will allow the user to swipe forward and backward through the navigation stack. 53 | 54 | ```swift 55 | func beginOnboarding() { 56 | let viewControllers = [ 57 | FirstViewController(), 58 | SecondViewController(), 59 | ThirdViewController(), 60 | ] 61 | let onboarding = BoardingNavigationController(viewControllersToPresent: viewControllers) 62 | present(onboarding, animated: true, completion: nil) 63 | } 64 | ``` 65 | 66 | ### Controlling Navigation 67 | 68 | For finer grained control over navigation, for instance to now allow the user to page backward after viewing the complete boarding stack, a view controller can conform to the `BoardingInformation` protocol and set a value for `nextViewController` or `previousViewController`. 69 | 70 | ```swift 71 | extension ThirdViewController: BoardingInformation { 72 | 73 | var nextViewController: UIViewController? { 74 | let completed = CompletedViewController() 75 | return completed 76 | } 77 | 78 | } 79 | ``` 80 | 81 | By returning a view controller outside of the series of view controllers to present, the `BoardingNavigationController` will disable the swipe gestures once the user advances to the `CompletedViewController`. 82 | 83 | ### Going Above and Beyond 84 | 85 | To give the boarding stack a more custom look and feel, `BoadingPass` is designed to make it easy to add animations that run alongside the push and pop presentations. To add a progress slider and a background color alongside navigation animations. 86 | 87 | The first step is defining a protocol that each of the presented view controllers is going to conform to, and a delegate protocol that the BoardingInformation subclass is going to conform to to allow the view controllers to communicate back up to the container. 88 | 89 | ```swift 90 | protocol BackgroundColorProvider: class { 91 | 92 | weak var onboardingDelegate: OnboardingViewControllerDelegate? { get set } 93 | var backgroundColor: UIColor { get } 94 | var currentProgress: Progress { get } 95 | 96 | } 97 | ``` 98 | 99 | ```swift 100 | protocol OnboardingViewControllerDelegate: class { 101 | 102 | var backgroundColor: UIColor? { get set } 103 | var progress: Progress { get set } 104 | 105 | } 106 | ``` 107 | 108 | Next the `BackgroundColorProvider` can be extended to create a shared function the generate closure to animate the background color and progress indicator. 109 | 110 | ``` 111 | extension BackgroundColorProvider { 112 | 113 | var animation: (() -> Void) { 114 | return { [unowned self] in 115 | self.onboardingDelegate?.backgroundColor = self.backgroundColor 116 | self.onboardingDelegate?.progress = self.currentProgress 117 | } 118 | } 119 | 120 | } 121 | ``` 122 | 123 | Then each class implementing `BackgroundColorProvider` needs to add a method to `viewWillAppear` to perform the coordinated animation alongside the current context, with a fallback of executing the animation if there is no context. 124 | 125 | ```swift 126 | override func viewWillAppear(_ animated: Bool) { 127 | super.viewWillAppear(animated) 128 | let factory: AnimationFactory = { [unowned self] (_, _) in 129 | return self.animation 130 | } 131 | perform(coordinatedAnimations: factory) 132 | } 133 | ``` 134 | 135 | ## Contributing 136 | 137 | Issues and pull requests are welcome! Please ensure that you have the latest [SwiftLint](https://github.com/realm/SwiftLint) installed before committing and that there are no style warnings generated when building. 138 | 139 | Contributors are expected to abide by the [Contributor Covenant Code of Conduct](https://github.com/Raizlabs/BoardingPass/blob/develop/CONTRIBUTING.md). 140 | 141 | ## License 142 | 143 | BoardingPass is available under the MIT license. See the LICENSE file for more info. 144 | 145 | ## Author 146 | 147 | Michael Skiba, [@atelierclkwrk](https://twitter.com/atelierclkwrk) 148 | -------------------------------------------------------------------------------- /BoardingPass/BoardingNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BoardingNavigationController.swift 3 | // BoardingPass 4 | // 5 | // Created by Michael Skiba on 7/20/16. 6 | // Copyright © 2016 Raizlabs. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TransitionState { 12 | enum Direction { 13 | case push 14 | case pop 15 | case none 16 | } 17 | 18 | var direction: Direction = .none 19 | var previousState: [UIViewController]? 20 | 21 | init(direction: Direction, previousState: [UIViewController]) { 22 | self.direction = direction 23 | self.previousState = previousState 24 | } 25 | 26 | init() { 27 | direction = .none 28 | previousState = nil 29 | } 30 | } 31 | 32 | // MARK: - Core 33 | 34 | #if swift(>=3.0) 35 | 36 | open class BoardingNavigationController: UINavigationController { 37 | 38 | let panGestureRecognizer = UIPanGestureRecognizer() 39 | var transitionState = TransitionState() 40 | var interactionController: UIPercentDrivenInteractiveTransition? 41 | 42 | /// An array of view controllers used to determine the next or previous view 43 | /// controller to present in the series. These are ignored if the top view 44 | /// controller conforms to `BoardingInformation` 45 | open var viewControllersToPresent: [UIViewController] = [] 46 | 47 | /** 48 | An optional closure that takes a `UINavigationControllerOperation` and returns a 49 | `UIViewControllerAnimatedTransitioning` object. Used to allow customization of 50 | the animation. The default value is `HorizontalSlideAnimatedTransiton.init`. 51 | Setting this value to `nil` will default to the standard navigation controller 52 | animation. 53 | */ 54 | open var animatedTransitioningProvider: ((UINavigationControllerOperation) -> UIViewControllerAnimatedTransitioning)? = HorizontalSlideAnimatedTransiton.init 55 | 56 | open override func viewDidLoad() { 57 | super.viewDidLoad() 58 | delegate = self 59 | configure(gestureRecognizer: panGestureRecognizer, action: #selector(handlePan)) 60 | } 61 | } 62 | 63 | #else 64 | 65 | public class BoardingNavigationController: UINavigationController { 66 | 67 | let panGestureRecognizer = UIPanGestureRecognizer() 68 | var transitionState = TransitionState() 69 | var interactionController: UIPercentDrivenInteractiveTransition? 70 | 71 | /// An array of view controllers used to determine the next or previous view 72 | /// controller to present in the series. These are ignored if the top view 73 | /// controller conforms to `BoardingInformation` 74 | public var viewControllersToPresent: [UIViewController] = [] 75 | 76 | /** 77 | An optional closure that takes a `UINavigationControllerOperation` and returns a 78 | `UIViewControllerAnimatedTransitioning` object. Used to allow customization of 79 | the animation. The default value is `HorizontalSlideAnimatedTransiton.init`. 80 | Setting this value to `nil` will default to the standard navigation controller 81 | animation. 82 | */ 83 | public var animatedTransitioningProvider: ((UINavigationControllerOperation) -> UIViewControllerAnimatedTransitioning)? = HorizontalSlideAnimatedTransiton.init 84 | 85 | public override func viewDidLoad() { 86 | super.viewDidLoad() 87 | delegate = self 88 | configure(gestureRecognizer: panGestureRecognizer, action: #selector(handlePan)) 89 | } 90 | } 91 | 92 | #endif 93 | 94 | // MARK: - Navigation Delegate 95 | 96 | #if swift(>=3.0) 97 | 98 | extension BoardingNavigationController: UINavigationControllerDelegate { 99 | 100 | public func navigationController(_ navigationController: UINavigationController, 101 | animationControllerFor operation: UINavigationControllerOperation, 102 | from fromVC: UIViewController, 103 | to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 104 | return animatedTransitioningProvider?(operation) 105 | } 106 | 107 | public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 108 | return interactionController 109 | } 110 | } 111 | 112 | #else 113 | 114 | extension BoardingNavigationController: UINavigationControllerDelegate { 115 | public func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 116 | return animatedTransitioningProvider?(operation) 117 | } 118 | 119 | public func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 120 | return interactionController 121 | } 122 | } 123 | 124 | #endif 125 | 126 | public extension BoardingNavigationController { 127 | /** 128 | Initializes the `BoardingNavigationController` with a populated array of 129 | view controllers to present. If the array is non-empty then it also sets 130 | the root view controller to the first element in the array. 131 | 132 | - parameter viewControllersToPresent: The array of view controllers to use 133 | as default navigation options. 134 | */ 135 | public convenience init(viewControllersToPresent: [UIViewController]) { 136 | if let firstViewController = viewControllersToPresent.first { 137 | self.init(rootViewController: firstViewController) 138 | } 139 | else { 140 | self.init() 141 | } 142 | self.viewControllersToPresent = viewControllersToPresent 143 | } 144 | 145 | /** 146 | Pushes the next view controller in boarding pass stack if one exists. 147 | 148 | - parameter animated: Specify true to animate the transition or false 149 | if you do not want the transition to be animated. 150 | */ 151 | public func pushToNextViewController(animated isAnimated: Bool) { 152 | if let pushableViewController = topViewController.flatMap(boardingInfo(afterController:)) { 153 | pushViewController(pushableViewController, animated: isAnimated) 154 | } 155 | } 156 | 157 | /** 158 | Pops to the previous view controller in the boarding pass stack if one exists. 159 | 160 | - parameter animated: Specify true to animate the transition or false 161 | if you do not want the transition to be animated. 162 | */ 163 | public func popToPreviousViewController(animated isAnimated: Bool) { 164 | if let poppableViewController = topViewController.flatMap(boardingInfo(afterController:)) { 165 | popToAndInsertIfNeeded(poppableViewController, animated: isAnimated) 166 | } 167 | } 168 | } 169 | 170 | // MARK: - Extensions 171 | 172 | // MARK: Actions 173 | private extension BoardingNavigationController { 174 | 175 | #if swift(>=3.0) 176 | func popToAndInsertIfNeeded(_ viewController: UIViewController, animated: Bool) { 177 | if !viewControllers.contains(viewController) { 178 | if viewControllers.count > 1 { 179 | viewControllers.insert(viewController, 180 | at: ((viewControllers.endIndex - 1) - 1)) 181 | } 182 | else { 183 | viewControllers.insert(viewController, at: viewControllers.startIndex) 184 | } 185 | } 186 | popToViewController(viewController, animated: animated) 187 | } 188 | #else 189 | func popToAndInsertIfNeeded(viewController: UIViewController, animated: Bool) { 190 | if !viewControllers.contains(viewController) { 191 | if viewControllers.count > 1 { 192 | viewControllers.insert(viewController, 193 | at: ((viewControllers.endIndex - 1) - 1)) 194 | } 195 | else { 196 | viewControllers.insert(viewController, at: viewControllers.startIndex) 197 | } 198 | } 199 | popToViewController(viewController, animated: animated) 200 | } 201 | #endif 202 | 203 | #if swift(>=3.0) 204 | @objc func handlePan(from sender: UIPanGestureRecognizer) { 205 | switch sender.state { 206 | case .began, .possible: 207 | break 208 | case .changed: 209 | updateAnimation(forRecognizer: sender) 210 | case .ended, .failed, .cancelled: 211 | finishAnimation(forRecognizer: sender) 212 | } 213 | } 214 | #else 215 | @objc func handlePan(from sender: UIPanGestureRecognizer) { 216 | switch sender.state { 217 | case .Began, .Possible: 218 | break 219 | case .Changed: 220 | updateAnimation(forRecognizer: sender) 221 | case .Ended, .Failed, .Cancelled: 222 | finishAnimation(forRecognizer: sender) 223 | } 224 | } 225 | #endif 226 | } 227 | 228 | private extension BoardingNavigationController { 229 | 230 | func viewController(before viewController: UIViewController?) -> UIViewController? { 231 | guard let vc = viewController else { 232 | return nil 233 | } 234 | guard let index = viewControllersToPresent.index(of: vc) else { 235 | return nil 236 | } 237 | guard index > 0 else { 238 | return nil 239 | } 240 | 241 | return viewControllersToPresent[(index - 1)] 242 | } 243 | 244 | func viewController(after viewController: UIViewController?) -> UIViewController? { 245 | guard let vc = viewController else { 246 | return nil 247 | } 248 | guard let index = ((viewControllersToPresent.index(of: vc))) else { 249 | return nil 250 | } 251 | 252 | let adjustedIndex = index + 1 253 | 254 | guard adjustedIndex < viewControllersToPresent.count else { 255 | return nil 256 | } 257 | 258 | return viewControllersToPresent[adjustedIndex] 259 | } 260 | 261 | func updateAnimation(forRecognizer recognizer: UIPanGestureRecognizer) { 262 | let xTranslation = recognizer.translation(in: view).x 263 | let percent = xTranslation / view.frame.width 264 | if (percent < 0 && transitionState.direction == .pop) || 265 | (percent > 0 && transitionState.direction == .push) { 266 | return 267 | } 268 | if (percent > 0.66 && transitionState.direction == .pop) || 269 | (percent < -0.66 && transitionState.direction == .push) { 270 | recognizer.isEnabled = false 271 | return 272 | } 273 | if interactionController == nil { 274 | interactionController = UIPercentDrivenInteractiveTransition() 275 | } 276 | // The transitioning delegate being nil tells us that there isn't another active transition in play 277 | if transitionState.direction == .none && transitioningDelegate == nil { 278 | if xTranslation < 0 { 279 | guard let pushableViewControler = topViewController.flatMap(boardingInfo(afterController:)) else { 280 | return 281 | } 282 | transitionState = TransitionState(direction: .push, previousState: viewControllers) 283 | pushViewController(pushableViewControler, animated: true) 284 | } 285 | else if xTranslation > 0 { 286 | guard let poppableViewController = topViewController.flatMap(boardingInfo(beforeController:)) else { 287 | return 288 | } 289 | transitionState = TransitionState(direction: .pop, previousState: viewControllers) 290 | popToAndInsertIfNeeded(poppableViewController, animated: true) 291 | } 292 | } 293 | interactionController?.update(abs(percent)) 294 | } 295 | 296 | func boardingInfo(beforeController viewController: UIViewController) -> UIViewController? { 297 | let poppableViewController: UIViewController? 298 | if let boardingViewController = viewController as? BoardingInformation { 299 | poppableViewController = boardingViewController.previousViewController 300 | } 301 | else { 302 | poppableViewController = self.viewController(before: viewController) 303 | } 304 | return poppableViewController 305 | } 306 | 307 | func boardingInfo(afterController viewController: UIViewController) -> UIViewController? { 308 | let pushableViewControler: UIViewController? 309 | if let boardingViewController = viewController as? BoardingInformation { 310 | pushableViewControler = boardingViewController.nextViewController 311 | } 312 | else { 313 | pushableViewControler = self.viewController(after: viewController) 314 | } 315 | return pushableViewControler 316 | } 317 | 318 | func finishAnimation(forRecognizer recognizer: UIPanGestureRecognizer) { 319 | recognizer.isEnabled = true 320 | let rawVelocity = recognizer.velocity(in: view).x 321 | let velocityPercentPerSecond: CGFloat 322 | switch transitionState.direction { 323 | case .pop: 324 | velocityPercentPerSecond = rawVelocity / view.frame.width 325 | case .push: 326 | velocityPercentPerSecond = -rawVelocity / view.frame.width 327 | case .none: 328 | velocityPercentPerSecond = 0 329 | } 330 | let percentComplete = interactionController?.percentComplete ?? 0 331 | if percentComplete > 0.5 || percentComplete + velocityPercentPerSecond > 0.75 { 332 | interactionController?.finish() 333 | interactionController = nil 334 | transitionState = TransitionState() 335 | } 336 | else { 337 | cleanUpAnimation() 338 | } 339 | } 340 | 341 | func cleanUpAnimation() { 342 | interactionController?.cancel() 343 | if let previousState = transitionState.previousState { 344 | viewControllers = previousState 345 | } 346 | interactionController = nil 347 | DispatchQueue.main.async { 348 | self.transitionState = TransitionState() 349 | } 350 | } 351 | 352 | func configure(gestureRecognizer recognizer: UIGestureRecognizer, action: Selector) { 353 | recognizer.addTarget(self, action: action) 354 | view.addGestureRecognizer(recognizer) 355 | } 356 | } 357 | 358 | private extension UISwipeGestureRecognizer { 359 | convenience init(direction: UISwipeGestureRecognizerDirection) { 360 | self.init() 361 | self.direction = direction 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /BoardingPass.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 23A09E271D908D05004A9ADF /* BoardingPassCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A09E261D908D05004A9ADF /* BoardingPassCompatibility.swift */; }; 11 | 7264CA211D3FC4AB00033FC4 /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA201D3FC4AB00033FC4 /* FirstViewController.swift */; }; 12 | 7264CA231D3FC4B300033FC4 /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA221D3FC4B300033FC4 /* SecondViewController.swift */; }; 13 | 7264CA251D3FC4B900033FC4 /* ThirdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA241D3FC4B900033FC4 /* ThirdViewController.swift */; }; 14 | 7264CA261D3FC54A00033FC4 /* BoardingPass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72BE8D661D3EC55E005720FB /* BoardingPass.framework */; }; 15 | 7264CA271D3FC54A00033FC4 /* BoardingPass.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 72BE8D661D3EC55E005720FB /* BoardingPass.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 7264CA2C1D3FC69800033FC4 /* BoardingNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA2B1D3FC69800033FC4 /* BoardingNavigationController.swift */; }; 17 | 7264CA2E1D3FEB2A00033FC4 /* BoardingInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA2D1D3FEB2A00033FC4 /* BoardingInformation.swift */; }; 18 | 7264CA331D3FEC4C00033FC4 /* CompletedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA321D3FEC4C00033FC4 /* CompletedViewController.swift */; }; 19 | 7264CA351D4001BD00033FC4 /* HorizontalSlideAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7264CA341D4001BD00033FC4 /* HorizontalSlideAnimatedTransition.swift */; }; 20 | 72BE8D6A1D3EC55E005720FB /* BoardingPass.h in Headers */ = {isa = PBXBuildFile; fileRef = 72BE8D691D3EC55E005720FB /* BoardingPass.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | 72BE8D781D3FBC05005720FB /* BoardingPassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72BE8D771D3FBC05005720FB /* BoardingPassTests.swift */; }; 22 | 72BE8D7A1D3FBC05005720FB /* BoardingPass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72BE8D661D3EC55E005720FB /* BoardingPass.framework */; }; 23 | 72BE8D871D3FBCDE005720FB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72BE8D861D3FBCDE005720FB /* AppDelegate.swift */; }; 24 | 72BE8D891D3FBCDE005720FB /* OnboardingWrapperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72BE8D881D3FBCDE005720FB /* OnboardingWrapperViewController.swift */; }; 25 | 72BE8D8E1D3FBCDE005720FB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 72BE8D8D1D3FBCDE005720FB /* Assets.xcassets */; }; 26 | 72BE8D911D3FBCDE005720FB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 72BE8D8F1D3FBCDE005720FB /* LaunchScreen.storyboard */; }; 27 | 72F163451D4910D1007D983B /* ActionableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72F163441D4910D1007D983B /* ActionableViewController.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 7264CA281D3FC54A00033FC4 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 72BE8D5D1D3EC55E005720FB /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 72BE8D651D3EC55E005720FB; 36 | remoteInfo = BoardingPass; 37 | }; 38 | 72BE8D7B1D3FBC05005720FB /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = 72BE8D5D1D3EC55E005720FB /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = 72BE8D651D3EC55E005720FB; 43 | remoteInfo = BoardingPass; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXCopyFilesBuildPhase section */ 48 | 7264CA2A1D3FC54A00033FC4 /* Embed Frameworks */ = { 49 | isa = PBXCopyFilesBuildPhase; 50 | buildActionMask = 2147483647; 51 | dstPath = ""; 52 | dstSubfolderSpec = 10; 53 | files = ( 54 | 7264CA271D3FC54A00033FC4 /* BoardingPass.framework in Embed Frameworks */, 55 | ); 56 | name = "Embed Frameworks"; 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | 23A09E261D908D05004A9ADF /* BoardingPassCompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardingPassCompatibility.swift; sourceTree = ""; }; 63 | 7264CA201D3FC4AB00033FC4 /* FirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; }; 64 | 7264CA221D3FC4B300033FC4 /* SecondViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; }; 65 | 7264CA241D3FC4B900033FC4 /* ThirdViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdViewController.swift; sourceTree = ""; }; 66 | 7264CA2B1D3FC69800033FC4 /* BoardingNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardingNavigationController.swift; sourceTree = ""; }; 67 | 7264CA2D1D3FEB2A00033FC4 /* BoardingInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardingInformation.swift; sourceTree = ""; }; 68 | 7264CA321D3FEC4C00033FC4 /* CompletedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompletedViewController.swift; sourceTree = ""; }; 69 | 7264CA341D4001BD00033FC4 /* HorizontalSlideAnimatedTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalSlideAnimatedTransition.swift; sourceTree = ""; }; 70 | 72BE8D661D3EC55E005720FB /* BoardingPass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoardingPass.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | 72BE8D691D3EC55E005720FB /* BoardingPass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BoardingPass.h; sourceTree = ""; }; 72 | 72BE8D6B1D3EC55E005720FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 72BE8D751D3FBC05005720FB /* BoardingPassTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BoardingPassTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 72BE8D771D3FBC05005720FB /* BoardingPassTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoardingPassTests.swift; sourceTree = ""; }; 75 | 72BE8D791D3FBC05005720FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 72BE8D841D3FBCDE005720FB /* BoardingPassExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BoardingPassExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 72BE8D861D3FBCDE005720FB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 78 | 72BE8D881D3FBCDE005720FB /* OnboardingWrapperViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingWrapperViewController.swift; sourceTree = ""; }; 79 | 72BE8D8D1D3FBCDE005720FB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 80 | 72BE8D901D3FBCDE005720FB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 81 | 72BE8D921D3FBCDE005720FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 72F163441D4910D1007D983B /* ActionableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionableViewController.swift; sourceTree = ""; }; 83 | /* End PBXFileReference section */ 84 | 85 | /* Begin PBXFrameworksBuildPhase section */ 86 | 72BE8D621D3EC55E005720FB /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | 72BE8D721D3FBC05005720FB /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | 72BE8D7A1D3FBC05005720FB /* BoardingPass.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 72BE8D811D3FBCDE005720FB /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | 7264CA261D3FC54A00033FC4 /* BoardingPass.framework in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | /* End PBXFrameworksBuildPhase section */ 110 | 111 | /* Begin PBXGroup section */ 112 | 7264CA301D3FEC2A00033FC4 /* Process View Controllers */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 7264CA201D3FC4AB00033FC4 /* FirstViewController.swift */, 116 | 7264CA221D3FC4B300033FC4 /* SecondViewController.swift */, 117 | 7264CA241D3FC4B900033FC4 /* ThirdViewController.swift */, 118 | 72F163441D4910D1007D983B /* ActionableViewController.swift */, 119 | ); 120 | path = "Process View Controllers"; 121 | sourceTree = ""; 122 | }; 123 | 7264CA311D3FEC4000033FC4 /* Completed View Controller */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 7264CA321D3FEC4C00033FC4 /* CompletedViewController.swift */, 127 | ); 128 | path = "Completed View Controller"; 129 | sourceTree = ""; 130 | }; 131 | 72BE8D5C1D3EC55E005720FB = { 132 | isa = PBXGroup; 133 | children = ( 134 | 72BE8D681D3EC55E005720FB /* BoardingPass */, 135 | 72BE8D851D3FBCDE005720FB /* BoardingPassExample */, 136 | 72BE8D761D3FBC05005720FB /* BoardingPassTests */, 137 | 72BE8D671D3EC55E005720FB /* Products */, 138 | ); 139 | sourceTree = ""; 140 | }; 141 | 72BE8D671D3EC55E005720FB /* Products */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 72BE8D661D3EC55E005720FB /* BoardingPass.framework */, 145 | 72BE8D751D3FBC05005720FB /* BoardingPassTests.xctest */, 146 | 72BE8D841D3FBCDE005720FB /* BoardingPassExample.app */, 147 | ); 148 | name = Products; 149 | sourceTree = ""; 150 | }; 151 | 72BE8D681D3EC55E005720FB /* BoardingPass */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 72BE8D981D3FBD0C005720FB /* Assets */, 155 | 7264CA2D1D3FEB2A00033FC4 /* BoardingInformation.swift */, 156 | 7264CA2B1D3FC69800033FC4 /* BoardingNavigationController.swift */, 157 | 7264CA341D4001BD00033FC4 /* HorizontalSlideAnimatedTransition.swift */, 158 | 23A09E261D908D05004A9ADF /* BoardingPassCompatibility.swift */, 159 | ); 160 | path = BoardingPass; 161 | sourceTree = ""; 162 | }; 163 | 72BE8D761D3FBC05005720FB /* BoardingPassTests */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 72BE8D971D3FBD00005720FB /* Assets */, 167 | 72BE8D771D3FBC05005720FB /* BoardingPassTests.swift */, 168 | ); 169 | path = BoardingPassTests; 170 | sourceTree = ""; 171 | }; 172 | 72BE8D851D3FBCDE005720FB /* BoardingPassExample */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 72BE8D991D3FBD26005720FB /* App Delegate */, 176 | 72BE8D961D3FBCEC005720FB /* Assets */, 177 | 72BE8D9A1D3FBD2F005720FB /* Onboarding Demo */, 178 | ); 179 | path = BoardingPassExample; 180 | sourceTree = ""; 181 | }; 182 | 72BE8D961D3FBCEC005720FB /* Assets */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 72BE8D8D1D3FBCDE005720FB /* Assets.xcassets */, 186 | 72BE8D921D3FBCDE005720FB /* Info.plist */, 187 | 72BE8D8F1D3FBCDE005720FB /* LaunchScreen.storyboard */, 188 | ); 189 | path = Assets; 190 | sourceTree = ""; 191 | }; 192 | 72BE8D971D3FBD00005720FB /* Assets */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 72BE8D791D3FBC05005720FB /* Info.plist */, 196 | ); 197 | path = Assets; 198 | sourceTree = ""; 199 | }; 200 | 72BE8D981D3FBD0C005720FB /* Assets */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 72BE8D691D3EC55E005720FB /* BoardingPass.h */, 204 | 72BE8D6B1D3EC55E005720FB /* Info.plist */, 205 | ); 206 | path = Assets; 207 | sourceTree = ""; 208 | }; 209 | 72BE8D991D3FBD26005720FB /* App Delegate */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | 72BE8D861D3FBCDE005720FB /* AppDelegate.swift */, 213 | ); 214 | path = "App Delegate"; 215 | sourceTree = ""; 216 | }; 217 | 72BE8D9A1D3FBD2F005720FB /* Onboarding Demo */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | 7264CA311D3FEC4000033FC4 /* Completed View Controller */, 221 | 7264CA301D3FEC2A00033FC4 /* Process View Controllers */, 222 | 72BE8D881D3FBCDE005720FB /* OnboardingWrapperViewController.swift */, 223 | ); 224 | path = "Onboarding Demo"; 225 | sourceTree = ""; 226 | }; 227 | /* End PBXGroup section */ 228 | 229 | /* Begin PBXHeadersBuildPhase section */ 230 | 72BE8D631D3EC55E005720FB /* Headers */ = { 231 | isa = PBXHeadersBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | 72BE8D6A1D3EC55E005720FB /* BoardingPass.h in Headers */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXHeadersBuildPhase section */ 239 | 240 | /* Begin PBXNativeTarget section */ 241 | 72BE8D651D3EC55E005720FB /* BoardingPass */ = { 242 | isa = PBXNativeTarget; 243 | buildConfigurationList = 72BE8D6E1D3EC55E005720FB /* Build configuration list for PBXNativeTarget "BoardingPass" */; 244 | buildPhases = ( 245 | 720EF3761DF9D136007A5E10 /* Swiftlint */, 246 | 72BE8D611D3EC55E005720FB /* Sources */, 247 | 72BE8D621D3EC55E005720FB /* Frameworks */, 248 | 72BE8D631D3EC55E005720FB /* Headers */, 249 | 72BE8D641D3EC55E005720FB /* Resources */, 250 | ); 251 | buildRules = ( 252 | ); 253 | dependencies = ( 254 | ); 255 | name = BoardingPass; 256 | productName = BoardingPass; 257 | productReference = 72BE8D661D3EC55E005720FB /* BoardingPass.framework */; 258 | productType = "com.apple.product-type.framework"; 259 | }; 260 | 72BE8D741D3FBC05005720FB /* BoardingPassTests */ = { 261 | isa = PBXNativeTarget; 262 | buildConfigurationList = 72BE8D7F1D3FBC05005720FB /* Build configuration list for PBXNativeTarget "BoardingPassTests" */; 263 | buildPhases = ( 264 | 72BE8D711D3FBC05005720FB /* Sources */, 265 | 72BE8D721D3FBC05005720FB /* Frameworks */, 266 | 72BE8D731D3FBC05005720FB /* Resources */, 267 | ); 268 | buildRules = ( 269 | ); 270 | dependencies = ( 271 | 72BE8D7C1D3FBC05005720FB /* PBXTargetDependency */, 272 | ); 273 | name = BoardingPassTests; 274 | productName = BoardingPassTests; 275 | productReference = 72BE8D751D3FBC05005720FB /* BoardingPassTests.xctest */; 276 | productType = "com.apple.product-type.bundle.unit-test"; 277 | }; 278 | 72BE8D831D3FBCDE005720FB /* BoardingPassExample */ = { 279 | isa = PBXNativeTarget; 280 | buildConfigurationList = 72BE8D931D3FBCDE005720FB /* Build configuration list for PBXNativeTarget "BoardingPassExample" */; 281 | buildPhases = ( 282 | 72BE8D801D3FBCDE005720FB /* Sources */, 283 | 72BE8D811D3FBCDE005720FB /* Frameworks */, 284 | 72BE8D821D3FBCDE005720FB /* Resources */, 285 | 7264CA2A1D3FC54A00033FC4 /* Embed Frameworks */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | 7264CA291D3FC54A00033FC4 /* PBXTargetDependency */, 291 | ); 292 | name = BoardingPassExample; 293 | productName = BoardingPassExample; 294 | productReference = 72BE8D841D3FBCDE005720FB /* BoardingPassExample.app */; 295 | productType = "com.apple.product-type.application"; 296 | }; 297 | /* End PBXNativeTarget section */ 298 | 299 | /* Begin PBXProject section */ 300 | 72BE8D5D1D3EC55E005720FB /* Project object */ = { 301 | isa = PBXProject; 302 | attributes = { 303 | LastSwiftUpdateCheck = 0730; 304 | LastUpgradeCheck = 0800; 305 | ORGANIZATIONNAME = Raizlabs; 306 | TargetAttributes = { 307 | 72BE8D651D3EC55E005720FB = { 308 | CreatedOnToolsVersion = 7.3.1; 309 | LastSwiftMigration = 0800; 310 | }; 311 | 72BE8D741D3FBC05005720FB = { 312 | CreatedOnToolsVersion = 7.3.1; 313 | LastSwiftMigration = 0800; 314 | }; 315 | 72BE8D831D3FBCDE005720FB = { 316 | CreatedOnToolsVersion = 7.3.1; 317 | LastSwiftMigration = 0800; 318 | }; 319 | }; 320 | }; 321 | buildConfigurationList = 72BE8D601D3EC55E005720FB /* Build configuration list for PBXProject "BoardingPass" */; 322 | compatibilityVersion = "Xcode 3.2"; 323 | developmentRegion = English; 324 | hasScannedForEncodings = 0; 325 | knownRegions = ( 326 | en, 327 | Base, 328 | ); 329 | mainGroup = 72BE8D5C1D3EC55E005720FB; 330 | productRefGroup = 72BE8D671D3EC55E005720FB /* Products */; 331 | projectDirPath = ""; 332 | projectRoot = ""; 333 | targets = ( 334 | 72BE8D651D3EC55E005720FB /* BoardingPass */, 335 | 72BE8D741D3FBC05005720FB /* BoardingPassTests */, 336 | 72BE8D831D3FBCDE005720FB /* BoardingPassExample */, 337 | ); 338 | }; 339 | /* End PBXProject section */ 340 | 341 | /* Begin PBXResourcesBuildPhase section */ 342 | 72BE8D641D3EC55E005720FB /* Resources */ = { 343 | isa = PBXResourcesBuildPhase; 344 | buildActionMask = 2147483647; 345 | files = ( 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | }; 349 | 72BE8D731D3FBC05005720FB /* Resources */ = { 350 | isa = PBXResourcesBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | ); 354 | runOnlyForDeploymentPostprocessing = 0; 355 | }; 356 | 72BE8D821D3FBCDE005720FB /* Resources */ = { 357 | isa = PBXResourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | 72BE8D911D3FBCDE005720FB /* LaunchScreen.storyboard in Resources */, 361 | 72BE8D8E1D3FBCDE005720FB /* Assets.xcassets in Resources */, 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | }; 365 | /* End PBXResourcesBuildPhase section */ 366 | 367 | /* Begin PBXShellScriptBuildPhase section */ 368 | 720EF3761DF9D136007A5E10 /* Swiftlint */ = { 369 | isa = PBXShellScriptBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | ); 373 | inputPaths = ( 374 | ); 375 | name = Swiftlint; 376 | outputPaths = ( 377 | ); 378 | runOnlyForDeploymentPostprocessing = 0; 379 | shellPath = /bin/sh; 380 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint || echo \"warning: SwiftLint failed with exit code $?. Is SwiftLint installed and up to date?\"\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 381 | }; 382 | /* End PBXShellScriptBuildPhase section */ 383 | 384 | /* Begin PBXSourcesBuildPhase section */ 385 | 72BE8D611D3EC55E005720FB /* Sources */ = { 386 | isa = PBXSourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | 7264CA2E1D3FEB2A00033FC4 /* BoardingInformation.swift in Sources */, 390 | 23A09E271D908D05004A9ADF /* BoardingPassCompatibility.swift in Sources */, 391 | 7264CA351D4001BD00033FC4 /* HorizontalSlideAnimatedTransition.swift in Sources */, 392 | 7264CA2C1D3FC69800033FC4 /* BoardingNavigationController.swift in Sources */, 393 | ); 394 | runOnlyForDeploymentPostprocessing = 0; 395 | }; 396 | 72BE8D711D3FBC05005720FB /* Sources */ = { 397 | isa = PBXSourcesBuildPhase; 398 | buildActionMask = 2147483647; 399 | files = ( 400 | 72BE8D781D3FBC05005720FB /* BoardingPassTests.swift in Sources */, 401 | ); 402 | runOnlyForDeploymentPostprocessing = 0; 403 | }; 404 | 72BE8D801D3FBCDE005720FB /* Sources */ = { 405 | isa = PBXSourcesBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | 72F163451D4910D1007D983B /* ActionableViewController.swift in Sources */, 409 | 7264CA331D3FEC4C00033FC4 /* CompletedViewController.swift in Sources */, 410 | 7264CA231D3FC4B300033FC4 /* SecondViewController.swift in Sources */, 411 | 7264CA211D3FC4AB00033FC4 /* FirstViewController.swift in Sources */, 412 | 7264CA251D3FC4B900033FC4 /* ThirdViewController.swift in Sources */, 413 | 72BE8D891D3FBCDE005720FB /* OnboardingWrapperViewController.swift in Sources */, 414 | 72BE8D871D3FBCDE005720FB /* AppDelegate.swift in Sources */, 415 | ); 416 | runOnlyForDeploymentPostprocessing = 0; 417 | }; 418 | /* End PBXSourcesBuildPhase section */ 419 | 420 | /* Begin PBXTargetDependency section */ 421 | 7264CA291D3FC54A00033FC4 /* PBXTargetDependency */ = { 422 | isa = PBXTargetDependency; 423 | target = 72BE8D651D3EC55E005720FB /* BoardingPass */; 424 | targetProxy = 7264CA281D3FC54A00033FC4 /* PBXContainerItemProxy */; 425 | }; 426 | 72BE8D7C1D3FBC05005720FB /* PBXTargetDependency */ = { 427 | isa = PBXTargetDependency; 428 | target = 72BE8D651D3EC55E005720FB /* BoardingPass */; 429 | targetProxy = 72BE8D7B1D3FBC05005720FB /* PBXContainerItemProxy */; 430 | }; 431 | /* End PBXTargetDependency section */ 432 | 433 | /* Begin PBXVariantGroup section */ 434 | 72BE8D8F1D3FBCDE005720FB /* LaunchScreen.storyboard */ = { 435 | isa = PBXVariantGroup; 436 | children = ( 437 | 72BE8D901D3FBCDE005720FB /* Base */, 438 | ); 439 | name = LaunchScreen.storyboard; 440 | path = .; 441 | sourceTree = ""; 442 | }; 443 | /* End PBXVariantGroup section */ 444 | 445 | /* Begin XCBuildConfiguration section */ 446 | 72BE8D6C1D3EC55E005720FB /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | CLANG_ANALYZER_NONNULL = YES; 451 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 452 | CLANG_CXX_LIBRARY = "libc++"; 453 | CLANG_ENABLE_MODULES = YES; 454 | CLANG_ENABLE_OBJC_ARC = YES; 455 | CLANG_WARN_BOOL_CONVERSION = YES; 456 | CLANG_WARN_CONSTANT_CONVERSION = YES; 457 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 458 | CLANG_WARN_EMPTY_BODY = YES; 459 | CLANG_WARN_ENUM_CONVERSION = YES; 460 | CLANG_WARN_INFINITE_RECURSION = YES; 461 | CLANG_WARN_INT_CONVERSION = YES; 462 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 463 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 464 | CLANG_WARN_UNREACHABLE_CODE = YES; 465 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 466 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 467 | COPY_PHASE_STRIP = NO; 468 | CURRENT_PROJECT_VERSION = 1; 469 | DEBUG_INFORMATION_FORMAT = dwarf; 470 | ENABLE_STRICT_OBJC_MSGSEND = YES; 471 | ENABLE_TESTABILITY = YES; 472 | GCC_C_LANGUAGE_STANDARD = gnu99; 473 | GCC_DYNAMIC_NO_PIC = NO; 474 | GCC_NO_COMMON_BLOCKS = YES; 475 | GCC_OPTIMIZATION_LEVEL = 0; 476 | GCC_PREPROCESSOR_DEFINITIONS = ( 477 | "DEBUG=1", 478 | "$(inherited)", 479 | ); 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 487 | MTL_ENABLE_DEBUG_INFO = YES; 488 | ONLY_ACTIVE_ARCH = YES; 489 | SDKROOT = iphoneos; 490 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 491 | TARGETED_DEVICE_FAMILY = "1,2"; 492 | VERSIONING_SYSTEM = "apple-generic"; 493 | VERSION_INFO_PREFIX = ""; 494 | }; 495 | name = Debug; 496 | }; 497 | 72BE8D6D1D3EC55E005720FB /* Release */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | ALWAYS_SEARCH_USER_PATHS = NO; 501 | CLANG_ANALYZER_NONNULL = YES; 502 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 503 | CLANG_CXX_LIBRARY = "libc++"; 504 | CLANG_ENABLE_MODULES = YES; 505 | CLANG_ENABLE_OBJC_ARC = YES; 506 | CLANG_WARN_BOOL_CONVERSION = YES; 507 | CLANG_WARN_CONSTANT_CONVERSION = YES; 508 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 509 | CLANG_WARN_EMPTY_BODY = YES; 510 | CLANG_WARN_ENUM_CONVERSION = YES; 511 | CLANG_WARN_INFINITE_RECURSION = YES; 512 | CLANG_WARN_INT_CONVERSION = YES; 513 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 514 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 515 | CLANG_WARN_UNREACHABLE_CODE = YES; 516 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 517 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 518 | COPY_PHASE_STRIP = NO; 519 | CURRENT_PROJECT_VERSION = 1; 520 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 521 | ENABLE_NS_ASSERTIONS = NO; 522 | ENABLE_STRICT_OBJC_MSGSEND = YES; 523 | GCC_C_LANGUAGE_STANDARD = gnu99; 524 | GCC_NO_COMMON_BLOCKS = YES; 525 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 526 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 527 | GCC_WARN_UNDECLARED_SELECTOR = YES; 528 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 529 | GCC_WARN_UNUSED_FUNCTION = YES; 530 | GCC_WARN_UNUSED_VARIABLE = YES; 531 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 532 | MTL_ENABLE_DEBUG_INFO = NO; 533 | SDKROOT = iphoneos; 534 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 535 | TARGETED_DEVICE_FAMILY = "1,2"; 536 | VALIDATE_PRODUCT = YES; 537 | VERSIONING_SYSTEM = "apple-generic"; 538 | VERSION_INFO_PREFIX = ""; 539 | }; 540 | name = Release; 541 | }; 542 | 72BE8D6F1D3EC55E005720FB /* Debug */ = { 543 | isa = XCBuildConfiguration; 544 | buildSettings = { 545 | CLANG_ENABLE_MODULES = YES; 546 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 547 | DEFINES_MODULE = YES; 548 | DYLIB_COMPATIBILITY_VERSION = 1; 549 | DYLIB_CURRENT_VERSION = 1; 550 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 551 | GCC_GENERATE_TEST_COVERAGE_FILES = NO; 552 | INFOPLIST_FILE = BoardingPass/Assets/Info.plist; 553 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 554 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 555 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 556 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPass; 557 | PRODUCT_NAME = "$(TARGET_NAME)"; 558 | SKIP_INSTALL = YES; 559 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 560 | SWIFT_VERSION = 3.0; 561 | }; 562 | name = Debug; 563 | }; 564 | 72BE8D701D3EC55E005720FB /* Release */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | CLANG_ENABLE_MODULES = YES; 568 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 569 | DEFINES_MODULE = YES; 570 | DYLIB_COMPATIBILITY_VERSION = 1; 571 | DYLIB_CURRENT_VERSION = 1; 572 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 573 | GCC_GENERATE_TEST_COVERAGE_FILES = NO; 574 | INFOPLIST_FILE = BoardingPass/Assets/Info.plist; 575 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 576 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 577 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 578 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPass; 579 | PRODUCT_NAME = "$(TARGET_NAME)"; 580 | SKIP_INSTALL = YES; 581 | SWIFT_VERSION = 3.0; 582 | }; 583 | name = Release; 584 | }; 585 | 72BE8D7D1D3FBC05005720FB /* Debug */ = { 586 | isa = XCBuildConfiguration; 587 | buildSettings = { 588 | INFOPLIST_FILE = BoardingPassTests/Assets/Info.plist; 589 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 590 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPassTests; 591 | PRODUCT_NAME = "$(TARGET_NAME)"; 592 | SWIFT_VERSION = 3.0; 593 | }; 594 | name = Debug; 595 | }; 596 | 72BE8D7E1D3FBC05005720FB /* Release */ = { 597 | isa = XCBuildConfiguration; 598 | buildSettings = { 599 | INFOPLIST_FILE = BoardingPassTests/Assets/Info.plist; 600 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 601 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPassTests; 602 | PRODUCT_NAME = "$(TARGET_NAME)"; 603 | SWIFT_VERSION = 3.0; 604 | }; 605 | name = Release; 606 | }; 607 | 72BE8D941D3FBCDE005720FB /* Debug */ = { 608 | isa = XCBuildConfiguration; 609 | buildSettings = { 610 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 611 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 612 | GCC_GENERATE_TEST_COVERAGE_FILES = NO; 613 | INFOPLIST_FILE = BoardingPassExample/Assets/Info.plist; 614 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 615 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 616 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPassExample; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | SWIFT_VERSION = 3.0; 619 | }; 620 | name = Debug; 621 | }; 622 | 72BE8D951D3FBCDE005720FB /* Release */ = { 623 | isa = XCBuildConfiguration; 624 | buildSettings = { 625 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 626 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 627 | GCC_GENERATE_TEST_COVERAGE_FILES = NO; 628 | INFOPLIST_FILE = BoardingPassExample/Assets/Info.plist; 629 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 630 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 631 | PRODUCT_BUNDLE_IDENTIFIER = com.raizlabs.BoardingPassExample; 632 | PRODUCT_NAME = "$(TARGET_NAME)"; 633 | SWIFT_VERSION = 3.0; 634 | }; 635 | name = Release; 636 | }; 637 | /* End XCBuildConfiguration section */ 638 | 639 | /* Begin XCConfigurationList section */ 640 | 72BE8D601D3EC55E005720FB /* Build configuration list for PBXProject "BoardingPass" */ = { 641 | isa = XCConfigurationList; 642 | buildConfigurations = ( 643 | 72BE8D6C1D3EC55E005720FB /* Debug */, 644 | 72BE8D6D1D3EC55E005720FB /* Release */, 645 | ); 646 | defaultConfigurationIsVisible = 0; 647 | defaultConfigurationName = Release; 648 | }; 649 | 72BE8D6E1D3EC55E005720FB /* Build configuration list for PBXNativeTarget "BoardingPass" */ = { 650 | isa = XCConfigurationList; 651 | buildConfigurations = ( 652 | 72BE8D6F1D3EC55E005720FB /* Debug */, 653 | 72BE8D701D3EC55E005720FB /* Release */, 654 | ); 655 | defaultConfigurationIsVisible = 0; 656 | defaultConfigurationName = Release; 657 | }; 658 | 72BE8D7F1D3FBC05005720FB /* Build configuration list for PBXNativeTarget "BoardingPassTests" */ = { 659 | isa = XCConfigurationList; 660 | buildConfigurations = ( 661 | 72BE8D7D1D3FBC05005720FB /* Debug */, 662 | 72BE8D7E1D3FBC05005720FB /* Release */, 663 | ); 664 | defaultConfigurationIsVisible = 0; 665 | defaultConfigurationName = Release; 666 | }; 667 | 72BE8D931D3FBCDE005720FB /* Build configuration list for PBXNativeTarget "BoardingPassExample" */ = { 668 | isa = XCConfigurationList; 669 | buildConfigurations = ( 670 | 72BE8D941D3FBCDE005720FB /* Debug */, 671 | 72BE8D951D3FBCDE005720FB /* Release */, 672 | ); 673 | defaultConfigurationIsVisible = 0; 674 | defaultConfigurationName = Release; 675 | }; 676 | /* End XCConfigurationList section */ 677 | }; 678 | rootObject = 72BE8D5D1D3EC55E005720FB /* Project object */; 679 | } 680 | --------------------------------------------------------------------------------