6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in
15 | // all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | // THE SOFTWARE.
24 | //
25 |
26 | import PackageDescription
27 |
28 | let package = Package(
29 | name: "Pulley",
30 | platforms: [.iOS(.v9)],
31 | products: [
32 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
33 | .library(
34 | name: "Pulley",
35 | targets: ["Pulley"]),
36 | ],
37 | dependencies: [
38 | // Dependencies declare other packages that this package depends on.
39 | // .package(url: /* package url */, from: "1.0.0"),
40 | ],
41 | targets: [
42 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
43 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
44 | .target(name: "Pulley",
45 | path: "PulleyLib")
46 | ]
47 | )
48 |
--------------------------------------------------------------------------------
/Pulley/CustomMaskExample.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomMaskExample.swift
3 | // Pulley
4 | //
5 | // Created by Connor Power on 19.08.18.
6 | // Copyright © 2018 52inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct CustomMaskExample {
12 |
13 | // MARK: - Constants
14 |
15 | private struct Constants {
16 | static let cornerRadius: CGFloat = 8.0
17 | static let cutoutDistanceFromEdge: CGFloat = 32.0
18 | static let cutoutRadius: CGFloat = 8.0
19 | }
20 |
21 | // MARK: - Functions
22 |
23 | func customMask(for bounds: CGRect) -> UIBezierPath {
24 | let maxX = bounds.maxX
25 | let maxY = bounds.maxY
26 |
27 | let path = UIBezierPath()
28 | path.move(to: CGPoint(x: 0, y: maxY))
29 |
30 | // Left hand edge
31 | path.addLine(to: CGPoint(x: 0, y: Constants.cornerRadius))
32 |
33 | // Top left rounded corner
34 | path.addArc(withCenter: CGPoint(x: Constants.cornerRadius, y: Constants.cornerRadius),
35 | radius: Constants.cornerRadius,
36 | startAngle: CGFloat.pi,
37 | endAngle: 1.5 * CGFloat.pi,
38 | clockwise: true)
39 |
40 | // Top edge left cutout section
41 | path.addLine(to: CGPoint(x: Constants.cutoutDistanceFromEdge - Constants.cutoutRadius, y: 0))
42 | path.addArc(withCenter: CGPoint(x: Constants.cutoutDistanceFromEdge, y: 0),
43 | radius: Constants.cutoutRadius,
44 | startAngle: CGFloat.pi,
45 | endAngle: 2.0 * CGFloat.pi,
46 | clockwise: false)
47 | path.addLine(to: CGPoint(x: Constants.cutoutDistanceFromEdge + Constants.cutoutRadius, y: 0))
48 |
49 | // Top edge right cutout section
50 | path.addLine(to: CGPoint(x: maxX - Constants.cutoutDistanceFromEdge - Constants.cutoutRadius, y: 0))
51 | path.addArc(withCenter: CGPoint(x: maxX - Constants.cutoutDistanceFromEdge, y: 0),
52 | radius: Constants.cutoutRadius,
53 | startAngle: CGFloat.pi,
54 | endAngle: 2.0 * CGFloat.pi,
55 | clockwise: false)
56 | path.addLine(to: CGPoint(x: maxX - Constants.cutoutDistanceFromEdge + Constants.cutoutRadius, y: 0))
57 | path.addLine(to: CGPoint(x: maxX - Constants.cornerRadius, y: 0))
58 |
59 | // Top right rounded corner
60 | path.addArc(withCenter: CGPoint(x: maxX - Constants.cornerRadius, y: Constants.cornerRadius),
61 | radius: Constants.cornerRadius,
62 | startAngle: 1.5 * CGFloat.pi,
63 | endAngle: 2.0 * CGFloat.pi,
64 | clockwise: true)
65 |
66 | // Right hand edge
67 | path.addLine(to: CGPoint(x: maxX, y: maxY))
68 |
69 | // Bottom edge
70 | path.addLine(to: CGPoint(x: 0, y: maxY))
71 | path.close()
72 | path.fill()
73 |
74 | return path
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/Pulley.xcodeproj/xcshareddata/xcschemes/Pulley.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
3 |
4 | ## User settings
5 | xcuserdata/
6 |
7 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
8 | *.xcscmblueprint
9 | *.xccheckout
10 | *.xcuserstate
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ####
26 | # Xcode temporary files that should never be committed
27 | #
28 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
29 |
30 | *~.nib
31 |
32 | ## Obj-C/Swift specific
33 | *.hmap
34 |
35 | ## App packaging
36 | *.ipa
37 | *.dSYM.zip
38 | *.dSYM
39 | *.zip
40 |
41 | ## Playgrounds
42 | timeline.xctimeline
43 | playground.xcworkspace
44 |
45 | # Swift Package Manager
46 | #
47 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
48 | # Packages/
49 | # Package.pins
50 | # Package.resolved
51 | # *.xcodeproj
52 | #
53 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
54 | # hence it is not needed unless you have added a package configuration file to your project
55 | # .swiftpm
56 |
57 | .build/
58 |
59 | # CocoaPods
60 | #
61 | # We recommend against adding the Pods directory to your .gitignore. However
62 | # you should judge for yourself, the pros and cons are mentioned at:
63 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
64 | #
65 | # Pods/
66 | #
67 | # Add this line if you want to avoid checking in source code from the Xcode workspace
68 | # *.xcworkspace
69 |
70 | # Carthage
71 | #
72 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
73 | # Carthage/Checkouts
74 |
75 | Carthage/Build/
76 |
77 | # Accio dependency management
78 | Dependencies/
79 | .accio/
80 |
81 | # fastlane
82 | #
83 | # It is recommended to not store the screenshots in the git repo.
84 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
85 | # For more information about the recommended setup visit:
86 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
87 |
88 | fastlane/report.xml
89 | fastlane/Preview.html
90 | fastlane/screenshots/**/*.png
91 | fastlane/test_output
92 |
93 | # Code Injection
94 | #
95 | # After new code Injection tools there's a generated folder /iOSInjectionProject
96 | # https://github.com/johnno1962/injectionforxcode
97 |
98 | iOSInjectionProject/
99 |
100 | # OSX Temp
101 | .DS_Store
102 | .AppleDouble
103 | .LSOverride
104 |
105 | # OSX Thumbnails
106 | ._*
107 |
108 | # OSX Directories potentially created on remote AFP share
109 | .AppleDB
110 | .AppleDesktop
111 | Network Trash Folder
112 | Temporary Items
113 | .apdisk
114 |
115 | # Linux trash folder which might appear on any partition or disk
116 | .Trash-*
117 |
118 | # vim
119 | *.swp
120 |
--------------------------------------------------------------------------------
/Pulley/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Pulley
4 | //
5 | // Created by Brendan Lee on 7/6/16.
6 | // Copyright © 2016 52inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Pulley
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
18 | {
19 | // Override point for customization after application launch.
20 |
21 | window = UIWindow(frame: UIScreen.main.bounds)
22 |
23 | // To create from a Storyboard
24 | window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
25 |
26 | // To create in code (uncomment this block)
27 | /*
28 | let mainContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PrimaryContentViewController")
29 | let drawerContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DrawerContentViewController")
30 | let pulleyDrawerVC = PulleyViewController(contentViewController: mainContentVC, drawerViewController: drawerContentVC)
31 |
32 | // Uncomment this next line to give the drawer a starting position, in this case: closed.
33 | // pulleyDrawerVC.initialDrawerPosition = .closed
34 |
35 | window?.rootViewController = pulleyDrawerVC
36 | */
37 |
38 | window?.makeKeyAndVisible()
39 |
40 | return true
41 | }
42 |
43 | func applicationWillResignActive(_ application: UIApplication) {
44 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
45 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
46 | }
47 |
48 | func applicationDidEnterBackground(_ application: UIApplication) {
49 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
50 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
51 | }
52 |
53 | func applicationWillEnterForeground(_ application: UIApplication) {
54 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
55 | }
56 |
57 | func applicationDidBecomeActive(_ application: UIApplication) {
58 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
59 | }
60 |
61 | func applicationWillTerminate(_ application: UIApplication) {
62 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.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, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and 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 hello@52inc.com. 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 https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/Pulley.xcodeproj/xcshareddata/xcschemes/PulleyDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
66 |
67 |
68 |
69 |
75 |
77 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute to Pulley
2 | :tada::heart: First off, thanks for taking the time to contribute or considering to contribute! :heart::tada:
3 |
4 | The following is a set of gidelines for contributing to the Pulley project. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. Also feel free to purpose changes to the new [issue templates](https://github.com/52inc/Pulley/tree/master/.github/ISSUE_TEMPLATE) or the new [pull request template](https://github.com/52inc/Pulley/blob/master/.github/PULL_REQUEST_TEMPLATE.md) in a pull request as well.
5 |
6 | ## Code of Conduct
7 |
8 | This project and everyone participating in it is governed by the [Pulley Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [hello@52inc.com](mailto:hello@52inc.com).
9 |
10 | ## Your First Contribution
11 |
12 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
13 |
14 | ## Reporting Bugs
15 |
16 | This section guides you through submitting a bug report for Pulley.
17 |
18 | Before creating bug reports, please check the open issues as you might find out that you don't need to create a new one. When you are creating a bug report, please include as many details as possible. Fill out [the required template](https://github.com/52inc/Pulley/tree/master/.github/ISSUE_TEMPLATE/pulley-bug-report.md), the information it asks for helps us resolve issues faster.
19 |
20 | > **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
21 |
22 | ## Suggesting Features
23 |
24 | This section guides you through submitting a feature suggestion for Pulley, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
25 |
26 | Before creating feature suggestions, please check the open issues with the enhancement label as you might find out that you don't need to create one. When you are creating a feature suggestion, please include as many details as possible and fill in [the template](https://github.com/52inc/Pulley/blob/master/.github/ISSUE_TEMPLATE/pulley-feature-request.md).
27 |
28 |
29 | ## Submitting Code
30 |
31 | This section guides you through submitting a pull request for Pulley. The goal being to imitate the behavior of the Apple Maps drawer, maintain backwards compatability, and maintain support for all iOS device size classes.
32 |
33 | Any code change should be submitted as a pull request. The description should explain what the code does, give steps to execute it, and breifly explan what steps were taken to test your code. Please follow the [pull request template](https://github.com/52inc/Pulley/blob/master/.github/PULL_REQUEST_TEMPLATE.md) as best you can and provide as much detail as possiable.
34 |
35 | ## Code Review Process
36 |
37 | We will do our best to review your request as soon as we can, but please keep in mind we are also full time developers. The bigger the pull request and the more parts of the application it can potentially effect, the longer it will take for us review and merge. Try to test as much as you can and think about how your pull request effects previous versions of iOS or the existing Pulley API before you submit it to us for review. It is also always helpful to have as much context as possiable for your pull request.
38 |
39 | ## Questions
40 |
41 | If you have any questions, create a new issue using the [question issue template](https://github.com/52inc/Pulley/tree/master/.github/ISSUE_TEMPLATE/pulley-question.md). Please do a quick search first to see if someone else didn't ask the same question before you.
42 | You can also reach us at [hello@52inc.com](mailto:hello@52inc.com).
43 |
44 | ## Credits
45 |
46 | ### Contributors
47 |
48 | Thank you to all the people who have already contributed to Pulley! I hope you all continue to contribute because you all make the open source community a better place by contributing!
49 |
50 |
--------------------------------------------------------------------------------
/Pulley/PrimaryContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Pulley
4 | //
5 | // Created by Brendan Lee on 7/6/16.
6 | // Copyright © 2016 52inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MapKit
11 | import Pulley
12 |
13 | class PrimaryContentViewController: UIViewController {
14 |
15 | @IBOutlet var mapView: MKMapView!
16 | @IBOutlet var controlsContainer: UIView!
17 | @IBOutlet var temperatureLabel: UILabel!
18 |
19 | /**
20 | * IMPORTANT! If you have constraints that you use to 'follow' the drawer (like the temperature label in the demo)...
21 | * Make sure you constraint them to the bottom of the superview and NOT the superview's bottom margin. Double click the constraint, and you can change it in the dropdown in the right-side panel. If you don't, you'll have varying spacings to the drawer depending on the device.
22 | */
23 | @IBOutlet var temperatureLabelBottomConstraint: NSLayoutConstraint!
24 |
25 | fileprivate let temperatureLabelBottomDistance: CGFloat = 8.0
26 |
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 | // Do any additional setup after loading the view, typically from a nib.
30 |
31 | controlsContainer.layer.cornerRadius = 10.0
32 | temperatureLabel.layer.cornerRadius = 7.0
33 | }
34 |
35 | override func viewWillAppear(_ animated: Bool) {
36 | super.viewWillAppear(animated)
37 |
38 | // Customize Pulley in viewWillAppear, as the view controller's viewDidLoad will run *before* Pulley's and some changes may be overwritten.
39 | // Uncomment if you want to change the visual effect style to dark. Note: The rest of the sample app's UI isn't made for dark theme. This just shows you how to do it.
40 | // drawer.drawerBackgroundVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
41 |
42 | // We want the 'side panel' layout in landscape iPhone / iPad, so we set this to 'automatic'. The default is 'bottomDrawer' for compatibility with older Pulley versions.
43 | self.pulleyViewController?.displayMode = .automatic
44 | }
45 |
46 | @IBAction func runPrimaryContentTransitionWithoutAnimation(sender: AnyObject) {
47 | let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PrimaryTransitionTargetViewController")
48 |
49 | self.pulleyViewController?.setPrimaryContentViewController(controller: primaryContent, animated: false)
50 | }
51 |
52 | @IBAction func runPrimaryContentTransition(sender: AnyObject) {
53 | let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PrimaryTransitionTargetViewController")
54 |
55 | self.pulleyViewController?.setPrimaryContentViewController(controller: primaryContent, animated: true)
56 | }
57 | }
58 |
59 | extension PrimaryContentViewController: PulleyPrimaryContentControllerDelegate {
60 |
61 | func makeUIAdjustmentsForFullscreen(progress: CGFloat, bottomSafeArea: CGFloat)
62 | {
63 | guard let drawer = self.pulleyViewController, drawer.currentDisplayMode == .drawer else {
64 | controlsContainer.alpha = 1.0
65 | return
66 | }
67 |
68 | controlsContainer.alpha = 1.0 - progress
69 | }
70 |
71 | func drawerChangedDistanceFromBottom(drawer: PulleyViewController, distance: CGFloat, bottomSafeArea: CGFloat)
72 | {
73 | // As of iOS 14, setting the constant on the constraint causes viewDidLayoutSubviews() to be call
74 | // on the PulleyViewController. This was causing issues with the drawer scroll view in 2.8.2+, see fix
75 | // for issue #400 and update 2.8.5
76 | guard drawer.currentDisplayMode == .drawer else {
77 |
78 | temperatureLabelBottomConstraint.constant = temperatureLabelBottomDistance
79 | return
80 | }
81 |
82 | if distance <= 268.0 + bottomSafeArea
83 | {
84 | temperatureLabelBottomConstraint.constant = distance + temperatureLabelBottomDistance
85 | }
86 | else
87 | {
88 | temperatureLabelBottomConstraint.constant = 268.0 + temperatureLabelBottomDistance
89 | }
90 | }
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/Pulley/DrawerContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DrawerPreviewContentViewController.swift
3 | // Pulley
4 | //
5 | // Created by Brendan Lee on 7/6/16.
6 | // Copyright © 2016 52inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Pulley
11 |
12 | class DrawerContentViewController: UIViewController {
13 |
14 | // Pulley can apply a custom mask to the panel drawer. This variable toggles an example.
15 | private var shouldDisplayCustomMaskExample = false
16 |
17 | @IBOutlet var tableView: UITableView!
18 | @IBOutlet var searchBar: UISearchBar!
19 | @IBOutlet var gripperView: UIView!
20 | @IBOutlet var topSeparatorView: UIView!
21 | @IBOutlet var bottomSeperatorView: UIView!
22 |
23 | @IBOutlet var gripperTopConstraint: NSLayoutConstraint!
24 |
25 | // We adjust our 'header' based on the bottom safe area using this constraint
26 | @IBOutlet var headerSectionHeightConstraint: NSLayoutConstraint!
27 |
28 | fileprivate var drawerBottomSafeArea: CGFloat = 0.0 {
29 | didSet {
30 | self.loadViewIfNeeded()
31 |
32 | // We'll configure our UI to respect the safe area. In our small demo app, we just want to adjust the contentInset for the tableview.
33 | tableView.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: drawerBottomSafeArea, right: 0.0)
34 | }
35 | }
36 |
37 | override func viewDidLoad() {
38 | super.viewDidLoad()
39 |
40 | // Do any additional setup after loading the view.
41 | gripperView.layer.cornerRadius = 2.5
42 | }
43 |
44 | override func viewWillAppear(_ animated: Bool) {
45 | super.viewWillAppear(animated)
46 |
47 | // You must wait until viewWillAppear -or- later in the view controller lifecycle in order to get a reference to Pulley via self.parent for customization.
48 |
49 | // UIFeedbackGenerator is only available iOS 10+. Since Pulley works back to iOS 9, the .feedbackGenerator property is "Any" and managed internally as a feedback generator.
50 | if #available(iOS 10.0, *)
51 | {
52 | let feedbackGenerator = UISelectionFeedbackGenerator()
53 | self.pulleyViewController?.feedbackGenerator = feedbackGenerator
54 | }
55 | }
56 |
57 | override func viewWillLayoutSubviews() {
58 | super.viewWillLayoutSubviews()
59 |
60 | if shouldDisplayCustomMaskExample {
61 | let maskLayer = CAShapeLayer()
62 | maskLayer.path = CustomMaskExample().customMask(for: view.bounds).cgPath
63 | view.layer.mask = maskLayer
64 | }
65 | }
66 |
67 | override func viewDidAppear(_ animated: Bool) {
68 | super.viewDidAppear(animated)
69 |
70 | // The bounce here is optional, but it's done automatically after appearance as a demonstration.
71 | Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(bounceDrawer), userInfo: nil, repeats: false)
72 | }
73 |
74 | @objc fileprivate func bounceDrawer() {
75 |
76 | // We can 'bounce' the drawer to show users that the drawer needs their attention. There are optional parameters you can pass this method to control the bounce height and speed.
77 | self.pulleyViewController?.bounceDrawer()
78 | }
79 | }
80 |
81 | extension DrawerContentViewController: PulleyDrawerViewControllerDelegate {
82 |
83 | func collapsedDrawerHeight(bottomSafeArea: CGFloat) -> CGFloat
84 | {
85 | // For devices with a bottom safe area, we want to make our drawer taller. Your implementation may not want to do that. In that case, disregard the bottomSafeArea value.
86 | return 68.0 + (pulleyViewController?.currentDisplayMode == .drawer ? bottomSafeArea : 0.0)
87 | }
88 |
89 | func partialRevealDrawerHeight(bottomSafeArea: CGFloat) -> CGFloat
90 | {
91 | // For devices with a bottom safe area, we want to make our drawer taller. Your implementation may not want to do that. In that case, disregard the bottomSafeArea value.
92 | return 264.0 + (pulleyViewController?.currentDisplayMode == .drawer ? bottomSafeArea : 0.0)
93 | }
94 |
95 | func supportedDrawerPositions() -> [PulleyPosition] {
96 | return PulleyPosition.all // You can specify the drawer positions you support. This is the same as: [.open, .partiallyRevealed, .collapsed, .closed]
97 | }
98 |
99 | // This function is called by Pulley anytime the size, drawer position, etc. changes. It's best to customize your VC UI based on the bottomSafeArea here (if needed). Note: You might also find the `pulleySafeAreaInsets` property on Pulley useful to get Pulley's current safe area insets in a backwards compatible (with iOS < 11) way. If you need this information for use in your layout, you can also access it directly by using `drawerDistanceFromBottom` at any time.
100 | func drawerPositionDidChange(drawer: PulleyViewController, bottomSafeArea: CGFloat)
101 | {
102 | // We want to know about the safe area to customize our UI. Our UI customization logic is in the didSet for this variable.
103 | drawerBottomSafeArea = bottomSafeArea
104 |
105 | /*
106 | Some explanation for what is happening here:
107 | 1. Our drawer UI needs some customization to look 'correct' on devices like the iPhone X, with a bottom safe area inset.
108 | 2. We only need this when it's in the 'collapsed' position, so we'll add some safe area when it's collapsed and remove it when it's not.
109 | 3. These changes are captured in an animation block (when necessary) by Pulley, so these changes will be animated along-side the drawer automatically.
110 | */
111 | if drawer.drawerPosition == .collapsed
112 | {
113 | headerSectionHeightConstraint.constant = 68.0 + drawerBottomSafeArea
114 | }
115 | else
116 | {
117 | headerSectionHeightConstraint.constant = 68.0
118 | }
119 |
120 | // Handle tableview scrolling / searchbar editing
121 |
122 | tableView.isScrollEnabled = drawer.drawerPosition == .open || drawer.currentDisplayMode == .panel
123 |
124 | if drawer.drawerPosition != .open
125 | {
126 | searchBar.resignFirstResponder()
127 | }
128 |
129 | if drawer.currentDisplayMode == .panel
130 | {
131 | topSeparatorView.isHidden = drawer.drawerPosition == .collapsed
132 | bottomSeperatorView.isHidden = drawer.drawerPosition == .collapsed
133 | }
134 | else
135 | {
136 | topSeparatorView.isHidden = false
137 | bottomSeperatorView.isHidden = true
138 | }
139 | }
140 |
141 | /// This function is called when the current drawer display mode changes. Make UI customizations here.
142 | func drawerDisplayModeDidChange(drawer: PulleyViewController) {
143 |
144 | print("Drawer: \(drawer.currentDisplayMode)")
145 | gripperTopConstraint.isActive = (drawer.currentDisplayMode == .drawer || drawer.currentDisplayMode == .compact)
146 | }
147 | }
148 |
149 | extension DrawerContentViewController: UISearchBarDelegate {
150 |
151 | func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
152 | pulleyViewController?.setDrawerPosition(position: .open, animated: true)
153 | }
154 | }
155 |
156 | extension DrawerContentViewController: UITableViewDataSource {
157 |
158 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
159 | return 50
160 | }
161 |
162 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
163 | return tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
164 | }
165 | }
166 |
167 | extension DrawerContentViewController: UITableViewDelegate {
168 |
169 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
170 | return 81.0
171 | }
172 |
173 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
174 | tableView.deselectRow(at: indexPath, animated: true)
175 |
176 | let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PrimaryTransitionTargetViewController")
177 |
178 | pulleyViewController?.setDrawerPosition(position: .collapsed, animated: true)
179 |
180 | pulleyViewController?.setPrimaryContentViewController(controller: primaryContent, animated: false)
181 | }
182 | }
183 |
184 |
185 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pulley
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | A library to imitate the drawer in Maps for iOS 10/11. The master branch follows the latest currently released version of Swift. If you need an older version of Swift, you can specify it's version (e.g. 1.0.x) in your Podfile or use the code on the branch for that version. Older branches are unsupported.
14 |
15 | ### Update / Migration Info
16 |
17 | **ATTENTION:**
18 | Pulley 2.9.0 has new properties to support a new displayMode. The base functionality should work without any significant changes. The biggest change being the new displayMode of `.compact` to replicate Apple Maps Behavior on the iPhone SE size class devices. This is an exact replica of the behavior of the Apple Maps drawer, therefor when the `currentDisplayMode` of the `PulleyViewController` is `.compact` then the only `supportedDrawerPositions` for the view controller when in `.compact` mode are `.open`, `.closed`, and `.collapsed`. This mode also has new @IBInspectable properties, `compactInsets` and `compactWidth`. This mode behaves in a very similar way to `.panel` mode. See the pull request [here](https://github.com/52inc/Pulley/pull/347) for the motivation behind this feature. Also in this release, `setDrawerContentViewController(controller: UIViewController, position: PulleyPosition? = nil, animated: Bool = true, completion: PulleyAnimationCompletionBlock?)` has a new optional parameter `position` to set a new drawer position the drawer when a new `DrawerContentViewController` is set. See [this](https://github.com/52inc/Pulley/pull/349) pull request for the motivation behind this feature.
19 |
20 |
21 | Pulley 2.5.0 had significant renaming changes to support new features. Although property names have changed, the functionality should work without any significant changes (aside from renaming). See [this thread](https://github.com/52inc/Pulley/issues/252) for additional information.
22 |
23 |
24 | Pulley 2.4.0 changed PulleyPosition from an enum to a class. This won't affect most uses, but may affect your switch statements. Continue to use the static PulleyPosition values as usual and add a default case. This was done to allow marking some `PulleyDrawerViewControllerDelegate` methods as optional so they don't need to be implemented if you aren't using certain positions (or wish to use the default values). If you have questions, please open an issue.
25 |
26 | _Technical reason: Optional protocol methods require the @objc attribute. Arrays of Swift enums can't be exposed to Objective-C, and supportedDrawerPositions previously returned an array of PulleyPosition enums. This change allows for marking the protocol @objc so methods can be marked optional._
27 |
28 | ### Introduction
29 | Pulley is an easy to use drawer library meant to imitate the drawer in iOS 10/11's Maps app. It exposes a simple API that allows you to use any UIViewController subclass as the drawer content or the primary content.
30 |
31 | **Here's a preview (apologies for the potato gif):**
32 |
33 | 
34 |
35 | 
36 |
37 | ### Installation
38 |
39 | ##### Installation with Cocoapods
40 | `pod 'Pulley'`
41 |
42 | ##### Installation with Carthage
43 | `github "52inc/Pulley"`
44 | Please read this [issue](https://github.com/52inc/Pulley/issues/331#issue-435421067) regarding setup if using Carthage.
45 |
46 | ##### Installation with Swift Package Manager
47 | Follow the [developer documentation](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) for Swift Package Manager (versions 2.8.x)
48 |
49 | ##### Manual Installation
50 | Simply copy the files in the PulleyLib folder into your project.
51 |
52 | ### How To use
53 |
54 | #### Interface Builder
55 |
56 | Pulley supports loading embedded view controllers from Interface Builder. In order to use Pulley with Interface Builder, you'll need to setup your `PulleyViewController` like this:
57 |
58 | 1. Add 2 container views to the `PulleyViewController` view. One for the drawer content and one for the primary (background) content.
59 | 2. Connect the container view for the primary (background) content to the outlet named **primaryContentContainerView**.
60 | 3. Connect the container view for the drawer content to the outlet named **drawerContentContainerView**.
61 | 4. Create an 'embed' segue between each container view and the view controller you want to display for that part of the drawer.
62 | 5. Make sure you set the Module for the view controller to 'Pulley'. [See this issue.](https://github.com/52inc/Pulley/issues/29)
63 |
64 | If you would like to customize the height of the "Collapsed" or "Partially Revealed" states of the drawer, have your Drawer Content view controller implement `PulleyDrawerViewControllerDelegate`. You can provide the height for your drawer content for both the Collapsed and Partially Revealed states.
65 |
66 | 
67 |
68 |
69 | #### Programmatically
70 |
71 | Pulley supports loading view controllers programmatically. In order to use Pulley programmatically, please consider the following code snippet:
72 |
73 | ```swift
74 | let mainContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("PrimaryContentViewController")
75 |
76 | let drawerContentVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DrawerContentViewController")
77 |
78 | let pulleyController = PulleyViewController(contentViewController: mainContentVC, drawerViewController: drawerContentVC)
79 | ```
80 |
81 | ### API
82 |
83 | **Important:** The background of the internal drawer view is clear. If your view controller's view is also clear then you'll see the shadow rendering below where the view is. I'd recommend giving your view a color or using a UIVisualEffectView to make sure you don't see the shadow. You can set the shadow opacity to 0.0 if you want the shadow to be hidden.
84 |
85 | **Important:** Drawer Content views are made **20pt too long** in order to account for the bounce animation. Make sure your drawer content view is aware that the bottom 20pts will be offscreen.
86 |
87 | **Important:** PulleyViewController is not accessible as a parent or as `self.pulleyViewController` until _during or after_ -viewWillAppear: if you're loading Pulley from Storyboards.
88 |
89 | #### iOS 11, Safe Areas, and the iPhone X
90 | Pulley has support for safe areas and the iPhone X. The sample project includes full support for this, and does a couple of UI tricks to make things look better. These are documented throughout the sample project.
91 |
92 | The basic concepts of using Pulley post-iOS 11 are:
93 |
94 | 1. The -topInset property is _from_ the top safe area, not the top of the screen.
95 | 2. Most delegate methods have a new parameter that tells you the current bottom safe area.
96 | 3. The drawer itself doesn't do anything special for the bottom safe area because everyone's UI will want to treat it a little differently. HOWEVER: The delegate methods have been updated to deliver you the current bottom safe area anytime that a value for a drawer position is requested from you. You can use this variable to compute the value you want to return for the drawer position. Checkout the sample project for a simple example on an easy approach to this.
97 | 4. If you have UI bottom safe area customizations that you want to perform, I recommend using the delegate method `drawerPositionDidChange(drawer:bottomSafeArea:)` to modify your UI based on the value of bottomSafeArea. Any time the size of the Pulley view controller changes, this method will be called with a new bottom safe area height. The sample project uses this to modify the drawer 'header' height, as well as to adjust the contentInset for the UITableView. It's not automatically taken care of for you, but it should be a fairly simple thing to add.
98 | 5. I do _not_ recommend constraining views to the safe are of the drawer content view controller. It won't actually work for the safe areas.
99 | 6. If you want the map (or other UI) in the primary view controller to render under the status bar (or in the ears of the iPhone X), make sure you constrain it directly to the superview's 'top'. You may need to double click on the constraint, and then make sure it _isn't_ constrained 'relative to margin'.
100 | 7. For backwards compatibility, iOS 9/10 use topLayoutGuide as the top safe area. Your implementation shouldn't need to worry about iOS versions, as that's taken care of for you by Pulley.
101 |
102 | If you have any problems / questions while updating Pulley to iOS 11 SDK, please feel free to create an issue if the above information didn't solve your problem.
103 |
104 | Even if you've already seen the example project, I highly encourage looking at the new post-iOS 11 version of the sample project. It may have something that could help your iPhone X / safe area implementation.
105 |
106 | #### 3 protocols exist for you to use:
107 |
108 | * `PulleyDelegate`: The protocol the other protocols inherit from. It's exposed as the .delegate property of `PulleyViewController`. NOTE: If the object you're wanting to receive delegate callbacks is either the Primary Content or Drawer Content view controllers...don't use the .delegate property. Continue reading for the other protocols.
109 | * `PulleyDrawerViewControllerDelegate`: Includes all of the methods from `PulleyDelegate` and adds methods for providing custom heights for the Collapsed and Partially Revealed states. Your Drawer Content view controller should implement this protocol if it wants to receive callbacks for changes in the drawer state or to provide custom heights for the aforementioned drawer states. Implementing this protocol is optional for the Drawer Content view controller, but if you don't then defaults will be used instead.
110 | * `PulleyPrimaryContentControllerDelegate`: This is currently identical to `PulleyDelegate`. However, this protocol may be implemented by your Primary Content view controller if you want to receive callbacks for changes in drawer state. Eventually specialized methods may be added to this protocol.
111 |
112 | #### Changing view controllers after creation:
113 |
114 | You'll likely need to change out the contents of the drawer or the primary view controller after creation. Here's how to do that programmatically.
115 |
116 | **NOTE:** If you pass animated: true then you'll get a subtle crossfade animation. This doesn't work well with all views / view hierarchies (Notably UIVisualEffectView). You've been warned.
117 |
118 | **Changing the Primary Content View Controller:**
119 |
120 | ```swift
121 | if let drawer = self.parentViewController as? PulleyViewController
122 | {
123 | let primaryContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("PrimaryContentViewController")
124 |
125 | drawer.setPrimaryContentViewController(primaryContent, animated: true)
126 | }
127 | ```
128 |
129 | **Changing the Drawer Content View Controller:**
130 |
131 | ```swift
132 | if let drawer = self.parentViewController as? PulleyViewController
133 | {
134 | let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DrawerContentViewController")
135 |
136 | drawer.setDrawerContentViewController(drawerContent, animated: false)
137 | }
138 | ```
139 |
140 | #### Customizing the drawer
141 |
142 | 1. See the 3 protocols above.
143 | 2. You can adjust the inset from the top of the screen in the "Open" state by setting the -topInset property on the `PulleyViewController`.
144 | 3. You can enable / disable drawer positions by implementing `PulleyDrawerViewControllerDelegate` in your 'drawer' view controller. If you need to change it, call `setNeedsSupportedDrawerPositionsUpdate()` on the `PulleyViewController` so it will recalculate the drawer based on your new settings.
145 | 4. You can adjust the corner radius applied to the drawer by setting the -drawerCornerRadius property on the `PulleyViewController`.
146 | 5. You can adjust the shadow opacity applied to the drawer by setting the -shadowOpacity property on the `PulleyViewController`.
147 | 6. You can adjust the shadow radius applied to the drawer by setting the -shadowRadius property on the `PulleyViewController`.
148 | 7. You can adjust the background dimming color by setting the -backgroundDimmingColor to an opaque color on the `PulleyViewController`.
149 | 8. You can adjust / remove the background blur effect by setting the -drawerBackgroundVisualEffectView property on the `PulleyViewController`.
150 | 9. You can adjust the alpha of the background dimming color by setting the -backgroundDimmingOpacity property on the `PulleyViewController`.
151 | 10. You can change the drawer position by calling setDrawerPosition( : ) on the `PulleyViewController`.
152 | 11. If an object needs to receive delegate callbacks and _isn't_ one of the view controller's presented then you can use the -delegate property on the `PulleyViewController`.
153 | 12. The Swift Interface for `PulleyViewController` is documented in case you want to see real documentation instead of a numbered list of useful things.
154 | 13. You can set the initial drawer position by using the initialDrawerPosition property on the `PulleyViewController`.
155 | 14. Most settings for the `PulleyViewController` are exposed in Interface Builder. Select the `PulleyViewController` View Controller (not the view) to access them via IBInspectable.
156 | 15. By default, Pulley will only use the 'bottom' display mode (to preserve backwards compatibility). If you want to use the iPad / iPhone landscape modes, you can use 'panel' for the display mode. If you want it to automatically switch like Maps.app on iOS, you can set the display mode to 'automatic'.
157 | 16. You can apply a custom mask to the Pulley drawer by setting your drawerViewController's view.layer.mask property to a CAShapeLayer. That mask will also be applied to the drawer in Pulley.
158 | 17. You can specify which corner you'd like the panel to display in (when in 'panel' displayMode) by using the 'panelCornerPlacement` property.
159 |
160 | ## Requirements
161 |
162 | - iOS 9.0+
163 | - Swift 4.0+
164 |
165 |
166 |
--------------------------------------------------------------------------------
/Pulley.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 355DBF171E40EA4300671CDD /* Pulley.h in Headers */ = {isa = PBXBuildFile; fileRef = 355DBF151E40EA4300671CDD /* Pulley.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 355DBF1A1E40EA4300671CDD /* Pulley.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 355DBF131E40EA4300671CDD /* Pulley.framework */; };
12 | 355DBF1B1E40EA4300671CDD /* Pulley.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 355DBF131E40EA4300671CDD /* Pulley.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
13 | 355DBF201E40EA5C00671CDD /* PulleyPassthroughScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6131BB71D305995002F27F3 /* PulleyPassthroughScrollView.swift */; };
14 | 355DBF211E40EA5F00671CDD /* PulleyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6131BB81D305995002F27F3 /* PulleyViewController.swift */; };
15 | 853FCF2622F9F98F006829F2 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 853FCF2422F9F98D006829F2 /* MapKit.framework */; };
16 | C6131BB41D30429E002F27F3 /* PrimaryTransitionTargetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6131BB31D30429E002F27F3 /* PrimaryTransitionTargetViewController.swift */; };
17 | C6C51DDD1F5108980079B57F /* UIView+constrainToParent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6C51DDC1F5108980079B57F /* UIView+constrainToParent.swift */; };
18 | C6DF73D31D2DE2B500735EBC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DF73D21D2DE2B500735EBC /* AppDelegate.swift */; };
19 | C6DF73D51D2DE2B500735EBC /* PrimaryContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DF73D41D2DE2B500735EBC /* PrimaryContentViewController.swift */; };
20 | C6DF73DA1D2DE2B500735EBC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C6DF73D91D2DE2B500735EBC /* Assets.xcassets */; };
21 | C6DF73DD1D2DE2B500735EBC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6DF73DB1D2DE2B500735EBC /* LaunchScreen.storyboard */; };
22 | C6DF73EA1D2DFE7F00735EBC /* DrawerContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DF73E91D2DFE7F00735EBC /* DrawerContentViewController.swift */; };
23 | C6DF73EC1D2E027500735EBC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C6DF73EB1D2E027500735EBC /* Main.storyboard */; };
24 | D2C07C7C2129BC8B00ED38D7 /* CustomMaskExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C07C7A2129BC0F00ED38D7 /* CustomMaskExample.swift */; };
25 | E15E853120BE56B900800173 /* UIViewController+PulleyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E15E853020BE56B900800173 /* UIViewController+PulleyViewController.swift */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | 355DBF181E40EA4300671CDD /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = C6DF73C71D2DE2B500735EBC /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 355DBF121E40EA4300671CDD;
34 | remoteInfo = Pulley;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXCopyFilesBuildPhase section */
39 | 355DBF1F1E40EA4300671CDD /* Embed Frameworks */ = {
40 | isa = PBXCopyFilesBuildPhase;
41 | buildActionMask = 2147483647;
42 | dstPath = "";
43 | dstSubfolderSpec = 10;
44 | files = (
45 | 355DBF1B1E40EA4300671CDD /* Pulley.framework in Embed Frameworks */,
46 | );
47 | name = "Embed Frameworks";
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXCopyFilesBuildPhase section */
51 |
52 | /* Begin PBXFileReference section */
53 | 355DBF131E40EA4300671CDD /* Pulley.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pulley.framework; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 355DBF151E40EA4300671CDD /* Pulley.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pulley.h; sourceTree = ""; };
55 | 355DBF161E40EA4300671CDD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | 853FCF2422F9F98D006829F2 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
57 | C6131BB31D30429E002F27F3 /* PrimaryTransitionTargetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimaryTransitionTargetViewController.swift; sourceTree = ""; };
58 | C6131BB71D305995002F27F3 /* PulleyPassthroughScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PulleyPassthroughScrollView.swift; path = PulleyLib/PulleyPassthroughScrollView.swift; sourceTree = SOURCE_ROOT; };
59 | C6131BB81D305995002F27F3 /* PulleyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PulleyViewController.swift; path = PulleyLib/PulleyViewController.swift; sourceTree = SOURCE_ROOT; };
60 | C6C51DDC1F5108980079B57F /* UIView+constrainToParent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "UIView+constrainToParent.swift"; path = "PulleyLib/UIView+constrainToParent.swift"; sourceTree = SOURCE_ROOT; };
61 | C6DF73CF1D2DE2B500735EBC /* PulleyDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PulleyDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
62 | C6DF73D21D2DE2B500735EBC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
63 | C6DF73D41D2DE2B500735EBC /* PrimaryContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryContentViewController.swift; sourceTree = ""; };
64 | C6DF73D91D2DE2B500735EBC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
65 | C6DF73DC1D2DE2B500735EBC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
66 | C6DF73DE1D2DE2B500735EBC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
67 | C6DF73E91D2DFE7F00735EBC /* DrawerContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerContentViewController.swift; sourceTree = ""; };
68 | C6DF73EB1D2E027500735EBC /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; };
69 | D2C07C7A2129BC0F00ED38D7 /* CustomMaskExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMaskExample.swift; sourceTree = ""; };
70 | E15E853020BE56B900800173 /* UIViewController+PulleyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+PulleyViewController.swift"; path = "PulleyLib/UIViewController+PulleyViewController.swift"; sourceTree = SOURCE_ROOT; };
71 | /* End PBXFileReference section */
72 |
73 | /* Begin PBXFrameworksBuildPhase section */
74 | 355DBF0F1E40EA4300671CDD /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | C6DF73CC1D2DE2B500735EBC /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | 853FCF2622F9F98F006829F2 /* MapKit.framework in Frameworks */,
86 | 355DBF1A1E40EA4300671CDD /* Pulley.framework in Frameworks */,
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | /* End PBXFrameworksBuildPhase section */
91 |
92 | /* Begin PBXGroup section */
93 | 355DBF141E40EA4300671CDD /* Pulley */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 355DBF151E40EA4300671CDD /* Pulley.h */,
97 | E15E853020BE56B900800173 /* UIViewController+PulleyViewController.swift */,
98 | C6131BB71D305995002F27F3 /* PulleyPassthroughScrollView.swift */,
99 | C6131BB81D305995002F27F3 /* PulleyViewController.swift */,
100 | C6C51DDC1F5108980079B57F /* UIView+constrainToParent.swift */,
101 | 355DBF161E40EA4300671CDD /* Info.plist */,
102 | );
103 | path = Pulley;
104 | sourceTree = "";
105 | };
106 | 853FCF2322F9F98D006829F2 /* Frameworks */ = {
107 | isa = PBXGroup;
108 | children = (
109 | 853FCF2422F9F98D006829F2 /* MapKit.framework */,
110 | );
111 | name = Frameworks;
112 | sourceTree = "";
113 | };
114 | C6131BB21D303FE0002F27F3 /* Supporting Files */ = {
115 | isa = PBXGroup;
116 | children = (
117 | C6DF73D91D2DE2B500735EBC /* Assets.xcassets */,
118 | C6DF73DE1D2DE2B500735EBC /* Info.plist */,
119 | C6DF73DB1D2DE2B500735EBC /* LaunchScreen.storyboard */,
120 | );
121 | name = "Supporting Files";
122 | sourceTree = "";
123 | };
124 | C6DF73C61D2DE2B500735EBC = {
125 | isa = PBXGroup;
126 | children = (
127 | C6DF73D11D2DE2B500735EBC /* Demo App */,
128 | 355DBF141E40EA4300671CDD /* Pulley */,
129 | C6DF73D01D2DE2B500735EBC /* Products */,
130 | 853FCF2322F9F98D006829F2 /* Frameworks */,
131 | );
132 | sourceTree = "";
133 | };
134 | C6DF73D01D2DE2B500735EBC /* Products */ = {
135 | isa = PBXGroup;
136 | children = (
137 | C6DF73CF1D2DE2B500735EBC /* PulleyDemo.app */,
138 | 355DBF131E40EA4300671CDD /* Pulley.framework */,
139 | );
140 | name = Products;
141 | sourceTree = "";
142 | };
143 | C6DF73D11D2DE2B500735EBC /* Demo App */ = {
144 | isa = PBXGroup;
145 | children = (
146 | C6DF73EB1D2E027500735EBC /* Main.storyboard */,
147 | C6DF73D21D2DE2B500735EBC /* AppDelegate.swift */,
148 | C6DF73D41D2DE2B500735EBC /* PrimaryContentViewController.swift */,
149 | C6DF73E91D2DFE7F00735EBC /* DrawerContentViewController.swift */,
150 | C6131BB31D30429E002F27F3 /* PrimaryTransitionTargetViewController.swift */,
151 | D2C07C7A2129BC0F00ED38D7 /* CustomMaskExample.swift */,
152 | C6131BB21D303FE0002F27F3 /* Supporting Files */,
153 | );
154 | name = "Demo App";
155 | path = Pulley;
156 | sourceTree = "";
157 | };
158 | /* End PBXGroup section */
159 |
160 | /* Begin PBXHeadersBuildPhase section */
161 | 355DBF101E40EA4300671CDD /* Headers */ = {
162 | isa = PBXHeadersBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | 355DBF171E40EA4300671CDD /* Pulley.h in Headers */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXHeadersBuildPhase section */
170 |
171 | /* Begin PBXNativeTarget section */
172 | 355DBF121E40EA4300671CDD /* Pulley */ = {
173 | isa = PBXNativeTarget;
174 | buildConfigurationList = 355DBF1C1E40EA4300671CDD /* Build configuration list for PBXNativeTarget "Pulley" */;
175 | buildPhases = (
176 | 355DBF0E1E40EA4300671CDD /* Sources */,
177 | 355DBF0F1E40EA4300671CDD /* Frameworks */,
178 | 355DBF101E40EA4300671CDD /* Headers */,
179 | 355DBF111E40EA4300671CDD /* Resources */,
180 | );
181 | buildRules = (
182 | );
183 | dependencies = (
184 | );
185 | name = Pulley;
186 | productName = Pulley;
187 | productReference = 355DBF131E40EA4300671CDD /* Pulley.framework */;
188 | productType = "com.apple.product-type.framework";
189 | };
190 | C6DF73CE1D2DE2B500735EBC /* PulleyDemo */ = {
191 | isa = PBXNativeTarget;
192 | buildConfigurationList = C6DF73E11D2DE2B500735EBC /* Build configuration list for PBXNativeTarget "PulleyDemo" */;
193 | buildPhases = (
194 | C6DF73CB1D2DE2B500735EBC /* Sources */,
195 | C6DF73CC1D2DE2B500735EBC /* Frameworks */,
196 | C6DF73CD1D2DE2B500735EBC /* Resources */,
197 | 355DBF1F1E40EA4300671CDD /* Embed Frameworks */,
198 | );
199 | buildRules = (
200 | );
201 | dependencies = (
202 | 355DBF191E40EA4300671CDD /* PBXTargetDependency */,
203 | );
204 | name = PulleyDemo;
205 | productName = Pulley;
206 | productReference = C6DF73CF1D2DE2B500735EBC /* PulleyDemo.app */;
207 | productType = "com.apple.product-type.application";
208 | };
209 | /* End PBXNativeTarget section */
210 |
211 | /* Begin PBXProject section */
212 | C6DF73C71D2DE2B500735EBC /* Project object */ = {
213 | isa = PBXProject;
214 | attributes = {
215 | LastSwiftUpdateCheck = 0730;
216 | LastUpgradeCheck = 1200;
217 | ORGANIZATIONNAME = 52inc;
218 | TargetAttributes = {
219 | 355DBF121E40EA4300671CDD = {
220 | CreatedOnToolsVersion = 8.2.1;
221 | DevelopmentTeam = P87N88ZC7B;
222 | LastSwiftMigration = 1020;
223 | ProvisioningStyle = Automatic;
224 | };
225 | C6DF73CE1D2DE2B500735EBC = {
226 | CreatedOnToolsVersion = 7.3.1;
227 | DevelopmentTeam = P87N88ZC7B;
228 | LastSwiftMigration = 1020;
229 | };
230 | };
231 | };
232 | buildConfigurationList = C6DF73CA1D2DE2B500735EBC /* Build configuration list for PBXProject "Pulley" */;
233 | compatibilityVersion = "Xcode 3.2";
234 | developmentRegion = en;
235 | hasScannedForEncodings = 0;
236 | knownRegions = (
237 | en,
238 | Base,
239 | );
240 | mainGroup = C6DF73C61D2DE2B500735EBC;
241 | productRefGroup = C6DF73D01D2DE2B500735EBC /* Products */;
242 | projectDirPath = "";
243 | projectRoot = "";
244 | targets = (
245 | 355DBF121E40EA4300671CDD /* Pulley */,
246 | C6DF73CE1D2DE2B500735EBC /* PulleyDemo */,
247 | );
248 | };
249 | /* End PBXProject section */
250 |
251 | /* Begin PBXResourcesBuildPhase section */
252 | 355DBF111E40EA4300671CDD /* Resources */ = {
253 | isa = PBXResourcesBuildPhase;
254 | buildActionMask = 2147483647;
255 | files = (
256 | );
257 | runOnlyForDeploymentPostprocessing = 0;
258 | };
259 | C6DF73CD1D2DE2B500735EBC /* Resources */ = {
260 | isa = PBXResourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | C6DF73EC1D2E027500735EBC /* Main.storyboard in Resources */,
264 | C6DF73DD1D2DE2B500735EBC /* LaunchScreen.storyboard in Resources */,
265 | C6DF73DA1D2DE2B500735EBC /* Assets.xcassets in Resources */,
266 | );
267 | runOnlyForDeploymentPostprocessing = 0;
268 | };
269 | /* End PBXResourcesBuildPhase section */
270 |
271 | /* Begin PBXSourcesBuildPhase section */
272 | 355DBF0E1E40EA4300671CDD /* Sources */ = {
273 | isa = PBXSourcesBuildPhase;
274 | buildActionMask = 2147483647;
275 | files = (
276 | E15E853120BE56B900800173 /* UIViewController+PulleyViewController.swift in Sources */,
277 | 355DBF201E40EA5C00671CDD /* PulleyPassthroughScrollView.swift in Sources */,
278 | 355DBF211E40EA5F00671CDD /* PulleyViewController.swift in Sources */,
279 | C6C51DDD1F5108980079B57F /* UIView+constrainToParent.swift in Sources */,
280 | );
281 | runOnlyForDeploymentPostprocessing = 0;
282 | };
283 | C6DF73CB1D2DE2B500735EBC /* Sources */ = {
284 | isa = PBXSourcesBuildPhase;
285 | buildActionMask = 2147483647;
286 | files = (
287 | C6131BB41D30429E002F27F3 /* PrimaryTransitionTargetViewController.swift in Sources */,
288 | D2C07C7C2129BC8B00ED38D7 /* CustomMaskExample.swift in Sources */,
289 | C6DF73D51D2DE2B500735EBC /* PrimaryContentViewController.swift in Sources */,
290 | C6DF73EA1D2DFE7F00735EBC /* DrawerContentViewController.swift in Sources */,
291 | C6DF73D31D2DE2B500735EBC /* AppDelegate.swift in Sources */,
292 | );
293 | runOnlyForDeploymentPostprocessing = 0;
294 | };
295 | /* End PBXSourcesBuildPhase section */
296 |
297 | /* Begin PBXTargetDependency section */
298 | 355DBF191E40EA4300671CDD /* PBXTargetDependency */ = {
299 | isa = PBXTargetDependency;
300 | target = 355DBF121E40EA4300671CDD /* Pulley */;
301 | targetProxy = 355DBF181E40EA4300671CDD /* PBXContainerItemProxy */;
302 | };
303 | /* End PBXTargetDependency section */
304 |
305 | /* Begin PBXVariantGroup section */
306 | C6DF73DB1D2DE2B500735EBC /* LaunchScreen.storyboard */ = {
307 | isa = PBXVariantGroup;
308 | children = (
309 | C6DF73DC1D2DE2B500735EBC /* Base */,
310 | );
311 | name = LaunchScreen.storyboard;
312 | sourceTree = "";
313 | };
314 | /* End PBXVariantGroup section */
315 |
316 | /* Begin XCBuildConfiguration section */
317 | 355DBF1D1E40EA4300671CDD /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
321 | CLANG_WARN_INFINITE_RECURSION = YES;
322 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
323 | CODE_SIGN_IDENTITY = "";
324 | CURRENT_PROJECT_VERSION = 1;
325 | DEFINES_MODULE = YES;
326 | DEVELOPMENT_TEAM = P87N88ZC7B;
327 | DYLIB_COMPATIBILITY_VERSION = 1;
328 | DYLIB_CURRENT_VERSION = 1;
329 | DYLIB_INSTALL_NAME_BASE = "@rpath";
330 | INFOPLIST_FILE = Pulley/Info.plist;
331 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
332 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
333 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
334 | PRODUCT_BUNDLE_IDENTIFIER = com.52inc.Pulley.Pulley;
335 | PRODUCT_NAME = "$(TARGET_NAME)";
336 | SKIP_INSTALL = YES;
337 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
338 | SWIFT_VERSION = 5.0;
339 | VERSIONING_SYSTEM = "apple-generic";
340 | VERSION_INFO_PREFIX = "";
341 | };
342 | name = Debug;
343 | };
344 | 355DBF1E1E40EA4300671CDD /* Release */ = {
345 | isa = XCBuildConfiguration;
346 | buildSettings = {
347 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
348 | CLANG_WARN_INFINITE_RECURSION = YES;
349 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
350 | CODE_SIGN_IDENTITY = "";
351 | CURRENT_PROJECT_VERSION = 1;
352 | DEFINES_MODULE = YES;
353 | DEVELOPMENT_TEAM = P87N88ZC7B;
354 | DYLIB_COMPATIBILITY_VERSION = 1;
355 | DYLIB_CURRENT_VERSION = 1;
356 | DYLIB_INSTALL_NAME_BASE = "@rpath";
357 | INFOPLIST_FILE = Pulley/Info.plist;
358 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
359 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
360 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
361 | PRODUCT_BUNDLE_IDENTIFIER = com.52inc.Pulley.Pulley;
362 | PRODUCT_NAME = "$(TARGET_NAME)";
363 | SKIP_INSTALL = YES;
364 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
365 | SWIFT_VERSION = 5.0;
366 | VERSIONING_SYSTEM = "apple-generic";
367 | VERSION_INFO_PREFIX = "";
368 | };
369 | name = Release;
370 | };
371 | C6DF73DF1D2DE2B500735EBC /* Debug */ = {
372 | isa = XCBuildConfiguration;
373 | buildSettings = {
374 | ALWAYS_SEARCH_USER_PATHS = NO;
375 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
376 | CLANG_ANALYZER_NONNULL = YES;
377 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
378 | CLANG_CXX_LIBRARY = "libc++";
379 | CLANG_ENABLE_MODULES = YES;
380 | CLANG_ENABLE_OBJC_ARC = YES;
381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
382 | CLANG_WARN_BOOL_CONVERSION = YES;
383 | CLANG_WARN_COMMA = YES;
384 | CLANG_WARN_CONSTANT_CONVERSION = YES;
385 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
386 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
387 | CLANG_WARN_EMPTY_BODY = YES;
388 | CLANG_WARN_ENUM_CONVERSION = YES;
389 | CLANG_WARN_INFINITE_RECURSION = YES;
390 | CLANG_WARN_INT_CONVERSION = YES;
391 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
392 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
393 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
394 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
395 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
397 | CLANG_WARN_STRICT_PROTOTYPES = YES;
398 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
399 | CLANG_WARN_UNREACHABLE_CODE = YES;
400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
401 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
402 | COPY_PHASE_STRIP = NO;
403 | DEBUG_INFORMATION_FORMAT = dwarf;
404 | ENABLE_STRICT_OBJC_MSGSEND = YES;
405 | ENABLE_TESTABILITY = YES;
406 | GCC_C_LANGUAGE_STANDARD = gnu99;
407 | GCC_DYNAMIC_NO_PIC = NO;
408 | GCC_NO_COMMON_BLOCKS = YES;
409 | GCC_OPTIMIZATION_LEVEL = 0;
410 | GCC_PREPROCESSOR_DEFINITIONS = (
411 | "DEBUG=1",
412 | "$(inherited)",
413 | );
414 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
415 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
416 | GCC_WARN_UNDECLARED_SELECTOR = YES;
417 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
418 | GCC_WARN_UNUSED_FUNCTION = YES;
419 | GCC_WARN_UNUSED_VARIABLE = YES;
420 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
421 | MTL_ENABLE_DEBUG_INFO = YES;
422 | ONLY_ACTIVE_ARCH = YES;
423 | SDKROOT = iphoneos;
424 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
425 | TARGETED_DEVICE_FAMILY = "1,2";
426 | };
427 | name = Debug;
428 | };
429 | C6DF73E01D2DE2B500735EBC /* Release */ = {
430 | isa = XCBuildConfiguration;
431 | buildSettings = {
432 | ALWAYS_SEARCH_USER_PATHS = NO;
433 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
434 | CLANG_ANALYZER_NONNULL = YES;
435 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
436 | CLANG_CXX_LIBRARY = "libc++";
437 | CLANG_ENABLE_MODULES = YES;
438 | CLANG_ENABLE_OBJC_ARC = YES;
439 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
440 | CLANG_WARN_BOOL_CONVERSION = YES;
441 | CLANG_WARN_COMMA = YES;
442 | CLANG_WARN_CONSTANT_CONVERSION = YES;
443 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
444 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
445 | CLANG_WARN_EMPTY_BODY = YES;
446 | CLANG_WARN_ENUM_CONVERSION = YES;
447 | CLANG_WARN_INFINITE_RECURSION = YES;
448 | CLANG_WARN_INT_CONVERSION = YES;
449 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
450 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
451 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
453 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
454 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
455 | CLANG_WARN_STRICT_PROTOTYPES = YES;
456 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
457 | CLANG_WARN_UNREACHABLE_CODE = YES;
458 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
459 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
460 | COPY_PHASE_STRIP = NO;
461 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
462 | ENABLE_NS_ASSERTIONS = NO;
463 | ENABLE_STRICT_OBJC_MSGSEND = YES;
464 | GCC_C_LANGUAGE_STANDARD = gnu99;
465 | GCC_NO_COMMON_BLOCKS = YES;
466 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
467 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
468 | GCC_WARN_UNDECLARED_SELECTOR = YES;
469 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
470 | GCC_WARN_UNUSED_FUNCTION = YES;
471 | GCC_WARN_UNUSED_VARIABLE = YES;
472 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
473 | MTL_ENABLE_DEBUG_INFO = NO;
474 | SDKROOT = iphoneos;
475 | TARGETED_DEVICE_FAMILY = "1,2";
476 | VALIDATE_PRODUCT = YES;
477 | };
478 | name = Release;
479 | };
480 | C6DF73E21D2DE2B500735EBC /* Debug */ = {
481 | isa = XCBuildConfiguration;
482 | buildSettings = {
483 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
484 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
485 | CURRENT_PROJECT_VERSION = 1;
486 | DEVELOPMENT_TEAM = P87N88ZC7B;
487 | INFOPLIST_FILE = Pulley/Info.plist;
488 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
490 | PRODUCT_BUNDLE_IDENTIFIER = com.52inc.Pulley;
491 | PRODUCT_NAME = PulleyDemo;
492 | SWIFT_VERSION = 5.0;
493 | };
494 | name = Debug;
495 | };
496 | C6DF73E31D2DE2B500735EBC /* Release */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
500 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
501 | CURRENT_PROJECT_VERSION = 1;
502 | DEVELOPMENT_TEAM = P87N88ZC7B;
503 | INFOPLIST_FILE = Pulley/Info.plist;
504 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
506 | PRODUCT_BUNDLE_IDENTIFIER = com.52inc.Pulley;
507 | PRODUCT_NAME = PulleyDemo;
508 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
509 | SWIFT_VERSION = 5.0;
510 | };
511 | name = Release;
512 | };
513 | /* End XCBuildConfiguration section */
514 |
515 | /* Begin XCConfigurationList section */
516 | 355DBF1C1E40EA4300671CDD /* Build configuration list for PBXNativeTarget "Pulley" */ = {
517 | isa = XCConfigurationList;
518 | buildConfigurations = (
519 | 355DBF1D1E40EA4300671CDD /* Debug */,
520 | 355DBF1E1E40EA4300671CDD /* Release */,
521 | );
522 | defaultConfigurationIsVisible = 0;
523 | defaultConfigurationName = Release;
524 | };
525 | C6DF73CA1D2DE2B500735EBC /* Build configuration list for PBXProject "Pulley" */ = {
526 | isa = XCConfigurationList;
527 | buildConfigurations = (
528 | C6DF73DF1D2DE2B500735EBC /* Debug */,
529 | C6DF73E01D2DE2B500735EBC /* Release */,
530 | );
531 | defaultConfigurationIsVisible = 0;
532 | defaultConfigurationName = Release;
533 | };
534 | C6DF73E11D2DE2B500735EBC /* Build configuration list for PBXNativeTarget "PulleyDemo" */ = {
535 | isa = XCConfigurationList;
536 | buildConfigurations = (
537 | C6DF73E21D2DE2B500735EBC /* Debug */,
538 | C6DF73E31D2DE2B500735EBC /* Release */,
539 | );
540 | defaultConfigurationIsVisible = 0;
541 | defaultConfigurationName = Release;
542 | };
543 | /* End XCConfigurationList section */
544 | };
545 | rootObject = C6DF73C71D2DE2B500735EBC /* Project object */;
546 | }
547 |
--------------------------------------------------------------------------------
/Pulley/Main.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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
87 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
236 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
369 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
--------------------------------------------------------------------------------