├── Drawer
├── Sources
│ └── Drawer
│ │ ├── DrawerModels.swift
│ │ ├── DrawerCoordinator.swift
│ │ └── DrawerviewController.swift
├── Example
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Scenes
│ │ ├── Background View Controller
│ │ │ ├── ViewController.swift
│ │ │ └── Base.lproj
│ │ │ │ └── Main.storyboard
│ │ └── Content View Controller
│ │ │ ├── ContentViewController.swift
│ │ │ └── ContentViewController.storyboard
│ ├── Info.plist
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ └── AppDelegate.swift
├── Drawer.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── Drawer.xcscheme
│ └── project.pbxproj
├── Drawer
│ ├── Drawer
│ │ ├── Protocols
│ │ │ ├── EmbeddableContentDelegate.swift
│ │ │ ├── EmbeddedScrollable.swift
│ │ │ └── Embeddable.swift
│ │ ├── DrawerCoordinator.swift
│ │ ├── DrawerModels.swift
│ │ └── DrawerViewController.swift
│ ├── Drawer.h
│ ├── Extensions
│ │ └── UIView+Superview.swift
│ ├── Info.plist
│ └── Touch Intercepting View
│ │ └── TouchInterceptingView.swift
├── DrawerTests
│ ├── Info.plist
│ └── DrawerTests.swift
└── ExampleTests
│ ├── Info.plist
│ └── ExampleTests.swift
├── Sources
└── Drawer
│ ├── DrawerModels.swift
│ ├── DrawerCoordinator.swift
│ ├── Embeddable.swift
│ ├── UIView+Superview.swift
│ ├── DrawerViewController.swift
│ ├── EmbeddedScrollable.swift
│ ├── TouchInterceptingView.swift
│ └── EmbeddableContentDelegate.swift
├── drawer_close.gif
├── drawer_open.gif
├── Drawer.framework.zip
├── NDrawer.podspec
├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── LICENSE
├── .circleci
└── config.yml
├── Package.swift
├── .gitignore
└── README.md
/Drawer/Sources/Drawer/DrawerModels.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/DrawerModels.swift
--------------------------------------------------------------------------------
/Sources/Drawer/DrawerModels.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/DrawerModels.swift
--------------------------------------------------------------------------------
/Drawer/Sources/Drawer/DrawerCoordinator.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/DrawerCoordinator.swift
--------------------------------------------------------------------------------
/Sources/Drawer/DrawerCoordinator.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/DrawerCoordinator.swift
--------------------------------------------------------------------------------
/Sources/Drawer/Embeddable.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/Protocols/Embeddable.swift
--------------------------------------------------------------------------------
/drawer_close.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ml-archive/Drawer/master/drawer_close.gif
--------------------------------------------------------------------------------
/drawer_open.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ml-archive/Drawer/master/drawer_open.gif
--------------------------------------------------------------------------------
/Sources/Drawer/UIView+Superview.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Extensions/UIView+Superview.swift
--------------------------------------------------------------------------------
/Drawer.framework.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ml-archive/Drawer/master/Drawer.framework.zip
--------------------------------------------------------------------------------
/Drawer/Sources/Drawer/DrawerviewController.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/DrawerviewController.swift
--------------------------------------------------------------------------------
/Sources/Drawer/DrawerViewController.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/DrawerViewController.swift
--------------------------------------------------------------------------------
/Sources/Drawer/EmbeddedScrollable.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/Protocols/EmbeddedScrollable.swift
--------------------------------------------------------------------------------
/Sources/Drawer/TouchInterceptingView.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Touch Intercepting View/TouchInterceptingView.swift
--------------------------------------------------------------------------------
/Sources/Drawer/EmbeddableContentDelegate.swift:
--------------------------------------------------------------------------------
1 | ../../Drawer/Drawer/Drawer/Protocols/EmbeddableContentDelegate.swift
--------------------------------------------------------------------------------
/Drawer/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Drawer/Drawer.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Drawer/Drawer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/Protocols/EmbeddableContentDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbeddableContentDelegate.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public protocol EmbeddableContentDelegate: class {
13 | func handle(action: Drawer.Action)
14 | var maxAllowedHeight: CGFloat { get }
15 | }
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Drawer.h
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for Drawer.
12 | FOUNDATION_EXPORT double DrawerVersionNumber;
13 |
14 | //! Project version string for Drawer.
15 | FOUNDATION_EXPORT const unsigned char DrawerVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Extensions/UIView+Superview.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Superview.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 |
13 | func superview(of type: T.Type) -> T? {
14 | return superview as? T ?? superview.flatMap { $0.superview(of: type) }
15 | }
16 |
17 | func subview(of type: T.Type) -> T? {
18 | return subviews.compactMap { $0 as? T ?? $0.subview(of: type) }.first
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/NDrawer.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'NDrawer'
3 | s.version = '1.0.4'
4 | s.summary = 'Drawer is a framework that enables you to easily embed a UIViewController in a drawer and display it on top of another UIViewController.'
5 | s.homepage = 'https://github.com/nodes-ios/Drawer'
6 | s.author = { "Nodes Agency - iOS" => "ios@nodes.dk" }
7 | s.license = { :type => 'MIT', :file => './LICENSE' }
8 | s.source = { :git => 'https://github.com/nodes-ios/Drawer.git', :tag => s.version.to_s }
9 |
10 | s.ios.deployment_target = '11.0'
11 |
12 | s.source_files = 'Drawer/Drawer/**/*.swift'
13 |
14 | s.swift_version = '5'
15 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '5' }
16 | end
17 |
--------------------------------------------------------------------------------
/Drawer/DrawerTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Drawer/ExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Drawer/Example/Scenes/Background View Controller/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Drawer
11 |
12 | class ViewController: UIViewController {
13 |
14 | private let contentVC = ContentViewController.instantiate()
15 | var drawer: DrawerCoordinator?
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | drawer = DrawerCoordinator(contentViewController: contentVC,
20 | backgroundViewController: self.tabBarController!,
21 | drawerBackgroundType: .withColor(UIColor.black.withAlphaComponent(0.5)))
22 | }
23 |
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **iPhone/iPad (please complete the following information):**
27 | - Device: [e.g. iPhoneX]
28 | - OS: [e.g. iOS11]
29 | - Version [e.g. 1.0]
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/Protocols/EmbeddedScrollable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EmbeddedScrollable.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // A Protocol exposed to the Application
12 | public protocol EmbeddedScrollable: Embeddable {
13 | /// Use this parameter to tell the drawer if the content UIViewContoller's embeded UIScrollView is scrolled to top.
14 | ///
15 | /// - parameters:
16 | /// - enabled: Bool
17 | ///
18 | var isScrolledToTop: Bool { get }
19 | /// Use this method to determine if the content UIViewContoller's embeded UIScrollView should allow scrolling.
20 | ///
21 | /// - parameters:
22 | /// - enabled: Bool
23 | ///
24 | func setScrollEnabled(_ enabled: Bool)
25 | }
26 |
--------------------------------------------------------------------------------
/Drawer/DrawerTests/DrawerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DrawerTests.swift
3 | // DrawerTests
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Drawer
11 |
12 | class DrawerTests: XCTestCase {
13 |
14 | override func 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 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Drawer/ExampleTests/ExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleTests.swift
3 | // ExampleTests
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Example
11 |
12 | class ExampleTests: XCTestCase {
13 |
14 | override func 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 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Nodes Agency - iOS
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 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # iOS CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/ios-migrating-from-1-2/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 |
9 | # Specify the Xcode version to use
10 | macos:
11 | xcode: "10.0"
12 |
13 | steps:
14 | - checkout
15 |
16 | # Install Carthage
17 | - run:
18 | name: Install Carthage
19 | command: carthage update --platform ios
20 |
21 | # Build the app and run tests
22 | - run:
23 | name: Build and run tests
24 | command: fastlane scan
25 | environment:
26 | SCAN_DEVICE: iPhone 6
27 | SCAN_SCHEME: WebTests
28 |
29 | # Collect XML test results data to show in the UI,
30 | # and save the same XML files under test-results folder
31 | # in the Artifacts tab
32 | - store_test_results:
33 | path: test_output/report.xml
34 | - store_artifacts:
35 | path: /tmp/test-results
36 | destination: scan-test-results
37 | - store_artifacts:
38 | path: ~/Library/Logs/scan
39 | destination: scan-logs
40 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Drawer",
8 | platforms: [
9 | .iOS(.v11),
10 | ],
11 | products: [
12 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
13 | .library(
14 | name: "Drawer",
15 | targets: ["Drawer"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
24 | .target(
25 | name: "Drawer",
26 | dependencies: []),
27 | .testTarget(
28 | name: "DrawerTests",
29 | dependencies: ["Drawer"],
30 | path: "Drawer/DrawerTests"),
31 | ]
32 | )
33 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Touch Intercepting View/TouchInterceptingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TouchInterceptingView.swift
3 | // Drawer
4 | //
5 | // Created by Jakob Mygind Jensen on 07/02/2018.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol TouchPassingWindowDelegate: class {
12 | func windowShouldBlockAll() -> Bool
13 | var viewsForInterceptingTouches: [UIView] { get }
14 | }
15 |
16 | class TouchInterceptingView: UIView {
17 |
18 | weak var delegate: TouchPassingWindowDelegate?
19 |
20 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
21 | let hitView = super.hitTest(point, with: event)
22 | if delegate?.windowShouldBlockAll() == true {
23 | return self
24 | }
25 |
26 | var isDescendant = false
27 | if let hitView = hitView, let interceptList = delegate?.viewsForInterceptingTouches {
28 | for v in interceptList {
29 | if hitView.isDescendant(of: v) {
30 | isDescendant = true
31 | }
32 | }
33 |
34 | if delegate?.viewsForInterceptingTouches.contains(hitView) == true || isDescendant {
35 | return hitView
36 | }
37 | }
38 |
39 | return nil
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/DrawerCoordinator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DrawerCoordinator.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public class DrawerCoordinator {
13 |
14 | private let backgroundViewController: UIViewController
15 | private let contentViewController: (UIViewController & Embeddable)
16 | private let drawerBackgroundType: DrawerViewController.DrawerBackgroundType
17 |
18 | public init(contentViewController: UIViewController & Embeddable,
19 | backgroundViewController: UIViewController,
20 | drawerBackgroundType: DrawerViewController.DrawerBackgroundType) {
21 | self.contentViewController = contentViewController
22 | self.backgroundViewController = backgroundViewController
23 | self.drawerBackgroundType = drawerBackgroundType
24 |
25 | start()
26 | }
27 |
28 | private func start() {
29 | if backgroundViewController.children.contains(where: { $0 is DrawerViewController }) {
30 | assertionFailure("\(backgroundViewController) already contains a Drawer. Multiple drawers not supported.")
31 | return
32 | }
33 |
34 | let drawerVC = DrawerViewController()
35 | drawerVC.contentViewController = contentViewController
36 | drawerVC.backgroundViewController = backgroundViewController
37 |
38 | drawerVC.makeViews(with: drawerBackgroundType)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Drawer/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.1
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
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 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 |
55 | Carthage/
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots/**/*.png
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/Protocols/Embeddable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Embeddable.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | // A Protocol exposed to the Application
13 | public protocol Embeddable where Self: UIViewController {
14 | /// Do not set this property directly. The drawer will assign it when it has finished creating.
15 | var embedDelegate: EmbeddableContentDelegate? { get set }
16 | /// Use this method to track upcoming changes in state. Triggered when Drawer state starts changing. This can be triggered by user Touch/Pan events or by calling the `embedDelegate` functions
17 | ///
18 | /// - parameters:
19 | /// - state: EmbeddableState
20 | ///
21 | func willChangeState(to state: EmbeddableState)
22 | /// Use this method to track changes in state.
23 | ///
24 | /// - parameters:
25 | /// - state: EmbeddableState
26 | ///
27 | func didChangeState(to state: EmbeddableState)
28 | /// Use this method to track changes of the content position.
29 | ///
30 | /// - parameters:
31 | /// - progress: CGFloat (values between 0 and 1). Example: A value of 0.1 means that the user just started the transition from state, while a value of 0.9 means that the user is getting close to finishing the transition to the oposite state of the `from state`
32 | /// - state: Drawer.State
33 | /// - direction: DrawerViewController.Direction direction of scroll
34 | ///
35 | func didScroll(with progress: CGFloat, from state: Drawer.State)
36 | }
37 |
38 | public enum EmbeddableState {
39 | case fullSize
40 | case minimized
41 | case closed
42 | }
43 |
--------------------------------------------------------------------------------
/Drawer/Example/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 |
29 |
30 |
--------------------------------------------------------------------------------
/Drawer/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Drawer/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // 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.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/DrawerModels.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomDrawerModels.swift
3 | // Drawer
4 | //
5 | // Created by Andrei Hogea on 27/02/2019.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public enum Drawer {
12 |
13 | public enum State: Int {
14 | case fullSize
15 | case minimized
16 | }
17 |
18 | internal enum ContainerInteraction: Int {
19 | case whenMinimised
20 | }
21 |
22 | public enum Action {
23 | case layoutUpdated(config: Drawer.Configuration)
24 | case changeState(to: MovementState)
25 |
26 | public enum MovementState: Int {
27 | case minimize
28 | case fullScreen
29 | case dismiss
30 | }
31 | }
32 |
33 | public struct Configuration {
34 |
35 | let duration: TimeInterval
36 | let embeddedFullHeight: CGFloat
37 | let embeddedMinimumHeight: CGFloat
38 | let state: Drawer.State
39 | let cornerRadius: Configuration.CornerRadius
40 | let dismissCompleteCallback: (() -> Void)?
41 |
42 | /**
43 | Creates a Configuration for the Drawer
44 |
45 | - Parameter options: Use options to configure the Drawer.
46 | - Parameter dismissCompleteCallback: Called when the Drawer has finished dismissing
47 |
48 | Available configurations:
49 | - .animationDuration: TimeInterval
50 | -- default value is 0.3
51 |
52 | - .fullHeight: CGFloat
53 | -- default value is 300
54 |
55 | - .minimumHeight: CGFloat
56 | -- default value is 100
57 |
58 | - .initialState: Drawer.State
59 | -- default value is .minimized
60 |
61 | - .cornerRadius: ContentConfiguration.CornerRadius
62 | -- default value is CornerRadius(fullSize: 0, minimized: 0)
63 |
64 | */
65 | public init(options: [Drawer.Configuration.Key: Any],
66 | dismissCompleteCallback: (() -> Void)? = nil) {
67 |
68 | duration = options[.animationDuration] as? TimeInterval ?? 0.3
69 | embeddedFullHeight = options[.fullHeight] as? CGFloat ?? 300
70 | embeddedMinimumHeight = options[.minimumHeight] as? CGFloat ?? 100
71 | state = options[.initialState] as? Drawer.State ?? .minimized
72 | cornerRadius = options[.cornerRadius] as? Configuration.CornerRadius ?? Configuration.CornerRadius(fullSize: 0, minimized: 0)
73 |
74 |
75 | self.dismissCompleteCallback = dismissCompleteCallback
76 | }
77 |
78 | public enum Key: String, CaseIterable {
79 | case animationDuration
80 | case fullHeight
81 | case minimumHeight
82 | case initialState
83 | case cornerRadius
84 | }
85 |
86 | public struct CornerRadius {
87 | let fullSize: CGFloat
88 | let minimized: CGFloat
89 |
90 | public init(fullSize: CGFloat, minimized: CGFloat) {
91 | self.fullSize = fullSize
92 | self.minimized = minimized
93 | }
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/Drawer/Drawer.xcodeproj/xcshareddata/xcschemes/Drawer.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### This library has been deprecated and the repo has been archived.
2 | ### The code is still here and you can still clone it, however the library will not receive any more updates or support.
3 |
4 | [](https://github.com/Carthage/Carthage)
5 | 
6 | [](https://github.com/nodes-ios/Drawer/blob/master/LICENSE)
7 | [](https://circleci.com/gh/nodes-ios/Drawer)
8 |
9 | ## Intro
10 |
11 | `Drawer` is a framework that enables you to easily embed a `UIViewController` in a drawer and display it on top of another `UIViewController`.
12 |
13 | 
14 | 
15 |
16 | ## 📝 Requirements
17 |
18 | - iOS 11
19 | - Swift 4.0+
20 |
21 | ## 📦 Installation
22 |
23 | ### Carthage
24 | ~~~bash
25 | github "nodes-ios/Drawer"
26 | ~~~
27 |
28 | ### Cocoapods
29 | ~~~bash
30 | pod 'NDrawer'
31 | ~~~
32 |
33 | ## 💻 Usage
34 |
35 | ### Requirements
36 |
37 | * A `UIViewController` for the drawer to be displayed over. This `ViewController` is referred to as the `backgroundViewController` in the following steps
38 | * A `UIViewController` to act as the content of the drawer. This `ViewController` is referred to as the `contentViewController` in the following steps.
39 |
40 | ### Steps
41 |
42 | #### Creating a Drawer
43 | Start by conforming your `contentViewController` to the `Embeddable` protocol. This exposes several delegate functions to the `contentViewController`.
44 |
45 | ```swift
46 | extension ContentViewController: Embeddable {}
47 | ```
48 |
49 | Furthermore an instance of `EmbeddableContentDelegate` is exposed. This `delegate` can be used to instruct the drawer to perform various tasks by calling the `handle` function on it.
50 |
51 | The `handle` function takes an `enum` of type `Drawer.Action` which allows these actions:
52 |
53 | - `layoutUpdated(config: Drawer.Configuration)` to update the layout of your drawer
54 | - `changeState(to: MovementState)` to show/hide your drawer.
55 |
56 | After creating the `contentViewController`, initialize an instance of `DrawerCoordinator` in your `backgroundViewController` to initialize the drawer.
57 |
58 | ```swift
59 | let drawer = DrawerCoordinator(contentViewController: contentVC,
60 | backgroundViewController: self,
61 | drawerBackgroundType: .withColor(UIColor.black.withAlphaComponent(0.5)))
62 | ```
63 |
64 | #### Displaying a Drawer
65 | After your content's views have finished creating and you are ready to display the drawer, create an instance of `Drawer.Configuration` to set the drawer state and properties.
66 |
67 | ```swift
68 |
69 | let options: [Drawer.Configuration.Key : Any] = [
70 | .animationDuration: 0.5,
71 | .fullHeight: maxHeight,
72 | .minimumHeight: minHeight,
73 | .initialState: Drawer.State.minimized,
74 | .cornerRadius: Drawer.Configuration.CornerRadius(fullSize: 20,
75 | minimized: 0)
76 | ]
77 |
78 | let contentConfiguration = Drawer.Configuration(options: options,
79 | dismissCompleteCallback: nil)
80 |
81 | ```
82 |
83 | Communication with the `EmbeddableContentDelegate` is managed by calling the `handle` function, which takes an `enum` of type `Drawer.Action` as a parameter.
84 | Finally call the `EmbeddableContentDelegate` `handle` function to update the drawer's layout to the new `Configuration`
85 |
86 | ```swift
87 | embedDelegate?.handle(action: .layoutUpdated(config: contentConfiguration))
88 | ```
89 |
90 | #### Expanding and Collapsing a Drawer
91 | To expand and collapse the drawer programatically, call the `EmbeddableContentDelegate` `handle` function with a `changeState` action containing the state which the drawer should transition to.
92 |
93 | ```swift
94 | embedDelegate?.handle(action: .changeState(to: .fullScreen))
95 | ```
96 |
97 | ## Example Project
98 | To learn more, please refer to the example project contained in this repository.
99 |
100 | ## 👥 Credits
101 | Made with ❤️ at [Nodes](http://nodesagency.com).
102 |
103 | ## 📄 License
104 | **Drawer** is available under the MIT license. See the [LICENSE](https://github.com/nodes-ios/DrawerI/blob/master/LICENSE) file for more info.
105 |
--------------------------------------------------------------------------------
/Drawer/Example/Scenes/Content View Controller/ContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentViewController.swift
3 | // DrawerExample
4 | //
5 | // Created by Andrei Hogea on 26/02/2019.
6 | // Copyright (c) 2019 Andrei Hogea. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Drawer
11 |
12 | class ContentViewController: UIViewController {
13 |
14 | // MARK: - Outlets
15 |
16 | @IBOutlet weak var expandButton: UIButton!
17 | @IBOutlet weak var collapseButton: UIButton!
18 | @IBOutlet weak var titleLabel: UILabel!
19 |
20 | // MARK: - Properties
21 |
22 | var embedDelegate: EmbeddableContentDelegate?
23 | private var animationDuration: TimeInterval = 1
24 |
25 | // title animations
26 | private var runningAnimators: [UIViewPropertyAnimator] = []
27 | private var titleAnimator: UIViewPropertyAnimator!
28 | private let titleScaleMax: CGFloat = 1.6
29 |
30 | // MARK: - Init
31 |
32 | class func instantiate() -> ContentViewController {
33 | let name = "\(ContentViewController.self)"
34 | let storyboard = UIStoryboard(name: name, bundle: nil)
35 | return storyboard.instantiateViewController(withIdentifier: name) as! ContentViewController
36 | }
37 |
38 | // MARK: - View Lifecycle -
39 |
40 | override func viewDidLoad() {
41 | super.viewDidLoad()
42 |
43 | titleAnimator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1)
44 | titleAnimator.addAnimations {
45 |
46 | }
47 | adjustDrawer(with: 400, with: 100)
48 | }
49 |
50 | override func viewDidLayoutSubviews() {
51 | super.viewDidLayoutSubviews()
52 |
53 | view.layer.shadowColor = UIColor.black.cgColor
54 | view.layer.shadowRadius = 2
55 | view.layer.shadowOffset = CGSize(width: 0, height: -1)
56 | view.layer.shadowOpacity = 0.3
57 | view.clipsToBounds = false
58 | view.layer.masksToBounds = false
59 | }
60 |
61 | private func adjustDrawer(with maxHeight: CGFloat, with minHeight: CGFloat) {
62 |
63 | let options: [Drawer.Configuration.Key : Any] = [
64 | .animationDuration: 0.5,
65 | .fullHeight: maxHeight,
66 | .minimumHeight: minHeight,
67 | .initialState: Drawer.State.minimized,
68 | .cornerRadius: Drawer.Configuration.CornerRadius(fullSize: 20,
69 | minimized: 0)
70 | ]
71 |
72 | let contentConfiguration = Drawer.Configuration(options: options,
73 | dismissCompleteCallback: nil)
74 |
75 | embedDelegate?.handle(action: .layoutUpdated(config: contentConfiguration))
76 | }
77 |
78 | // MARK: - Callbacks -
79 |
80 | @IBAction func expandTapped(_ sender: Any) {
81 | embedDelegate?.handle(action: .changeState(to: .fullScreen))
82 | }
83 |
84 | @IBAction func collapseTapped(_ sender: Any) {
85 | embedDelegate?.handle(action: .changeState(to: .minimize))
86 | }
87 |
88 | }
89 |
90 | extension ContentViewController: Embeddable {
91 | func willChangeState(to state: EmbeddableState) {
92 | runningAnimators.forEach({
93 | $0.stopAnimation(false)
94 | $0.finishAnimation(at: .current)
95 | })
96 | let transform: CGAffineTransform
97 | let collapseAlpha: CGFloat
98 | let expandAlpha: CGFloat
99 |
100 | guard runningAnimators.isEmpty else { return }
101 |
102 | switch state {
103 | case .minimized:
104 | transform = .identity
105 | collapseAlpha = 0
106 | expandAlpha = 1
107 | case .fullSize:
108 | transform = CGAffineTransform(scaleX: titleScaleMax, y: titleScaleMax).concatenating(CGAffineTransform(translationX: 25, y: 0))
109 | collapseAlpha = 1
110 | expandAlpha = 0
111 | default:
112 | transform = .identity
113 | collapseAlpha = 0
114 | expandAlpha = 1
115 | }
116 |
117 | titleAnimator.addAnimations {
118 | self.titleLabel.transform = transform
119 | self.collapseButton.alpha = collapseAlpha
120 | self.expandButton.alpha = expandAlpha
121 | }
122 | titleAnimator.addCompletion {_ in
123 | self.titleLabel.transform = transform
124 | self.collapseButton.alpha = collapseAlpha
125 | self.expandButton.alpha = expandAlpha
126 | self.runningAnimators.removeAll()
127 | }
128 |
129 | titleAnimator.startAnimation()
130 | runningAnimators.append(titleAnimator)
131 | }
132 |
133 | func didChangeState(to state: EmbeddableState) {
134 | switch state {
135 | case .minimized:
136 | collapseButton.alpha = 0
137 | expandButton.alpha = 1
138 | case .fullSize:
139 | collapseButton.alpha = 1
140 | expandButton.alpha = 0
141 | case .closed:
142 | break
143 | }
144 |
145 | runningAnimators.forEach({
146 | $0.stopAnimation(false)
147 | $0.finishAnimation(at: .end)
148 | })
149 | }
150 |
151 | func didScroll(with progress: CGFloat, from state: Drawer.State) {
152 | runningAnimators.forEach({$0.pauseAnimation()})
153 | switch state {
154 | case .fullSize:
155 | collapseButton.alpha = 1 - progress
156 | expandButton.alpha = progress
157 | titleAnimator.fractionComplete = progress
158 | case .minimized:
159 | collapseButton.alpha = progress
160 | expandButton.alpha = 1 - progress
161 | titleAnimator.fractionComplete = progress
162 | }
163 |
164 | runningAnimators.forEach({$0.continueAnimation(withTimingParameters: nil, durationFactor: 0)})
165 | }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/Drawer/Example/Scenes/Background View Controller/Base.lproj/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 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.
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 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Drawer/Example/Scenes/Content View Controller/ContentViewController.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
32 |
43 |
44 |
45 |
46 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.
47 |
48 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/Drawer/Drawer/Drawer/DrawerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DrawerViewController.swift
3 | // Nodes
4 | //
5 | // Created by Andrei Hogea on 06/08/2018.
6 | // Copyright © 2019 Nodes. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class DrawerViewController: UIViewController { //swiftlint:disable:this type_body_length
12 |
13 | weak var contentViewController: (UIViewController & Embeddable)?
14 | weak var backgroundViewController: UIViewController?
15 |
16 | // MARK: Configuration
17 |
18 | private var embedConfig: Drawer.Configuration! {
19 | didSet {
20 | animationDuration = embedConfig.duration
21 |
22 | //drawer heights
23 | ownMaxHeight = embedConfig.embeddedFullHeight
24 | ownMinHeight = embedConfig.embeddedMinimumHeight
25 | heightAnchorContent.constant = ownMaxHeight
26 | cornerRadius = embedConfig.cornerRadius
27 |
28 | //drawer state
29 | state = embedConfig.state
30 | showAnimation()
31 |
32 | }
33 | }
34 |
35 | // MARK: Sizes and Constrains
36 |
37 | private var heightAnchorContent: NSLayoutConstraint!
38 | private var bottomAnchorContent: NSLayoutConstraint!
39 | private var ownMaxHeight: CGFloat = 0
40 | private var ownMinHeight: CGFloat = 0
41 | private var cornerRadius: Drawer.Configuration.CornerRadius!
42 |
43 | // MARK: States
44 |
45 | private var isInitiated: Bool = false
46 | private var state: Drawer.State = .minimized
47 | private var backgroundInteraction: Drawer.ContainerInteraction = .whenMinimised
48 |
49 | // MARK: Drawer possible backgrounds
50 |
51 | private var backgroundType: DrawerBackgroundType!
52 |
53 | private var backgroundColorView: UIView?
54 | private var backgroundBlurEffectView: UIVisualEffectView?
55 |
56 | // MARK: Slide Animation Properties
57 |
58 | private var animationDuration: TimeInterval!
59 | private let damping: CGFloat = 0.85
60 | // direction represents scrolling direction of the view
61 | private var direction: Direction!
62 | private var runningAnimators: [UIViewPropertyAnimator] = []
63 | private var animationProgress: [CGFloat] = []
64 | private var lastFractionComplete: CGFloat = 0
65 |
66 | // MARK: - Init
67 |
68 | public override func loadView() {
69 | super.loadView()
70 | self.view = TouchInterceptingView()
71 | }
72 |
73 | override public func viewDidLayoutSubviews() {
74 | super.viewDidLayoutSubviews()
75 |
76 | if ownMaxHeight > 0 && isInitiated == false {
77 | DispatchQueue.main.async {
78 | self.showAnimation()
79 | }
80 | }
81 |
82 | }
83 |
84 | func makeViews(with backgroundType: DrawerBackgroundType) {
85 | self.backgroundType = backgroundType
86 | view.backgroundColor = .clear
87 |
88 | addDrawerToBackground()
89 | switch backgroundType {
90 | case .withBlur:
91 | addBlurEffectViewToDrawer()
92 | case .withColor:
93 | addColorViewToDrawer()
94 | default: break
95 | }
96 | addContentToDrawer()
97 | setupGestureRecognizers()
98 |
99 | view.setNeedsLayout()
100 | view.layoutIfNeeded()
101 | }
102 |
103 | private func roundCorners(with radius: CGFloat) {
104 | contentViewController?.view.layer.cornerRadius = radius
105 | let corners = UIRectCorner(arrayLiteral: .topLeft, .topRight)
106 | contentViewController?.view.layer.maskedCorners = CACornerMask(rawValue: corners.rawValue)
107 | }
108 |
109 | }
110 |
111 | // MARK: - Add Children -
112 |
113 | extension DrawerViewController {
114 |
115 | /// Adds the Drawer(self) to the backgroundViewController
116 | private func addDrawerToBackground() {
117 | guard let backgroundViewController = backgroundViewController else { return }
118 |
119 | //swiftlint:disable:next force_cast
120 | let touchInterceptingView = view as! TouchInterceptingView
121 | touchInterceptingView.delegate = self
122 |
123 | backgroundViewController.view.addSubview(view)
124 | willMove(toParent: backgroundViewController)
125 | backgroundViewController.addChild(self)
126 | didMove(toParent: backgroundViewController)
127 |
128 | view.translatesAutoresizingMaskIntoConstraints = false
129 | view.heightAnchor.constraint(equalToConstant: maxAllowedHeight).isActive = true
130 | view.bottomAnchor.constraint(equalTo: backgroundViewController.view.bottomAnchor).isActive = true
131 | view.leadingAnchor.constraint(equalTo: backgroundViewController.view.leadingAnchor).isActive = true
132 | view.trailingAnchor.constraint(equalTo: backgroundViewController.view.trailingAnchor).isActive = true
133 | }
134 |
135 | /// Adds a UIVisualEffectView to self to act as background
136 | private func addBlurEffectViewToDrawer() {
137 | backgroundBlurEffectView = UIVisualEffectView()
138 | view.addSubview(backgroundBlurEffectView!)
139 | backgroundBlurEffectView?.translatesAutoresizingMaskIntoConstraints = false
140 | backgroundBlurEffectView?.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
141 | backgroundBlurEffectView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
142 | backgroundBlurEffectView?.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
143 | backgroundBlurEffectView?.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
144 | addTapToMinimise(on: backgroundBlurEffectView!)
145 | }
146 |
147 | /// Adds a UIView to self to act as background
148 | private func addColorViewToDrawer() {
149 | backgroundColorView = UIView()
150 | view.addSubview(backgroundColorView!)
151 | backgroundColorView?.translatesAutoresizingMaskIntoConstraints = false
152 | backgroundColorView?.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
153 | backgroundColorView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
154 | backgroundColorView?.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
155 | backgroundColorView?.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
156 | addTapToMinimise(on: backgroundColorView!)
157 | }
158 |
159 | private func addTapToMinimise(on tapView: UIView) {
160 | let tap = UITapGestureRecognizer(target: self, action: #selector(tapMinimize))
161 | tap.delegate = self
162 | tapView.isUserInteractionEnabled = true
163 | tapView.addGestureRecognizer(tap)
164 | }
165 |
166 | @objc private func tapMinimize() {
167 | contentViewController?.willChangeState(to: .minimized)
168 | closeDrawer()
169 | }
170 |
171 | /// Adds a contents UIViewController's view to self
172 | private func addContentToDrawer() {
173 | guard
174 | contentViewController != nil
175 | else { return }
176 |
177 | contentViewController?.embedDelegate = self
178 |
179 | view.addSubview(contentViewController!.view)
180 | contentViewController?.willMove(toParent: self)
181 | addChild(contentViewController!)
182 | contentViewController?.didMove(toParent: self)
183 |
184 | contentViewController?.view.translatesAutoresizingMaskIntoConstraints = false
185 | heightAnchorContent = contentViewController?.view.heightAnchor.constraint(equalToConstant: maxAllowedHeight)
186 | heightAnchorContent.identifier = "heightAnchorContent"
187 | heightAnchorContent.isActive = true
188 | bottomAnchorContent = contentViewController?.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: maxAllowedHeight)
189 | bottomAnchorContent.identifier = "bottomAnchorContent"
190 | bottomAnchorContent.isActive = true
191 | contentViewController?.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
192 | contentViewController?.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
193 | }
194 |
195 | }
196 |
197 | // MARK: - UIGestureRecognizer -
198 |
199 | extension DrawerViewController {
200 |
201 | private func setupGestureRecognizers() {
202 |
203 | func makePanGestureRecognizer(addToView view: UIView) {
204 | let contentPan = UIPanGestureRecognizer.init(target: self, action: #selector(handlePan))
205 | contentPan.delegate = self
206 | view.addGestureRecognizer(contentPan)
207 | }
208 |
209 | func makeTapGestureRecognizer(addToView view: UIView) {
210 | let contentPan = UITapGestureRecognizer.init(target: self, action: #selector(tapMinimize))
211 | contentPan.delegate = self
212 | view.addGestureRecognizer(contentPan)
213 | }
214 |
215 | do {
216 | if let contentViewController = contentViewController {
217 | makePanGestureRecognizer(addToView: contentViewController.view)
218 | }
219 |
220 | if let backgroundColorView = backgroundColorView {
221 | makePanGestureRecognizer(addToView: backgroundColorView)
222 | }
223 |
224 | if let backgroundBlurEffectView = backgroundBlurEffectView {
225 | makePanGestureRecognizer(addToView: backgroundBlurEffectView)
226 | }
227 | }
228 | }
229 |
230 | @objc private func handlePan(recognizer: UIPanGestureRecognizer) {
231 | switch recognizer.state {
232 | case .began:
233 | startInteractiveTransition(duration: animationDuration)
234 | case .changed:
235 | let translation = recognizer.translation(in: contentViewController?.view)
236 | var fractionComplete = translation.y / (ownMaxHeight - ownMinHeight)
237 |
238 | switch state {
239 | case .fullSize:
240 | direction = fourDecimal(fractionComplete) >= fourDecimal(lastFractionComplete) ? .down : .up
241 | case .minimized:
242 | fractionComplete *= -1
243 | direction = fourDecimal(fractionComplete) >= fourDecimal(lastFractionComplete) ? .up : .down
244 | }
245 |
246 | // if we have a progress, that means that the user started the swipe during the animation
247 | if animationProgress[0] > 0 {
248 | for (index, animator) in runningAnimators.enumerated() {
249 | if animator.isReversed {
250 | animator.fractionComplete = -fractionComplete + animationProgress[index]
251 | } else {
252 | animator.fractionComplete = fractionComplete + animationProgress[index]
253 | }
254 | }
255 | } else { // scroll started from initial state
256 | guard fractionComplete > 0 && fractionComplete < 1 else {
257 | return
258 | }
259 | for (index, animator) in runningAnimators.enumerated() {
260 | if animator.isReversed {
261 | animator.fractionComplete = fractionComplete - animationProgress[index]
262 | } else {
263 | animator.fractionComplete = fractionComplete + animationProgress[index]
264 | }
265 | }
266 | }
267 |
268 | // set lastFractionComplete -> used to determine pan direction
269 | lastFractionComplete = fractionComplete
270 |
271 | // normalise the progress and return it to the delegate
272 | var returnFractionComplete = runningAnimators[0].fractionComplete
273 | if returnFractionComplete >= 1 {
274 | returnFractionComplete = 1
275 | } else if returnFractionComplete <= 0 {
276 | returnFractionComplete = 0
277 | }
278 |
279 | contentViewController?.didScroll(with: returnFractionComplete, from: state)
280 |
281 | case .ended:
282 | // normal animation conditions
283 | if state == .fullSize && direction == .down || state == .minimized && direction == .up {
284 | switch state {
285 | case .fullSize:
286 | switch direction {
287 | case .down?:
288 | if runningAnimators[0].isReversed {
289 | runningAnimators.forEach { $0.isReversed = !$0.isReversed } // will Cancel reverse
290 | contentViewController?.willChangeState(to: .minimized)
291 | }
292 | default: break
293 | }
294 | case .minimized:
295 | switch direction {
296 | case .up?:
297 | if runningAnimators[0].isReversed {
298 | runningAnimators.forEach { $0.isReversed = !$0.isReversed } //will Cancel reverse
299 | contentViewController?.willChangeState(to: .fullSize)
300 | }
301 | default: break
302 | }
303 | }
304 | } else {
305 | // reverse the animations based on their current state and pan motion direction
306 | switch state {
307 | case .fullSize:
308 | switch direction {
309 | case .up?:
310 | if !runningAnimators[0].isReversed {
311 | runningAnimators.forEach { $0.isReversed = !$0.isReversed } //will reverse
312 | contentViewController?.willChangeState(to: .fullSize)
313 | }
314 | default: break
315 | }
316 | case .minimized:
317 | switch direction {
318 | case .down?:
319 | if !runningAnimators[0].isReversed {
320 | runningAnimators.forEach { $0.isReversed = !$0.isReversed } //will reverse
321 | contentViewController?.willChangeState(to: .minimized)
322 | }
323 | default: break
324 | }
325 | }
326 | }
327 |
328 | // continue the paused animations
329 | runningAnimators.forEach { $0.continueAnimation(withTimingParameters: nil, durationFactor: 0) }
330 | default: break
331 | }
332 | }
333 |
334 | private func startInteractiveTransition(duration: TimeInterval) {
335 | animateTransitionIfNeeded(duration: animationDuration)
336 | runningAnimators.forEach({ animator in
337 | animator.pauseAnimation()
338 | })
339 |
340 | animationProgress = runningAnimators.map { $0.fractionComplete }
341 | }
342 |
343 | }
344 |
345 | // MARK: - Content Constrains Helpers -
346 |
347 | extension DrawerViewController {
348 |
349 | private func setupOpenConstraints() {
350 | guard bottomAnchorContent != nil else { return }
351 | bottomAnchorContent.constant = 0
352 | }
353 |
354 | private func setupClosedConstraints() {
355 | guard bottomAnchorContent != nil else { return }
356 | bottomAnchorContent.constant = ownMaxHeight - ownMinHeight
357 | }
358 |
359 | private func setupDismissConstraints() {
360 | guard bottomAnchorContent != nil else { return }
361 | bottomAnchorContent.constant = heightAnchorContent.constant
362 | }
363 |
364 | }
365 |
366 | // MARK: - Background Helpers -
367 |
368 | extension DrawerViewController {
369 |
370 | private func handleOpenBackgroundAnimation() {
371 | switch self.backgroundType {
372 | case .withBlur(let style)?:
373 | self.backgroundBlurEffectView?.effect = UIBlurEffect(style: style)
374 | case .withColor(let color)?:
375 | backgroundColorView?.backgroundColor = color
376 | default: break
377 | }
378 | }
379 |
380 |
381 | private func handleCloseBackgroundAnimation() {
382 | switch self.backgroundType {
383 | case .withBlur?:
384 | self.backgroundBlurEffectView?.effect = nil
385 | case .withColor(let color)?:
386 | backgroundColorView?.backgroundColor = color.withAlphaComponent(0)
387 | default: break
388 | }
389 | }
390 | }
391 |
392 | // MARK: - Full Animations -
393 |
394 | extension DrawerViewController {
395 | private func openDrawer(animated: Bool = true, completion: (() -> Void)? = nil) {
396 | state = .fullSize
397 | setupOpenConstraints()
398 |
399 | //allow for scrolling in ContentVC
400 | if let scrollableContent = contentViewController as? EmbeddedScrollable {
401 | scrollableContent.setScrollEnabled(true)
402 | }
403 |
404 | let duration: TimeInterval = animated ? animationDuration : 0
405 | UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: [.beginFromCurrentState], animations: { [weak self] in
406 | guard let self = self else { return }
407 | self.handleOpenBackgroundAnimation()
408 | self.roundCorners(with: self.cornerRadius.fullSize)
409 | self.view.layoutIfNeeded()
410 | }, completion: { [weak self] _ in
411 | completion?()
412 | guard let self = self else { return }
413 | self.contentViewController?.didChangeState(to: .fullSize)
414 | })
415 | }
416 |
417 | private func closeDrawer(animated: Bool = true, completion: (() -> Void)? = nil) {
418 | state = .minimized
419 | setupClosedConstraints()
420 |
421 | //allow for scrolling in ContentVC
422 | if let scrollableContent = contentViewController as? EmbeddedScrollable {
423 | scrollableContent.setScrollEnabled(true)
424 | }
425 |
426 | let duration: TimeInterval = animated ? animationDuration : 0
427 | UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: [.beginFromCurrentState], animations: { [weak self] in
428 | guard let self = self else { return }
429 | self.handleCloseBackgroundAnimation()
430 | self.roundCorners(with: self.cornerRadius.minimized)
431 | self.view.layoutIfNeeded()
432 |
433 | }, completion: { [weak self] _ in
434 | completion?()
435 | guard let self = self else { return }
436 | self.contentViewController?.didChangeState(to: .minimized)
437 | })
438 | }
439 |
440 | private func dismiss(completion: (() -> Void)? = nil) {
441 | state = .minimized
442 | setupDismissConstraints()
443 |
444 | UIView.animate(withDuration: animationDuration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: [.beginFromCurrentState], animations: { [weak self] in
445 | self?.view.layoutIfNeeded()
446 | }, completion: { [weak self] _ in
447 | completion?()
448 | guard let self = self else { return }
449 | self.contentViewController?.didChangeState(to: .closed)
450 | self.destroySelf()
451 | })
452 | }
453 |
454 | }
455 |
456 | // MARK: - Scroll Animations -
457 |
458 | extension DrawerViewController {
459 | private enum Direction {
460 | case up, down
461 |
462 | mutating func reversed() {
463 | switch self {
464 | case .up:
465 | self = .down
466 | case .down:
467 | self = .up
468 | }
469 | }
470 | }
471 |
472 | /// Initiate transition if not already running
473 | private func animateTransitionIfNeeded(duration: TimeInterval) {
474 | guard runningAnimators.isEmpty else {
475 | direction.reversed()
476 | return
477 | }
478 | switch state {
479 | case .fullSize:
480 | direction = .down
481 | case .minimized:
482 | direction = .up
483 | }
484 |
485 | let animator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1)
486 |
487 | animator.addAnimations {
488 | switch self.state {
489 | case .fullSize:
490 | self.contentViewController?.willChangeState(to: .minimized)
491 | self.setupClosedConstraints()
492 | self.roundCorners(with: self.cornerRadius.minimized)
493 | self.handleCloseBackgroundAnimation()
494 | case .minimized:
495 | self.contentViewController?.willChangeState(to: .fullSize)
496 | self.setupOpenConstraints()
497 | self.roundCorners(with: self.cornerRadius.fullSize)
498 | self.handleOpenBackgroundAnimation()
499 | }
500 | self.view.layoutIfNeeded()
501 | }
502 |
503 | animator.addCompletion { position in
504 | switch self.direction {
505 | case .down?:
506 | self.closeDrawer(animated: self.state == .minimized)
507 | case .up?:
508 | self.openDrawer(animated: self.state == .fullSize)
509 | default: break
510 | }
511 |
512 | self.direction = nil
513 | self.animationProgress.removeAll()
514 | self.runningAnimators.removeAll()
515 | }
516 |
517 | animator.startAnimation()
518 | runningAnimators.append(animator)
519 | }
520 |
521 | // MARK: - Show animation
522 |
523 | //initial animation to display
524 | private func showAnimation() {
525 | isInitiated = true
526 | switch state {
527 | case .fullSize:
528 | openDrawer()
529 | case .minimized:
530 | closeDrawer()
531 | }
532 | }
533 |
534 |
535 | }
536 |
537 | // MARK: - EmbeddableContentDelegate
538 |
539 | extension DrawerViewController: EmbeddableContentDelegate {
540 |
541 | public var maxAllowedHeight: CGFloat {
542 | return UIScreen.main.bounds.height
543 | }
544 |
545 | public func handle(action: Drawer.Action) {
546 |
547 | switch action {
548 | case .layoutUpdated(config: let config):
549 | DispatchQueue.main.asyncAfter(deadline: .now()) {
550 | self.embedConfig = config
551 | }
552 | case .changeState(let drawerState):
553 | switch drawerState {
554 | case .minimize:
555 | contentViewController?.willChangeState(to: .minimized)
556 | closeDrawer()
557 | case .fullScreen:
558 | contentViewController?.willChangeState(to: .fullSize)
559 | openDrawer()
560 | case .dismiss:
561 | contentViewController?.willChangeState(to: .closed)
562 | dismiss()
563 | }
564 | }
565 | }
566 | }
567 |
568 | // MARK: - UIGestureRecognizerDelegate
569 |
570 | extension DrawerViewController: UIGestureRecognizerDelegate {
571 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
572 | guard let embeddedContentViewController = contentViewController else {
573 | return false
574 | }
575 |
576 | guard let gesture = gestureRecognizer as? UIPanGestureRecognizer else { return false }
577 | let direction = gesture.velocity(in: view).y
578 |
579 | if let scrollableContent = embeddedContentViewController as? EmbeddedScrollable {
580 | if state == .fullSize && scrollableContent.isScrolledToTop && direction > 0 {
581 | scrollableContent.setScrollEnabled(false)
582 | } else {
583 | scrollableContent.setScrollEnabled(true)
584 | }
585 | }
586 | return false
587 | }
588 |
589 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
590 | if gestureRecognizer is UIScreenEdgePanGestureRecognizer {
591 | return false
592 | }
593 |
594 | if touch.view?.superview(of: UITableViewCell.self) != nil && gestureRecognizer is UIPanGestureRecognizer {
595 | return false
596 | }
597 |
598 | if touch.view is UIButton && gestureRecognizer is UIPanGestureRecognizer {
599 | return false
600 | }
601 |
602 | // if the touch view is not the content's view, then we don't handle the touch in some cases
603 | if touch.view != contentViewController?.view && gestureRecognizer is UIPanGestureRecognizer {
604 |
605 | // check if the scrollview can scroll, then allow gesture based on that
606 | if let scrollView = touch.view as? UIScrollView,
607 | self.state == .fullSize {
608 |
609 | let scrollViewHeight = scrollView.frame.size.height
610 | let scrollContentSizeHeight = scrollView.contentSize.height
611 |
612 | if scrollViewHeight >= scrollContentSizeHeight {
613 | return true
614 | } else {
615 | return false
616 | }
617 |
618 | }
619 |
620 | return true
621 | }
622 |
623 | return true
624 | }
625 |
626 | }
627 |
628 | // MARK: - TouchPassingWindowDelegate
629 |
630 | extension DrawerViewController: TouchPassingWindowDelegate {
631 | func windowShouldBlockAll() -> Bool {
632 | switch backgroundInteraction {
633 | case .whenMinimised:
634 | return false
635 | }
636 | }
637 |
638 | var viewsForInterceptingTouches: [UIView] {
639 | guard
640 | let embeddedContentViewController = contentViewController
641 | else {
642 | return []
643 | }
644 | var views: [UIView] = [embeddedContentViewController.view]
645 |
646 | // intercept taps on the background if state is fullSize
647 | if backgroundBlurEffectView != nil && state == .fullSize {
648 | views.append(backgroundBlurEffectView!)
649 | }
650 |
651 | // intercept taps on the background if state is fullSize
652 | if backgroundColorView != nil && state == .fullSize {
653 | views.append(backgroundColorView!)
654 | }
655 |
656 | return views
657 | }
658 |
659 | }
660 |
661 |
662 | // MARK: - Destroy -
663 |
664 | extension DrawerViewController {
665 |
666 | private func destroySelf() {
667 | contentViewController?.view.removeFromSuperview()
668 | contentViewController?.removeFromParent()
669 |
670 | view.removeFromSuperview()
671 | removeFromParent()
672 |
673 | contentViewController = nil
674 | backgroundViewController = nil
675 | embedConfig?.dismissCompleteCallback?()
676 |
677 | isInitiated = false
678 | }
679 |
680 | }
681 |
682 | // MARK: - DrawerBackgroundType
683 |
684 | extension DrawerViewController {
685 |
686 | public enum DrawerBackgroundType {
687 | case clear
688 | case withColor(UIColor)
689 | case withBlur(UIBlurEffect.Style)
690 | }
691 |
692 | }
693 |
694 | // MARK: - CGFloat 2 decimal
695 |
696 | extension DrawerViewController {
697 |
698 | func fourDecimal(_ value: CGFloat) -> CGFloat {
699 | return round(10000*value)/10000
700 | }
701 |
702 | }//swiftlint:disable:this file_length
703 |
704 |
--------------------------------------------------------------------------------
/Drawer/Drawer.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 42321BF92226973500CE1DCB /* Drawer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42321BEF2226973500CE1DCB /* Drawer.framework */; };
11 | 42321BFE2226973500CE1DCB /* DrawerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321BFD2226973500CE1DCB /* DrawerTests.swift */; };
12 | 42321C002226973500CE1DCB /* Drawer.h in Headers */ = {isa = PBXBuildFile; fileRef = 42321BF22226973500CE1DCB /* Drawer.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | 42321C0B222697EA00CE1DCB /* TouchInterceptingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C0A222697EA00CE1DCB /* TouchInterceptingView.swift */; };
14 | 42321C0E2226982700CE1DCB /* UIView+Superview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C0D2226982700CE1DCB /* UIView+Superview.swift */; };
15 | 42321C152226987C00CE1DCB /* DrawerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C102226987C00CE1DCB /* DrawerCoordinator.swift */; };
16 | 42321C162226987C00CE1DCB /* EmbeddableContentDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C112226987C00CE1DCB /* EmbeddableContentDelegate.swift */; };
17 | 42321C172226987C00CE1DCB /* DrawerModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C122226987C00CE1DCB /* DrawerModels.swift */; };
18 | 42321C182226987C00CE1DCB /* DrawerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C132226987C00CE1DCB /* DrawerViewController.swift */; };
19 | 42321C1C2226A79F00CE1DCB /* Embeddable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C1B2226A79F00CE1DCB /* Embeddable.swift */; };
20 | 42321C1E2226A7ED00CE1DCB /* EmbeddedScrollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C1D2226A7ED00CE1DCB /* EmbeddedScrollable.swift */; };
21 | 42321C982226BD1000CE1DCB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C972226BD1000CE1DCB /* AppDelegate.swift */; };
22 | 42321C9A2226BD1000CE1DCB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321C992226BD1000CE1DCB /* ViewController.swift */; };
23 | 42321C9D2226BD1000CE1DCB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42321C9B2226BD1000CE1DCB /* Main.storyboard */; };
24 | 42321C9F2226BD1100CE1DCB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42321C9E2226BD1100CE1DCB /* Assets.xcassets */; };
25 | 42321CA22226BD1100CE1DCB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42321CA02226BD1100CE1DCB /* LaunchScreen.storyboard */; };
26 | 42321CAD2226BD1100CE1DCB /* ExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321CAC2226BD1100CE1DCB /* ExampleTests.swift */; };
27 | 42321CBA2226BD8600CE1DCB /* ContentViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42321CB82226BD8600CE1DCB /* ContentViewController.storyboard */; };
28 | 42321CBB2226BD8600CE1DCB /* ContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42321CB92226BD8600CE1DCB /* ContentViewController.swift */; };
29 | 42321CEB2226BE8400CE1DCB /* Drawer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42321BEF2226973500CE1DCB /* Drawer.framework */; };
30 | 42321CEC2226BE8400CE1DCB /* Drawer.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 42321BEF2226973500CE1DCB /* Drawer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
31 | /* End PBXBuildFile section */
32 |
33 | /* Begin PBXContainerItemProxy section */
34 | 42321BFA2226973500CE1DCB /* PBXContainerItemProxy */ = {
35 | isa = PBXContainerItemProxy;
36 | containerPortal = 42321BE62226973500CE1DCB /* Project object */;
37 | proxyType = 1;
38 | remoteGlobalIDString = 42321BEE2226973500CE1DCB;
39 | remoteInfo = Drawer;
40 | };
41 | 42321CA92226BD1100CE1DCB /* PBXContainerItemProxy */ = {
42 | isa = PBXContainerItemProxy;
43 | containerPortal = 42321BE62226973500CE1DCB /* Project object */;
44 | proxyType = 1;
45 | remoteGlobalIDString = 42321C942226BD1000CE1DCB;
46 | remoteInfo = Example;
47 | };
48 | 42321CED2226BE8400CE1DCB /* PBXContainerItemProxy */ = {
49 | isa = PBXContainerItemProxy;
50 | containerPortal = 42321BE62226973500CE1DCB /* Project object */;
51 | proxyType = 1;
52 | remoteGlobalIDString = 42321BEE2226973500CE1DCB;
53 | remoteInfo = Drawer;
54 | };
55 | /* End PBXContainerItemProxy section */
56 |
57 | /* Begin PBXCopyFilesBuildPhase section */
58 | 42321CEF2226BE8400CE1DCB /* Embed Frameworks */ = {
59 | isa = PBXCopyFilesBuildPhase;
60 | buildActionMask = 2147483647;
61 | dstPath = "";
62 | dstSubfolderSpec = 10;
63 | files = (
64 | 42321CEC2226BE8400CE1DCB /* Drawer.framework in Embed Frameworks */,
65 | );
66 | name = "Embed Frameworks";
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | /* End PBXCopyFilesBuildPhase section */
70 |
71 | /* Begin PBXFileReference section */
72 | 42321BEF2226973500CE1DCB /* Drawer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Drawer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
73 | 42321BF22226973500CE1DCB /* Drawer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Drawer.h; sourceTree = ""; };
74 | 42321BF32226973500CE1DCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
75 | 42321BF82226973500CE1DCB /* DrawerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DrawerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
76 | 42321BFD2226973500CE1DCB /* DrawerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawerTests.swift; sourceTree = ""; };
77 | 42321BFF2226973500CE1DCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
78 | 42321C0A222697EA00CE1DCB /* TouchInterceptingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchInterceptingView.swift; sourceTree = ""; };
79 | 42321C0D2226982700CE1DCB /* UIView+Superview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Superview.swift"; sourceTree = ""; };
80 | 42321C102226987C00CE1DCB /* DrawerCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerCoordinator.swift; sourceTree = ""; };
81 | 42321C112226987C00CE1DCB /* EmbeddableContentDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmbeddableContentDelegate.swift; sourceTree = ""; };
82 | 42321C122226987C00CE1DCB /* DrawerModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerModels.swift; sourceTree = ""; };
83 | 42321C132226987C00CE1DCB /* DrawerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerViewController.swift; sourceTree = ""; };
84 | 42321C1B2226A79F00CE1DCB /* Embeddable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Embeddable.swift; sourceTree = ""; };
85 | 42321C1D2226A7ED00CE1DCB /* EmbeddedScrollable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedScrollable.swift; sourceTree = ""; };
86 | 42321C952226BD1000CE1DCB /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
87 | 42321C972226BD1000CE1DCB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
88 | 42321C992226BD1000CE1DCB /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
89 | 42321C9C2226BD1000CE1DCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
90 | 42321C9E2226BD1100CE1DCB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
91 | 42321CA12226BD1100CE1DCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
92 | 42321CA32226BD1100CE1DCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
93 | 42321CA82226BD1100CE1DCB /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
94 | 42321CAC2226BD1100CE1DCB /* ExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleTests.swift; sourceTree = ""; };
95 | 42321CAE2226BD1100CE1DCB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
96 | 42321CB82226BD8600CE1DCB /* ContentViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ContentViewController.storyboard; sourceTree = ""; };
97 | 42321CB92226BD8600CE1DCB /* ContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentViewController.swift; sourceTree = ""; };
98 | /* End PBXFileReference section */
99 |
100 | /* Begin PBXFrameworksBuildPhase section */
101 | 42321BEC2226973500CE1DCB /* Frameworks */ = {
102 | isa = PBXFrameworksBuildPhase;
103 | buildActionMask = 2147483647;
104 | files = (
105 | );
106 | runOnlyForDeploymentPostprocessing = 0;
107 | };
108 | 42321BF52226973500CE1DCB /* Frameworks */ = {
109 | isa = PBXFrameworksBuildPhase;
110 | buildActionMask = 2147483647;
111 | files = (
112 | 42321BF92226973500CE1DCB /* Drawer.framework in Frameworks */,
113 | );
114 | runOnlyForDeploymentPostprocessing = 0;
115 | };
116 | 42321C922226BD1000CE1DCB /* Frameworks */ = {
117 | isa = PBXFrameworksBuildPhase;
118 | buildActionMask = 2147483647;
119 | files = (
120 | 42321CEB2226BE8400CE1DCB /* Drawer.framework in Frameworks */,
121 | );
122 | runOnlyForDeploymentPostprocessing = 0;
123 | };
124 | 42321CA52226BD1100CE1DCB /* Frameworks */ = {
125 | isa = PBXFrameworksBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | /* End PBXFrameworksBuildPhase section */
132 |
133 | /* Begin PBXGroup section */
134 | 42321BE52226973500CE1DCB = {
135 | isa = PBXGroup;
136 | children = (
137 | 42321BF12226973500CE1DCB /* Drawer */,
138 | 42321BFC2226973500CE1DCB /* DrawerTests */,
139 | 42321C962226BD1000CE1DCB /* Example */,
140 | 42321CAB2226BD1100CE1DCB /* ExampleTests */,
141 | 42321BF02226973500CE1DCB /* Products */,
142 | 42321CBC2226BDE700CE1DCB /* Frameworks */,
143 | );
144 | sourceTree = "";
145 | };
146 | 42321BF02226973500CE1DCB /* Products */ = {
147 | isa = PBXGroup;
148 | children = (
149 | 42321BEF2226973500CE1DCB /* Drawer.framework */,
150 | 42321BF82226973500CE1DCB /* DrawerTests.xctest */,
151 | 42321C952226BD1000CE1DCB /* Example.app */,
152 | 42321CA82226BD1100CE1DCB /* ExampleTests.xctest */,
153 | );
154 | name = Products;
155 | sourceTree = "";
156 | };
157 | 42321BF12226973500CE1DCB /* Drawer */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 42321C0F2226984A00CE1DCB /* Drawer */,
161 | 42321C0C2226981200CE1DCB /* Extensions */,
162 | 42321C092226977500CE1DCB /* Touch Intercepting View */,
163 | 42321BF22226973500CE1DCB /* Drawer.h */,
164 | 42321BF32226973500CE1DCB /* Info.plist */,
165 | );
166 | path = Drawer;
167 | sourceTree = "";
168 | };
169 | 42321BFC2226973500CE1DCB /* DrawerTests */ = {
170 | isa = PBXGroup;
171 | children = (
172 | 42321BFD2226973500CE1DCB /* DrawerTests.swift */,
173 | 42321BFF2226973500CE1DCB /* Info.plist */,
174 | );
175 | path = DrawerTests;
176 | sourceTree = "";
177 | };
178 | 42321C092226977500CE1DCB /* Touch Intercepting View */ = {
179 | isa = PBXGroup;
180 | children = (
181 | 42321C0A222697EA00CE1DCB /* TouchInterceptingView.swift */,
182 | );
183 | path = "Touch Intercepting View";
184 | sourceTree = "";
185 | };
186 | 42321C0C2226981200CE1DCB /* Extensions */ = {
187 | isa = PBXGroup;
188 | children = (
189 | 42321C0D2226982700CE1DCB /* UIView+Superview.swift */,
190 | );
191 | path = Extensions;
192 | sourceTree = "";
193 | };
194 | 42321C0F2226984A00CE1DCB /* Drawer */ = {
195 | isa = PBXGroup;
196 | children = (
197 | 42321C102226987C00CE1DCB /* DrawerCoordinator.swift */,
198 | 42321C132226987C00CE1DCB /* DrawerViewController.swift */,
199 | 42321C122226987C00CE1DCB /* DrawerModels.swift */,
200 | 42321C1F2226A80700CE1DCB /* Protocols */,
201 | );
202 | path = Drawer;
203 | sourceTree = "";
204 | };
205 | 42321C1F2226A80700CE1DCB /* Protocols */ = {
206 | isa = PBXGroup;
207 | children = (
208 | 42321C1B2226A79F00CE1DCB /* Embeddable.swift */,
209 | 42321C1D2226A7ED00CE1DCB /* EmbeddedScrollable.swift */,
210 | 42321C112226987C00CE1DCB /* EmbeddableContentDelegate.swift */,
211 | );
212 | path = Protocols;
213 | sourceTree = "";
214 | };
215 | 42321C962226BD1000CE1DCB /* Example */ = {
216 | isa = PBXGroup;
217 | children = (
218 | 42321C972226BD1000CE1DCB /* AppDelegate.swift */,
219 | 42321CB52226BD2D00CE1DCB /* Scenes */,
220 | 42321C9E2226BD1100CE1DCB /* Assets.xcassets */,
221 | 42321CA02226BD1100CE1DCB /* LaunchScreen.storyboard */,
222 | 42321CA32226BD1100CE1DCB /* Info.plist */,
223 | );
224 | path = Example;
225 | sourceTree = "";
226 | };
227 | 42321CAB2226BD1100CE1DCB /* ExampleTests */ = {
228 | isa = PBXGroup;
229 | children = (
230 | 42321CAC2226BD1100CE1DCB /* ExampleTests.swift */,
231 | 42321CAE2226BD1100CE1DCB /* Info.plist */,
232 | );
233 | path = ExampleTests;
234 | sourceTree = "";
235 | };
236 | 42321CB52226BD2D00CE1DCB /* Scenes */ = {
237 | isa = PBXGroup;
238 | children = (
239 | 42321CB62226BD3B00CE1DCB /* Background View Controller */,
240 | 42321CB72226BD6800CE1DCB /* Content View Controller */,
241 | );
242 | path = Scenes;
243 | sourceTree = "";
244 | };
245 | 42321CB62226BD3B00CE1DCB /* Background View Controller */ = {
246 | isa = PBXGroup;
247 | children = (
248 | 42321C992226BD1000CE1DCB /* ViewController.swift */,
249 | 42321C9B2226BD1000CE1DCB /* Main.storyboard */,
250 | );
251 | path = "Background View Controller";
252 | sourceTree = "";
253 | };
254 | 42321CB72226BD6800CE1DCB /* Content View Controller */ = {
255 | isa = PBXGroup;
256 | children = (
257 | 42321CB92226BD8600CE1DCB /* ContentViewController.swift */,
258 | 42321CB82226BD8600CE1DCB /* ContentViewController.storyboard */,
259 | );
260 | path = "Content View Controller";
261 | sourceTree = "";
262 | };
263 | 42321CBC2226BDE700CE1DCB /* Frameworks */ = {
264 | isa = PBXGroup;
265 | children = (
266 | );
267 | name = Frameworks;
268 | sourceTree = "";
269 | };
270 | /* End PBXGroup section */
271 |
272 | /* Begin PBXHeadersBuildPhase section */
273 | 42321BEA2226973500CE1DCB /* Headers */ = {
274 | isa = PBXHeadersBuildPhase;
275 | buildActionMask = 2147483647;
276 | files = (
277 | 42321C002226973500CE1DCB /* Drawer.h in Headers */,
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | /* End PBXHeadersBuildPhase section */
282 |
283 | /* Begin PBXNativeTarget section */
284 | 42321BEE2226973500CE1DCB /* Drawer */ = {
285 | isa = PBXNativeTarget;
286 | buildConfigurationList = 42321C032226973500CE1DCB /* Build configuration list for PBXNativeTarget "Drawer" */;
287 | buildPhases = (
288 | 42321BEA2226973500CE1DCB /* Headers */,
289 | 42321BEB2226973500CE1DCB /* Sources */,
290 | 42321BEC2226973500CE1DCB /* Frameworks */,
291 | 42321BED2226973500CE1DCB /* Resources */,
292 | );
293 | buildRules = (
294 | );
295 | dependencies = (
296 | );
297 | name = Drawer;
298 | productName = Drawer;
299 | productReference = 42321BEF2226973500CE1DCB /* Drawer.framework */;
300 | productType = "com.apple.product-type.framework";
301 | };
302 | 42321BF72226973500CE1DCB /* DrawerTests */ = {
303 | isa = PBXNativeTarget;
304 | buildConfigurationList = 42321C062226973500CE1DCB /* Build configuration list for PBXNativeTarget "DrawerTests" */;
305 | buildPhases = (
306 | 42321BF42226973500CE1DCB /* Sources */,
307 | 42321BF52226973500CE1DCB /* Frameworks */,
308 | 42321BF62226973500CE1DCB /* Resources */,
309 | );
310 | buildRules = (
311 | );
312 | dependencies = (
313 | 42321BFB2226973500CE1DCB /* PBXTargetDependency */,
314 | );
315 | name = DrawerTests;
316 | productName = DrawerTests;
317 | productReference = 42321BF82226973500CE1DCB /* DrawerTests.xctest */;
318 | productType = "com.apple.product-type.bundle.unit-test";
319 | };
320 | 42321C942226BD1000CE1DCB /* Example */ = {
321 | isa = PBXNativeTarget;
322 | buildConfigurationList = 42321CB32226BD1100CE1DCB /* Build configuration list for PBXNativeTarget "Example" */;
323 | buildPhases = (
324 | 42321C912226BD1000CE1DCB /* Sources */,
325 | 42321C922226BD1000CE1DCB /* Frameworks */,
326 | 42321C932226BD1000CE1DCB /* Resources */,
327 | 42321CEF2226BE8400CE1DCB /* Embed Frameworks */,
328 | );
329 | buildRules = (
330 | );
331 | dependencies = (
332 | 42321CEE2226BE8400CE1DCB /* PBXTargetDependency */,
333 | );
334 | name = Example;
335 | productName = Example;
336 | productReference = 42321C952226BD1000CE1DCB /* Example.app */;
337 | productType = "com.apple.product-type.application";
338 | };
339 | 42321CA72226BD1100CE1DCB /* ExampleTests */ = {
340 | isa = PBXNativeTarget;
341 | buildConfigurationList = 42321CB42226BD1100CE1DCB /* Build configuration list for PBXNativeTarget "ExampleTests" */;
342 | buildPhases = (
343 | 42321CA42226BD1100CE1DCB /* Sources */,
344 | 42321CA52226BD1100CE1DCB /* Frameworks */,
345 | 42321CA62226BD1100CE1DCB /* Resources */,
346 | );
347 | buildRules = (
348 | );
349 | dependencies = (
350 | 42321CAA2226BD1100CE1DCB /* PBXTargetDependency */,
351 | );
352 | name = ExampleTests;
353 | productName = ExampleTests;
354 | productReference = 42321CA82226BD1100CE1DCB /* ExampleTests.xctest */;
355 | productType = "com.apple.product-type.bundle.unit-test";
356 | };
357 | /* End PBXNativeTarget section */
358 |
359 | /* Begin PBXProject section */
360 | 42321BE62226973500CE1DCB /* Project object */ = {
361 | isa = PBXProject;
362 | attributes = {
363 | LastSwiftUpdateCheck = 1010;
364 | LastUpgradeCheck = 1010;
365 | ORGANIZATIONNAME = "Andrei Hogea";
366 | TargetAttributes = {
367 | 42321BEE2226973500CE1DCB = {
368 | CreatedOnToolsVersion = 10.1;
369 | LastSwiftMigration = 1020;
370 | };
371 | 42321BF72226973500CE1DCB = {
372 | CreatedOnToolsVersion = 10.1;
373 | };
374 | 42321C942226BD1000CE1DCB = {
375 | CreatedOnToolsVersion = 10.1;
376 | LastSwiftMigration = 1020;
377 | };
378 | 42321CA72226BD1100CE1DCB = {
379 | CreatedOnToolsVersion = 10.1;
380 | LastSwiftMigration = 1020;
381 | TestTargetID = 42321C942226BD1000CE1DCB;
382 | };
383 | };
384 | };
385 | buildConfigurationList = 42321BE92226973500CE1DCB /* Build configuration list for PBXProject "Drawer" */;
386 | compatibilityVersion = "Xcode 9.3";
387 | developmentRegion = en;
388 | hasScannedForEncodings = 0;
389 | knownRegions = (
390 | en,
391 | Base,
392 | );
393 | mainGroup = 42321BE52226973500CE1DCB;
394 | productRefGroup = 42321BF02226973500CE1DCB /* Products */;
395 | projectDirPath = "";
396 | projectRoot = "";
397 | targets = (
398 | 42321BEE2226973500CE1DCB /* Drawer */,
399 | 42321BF72226973500CE1DCB /* DrawerTests */,
400 | 42321C942226BD1000CE1DCB /* Example */,
401 | 42321CA72226BD1100CE1DCB /* ExampleTests */,
402 | );
403 | };
404 | /* End PBXProject section */
405 |
406 | /* Begin PBXResourcesBuildPhase section */
407 | 42321BED2226973500CE1DCB /* Resources */ = {
408 | isa = PBXResourcesBuildPhase;
409 | buildActionMask = 2147483647;
410 | files = (
411 | );
412 | runOnlyForDeploymentPostprocessing = 0;
413 | };
414 | 42321BF62226973500CE1DCB /* Resources */ = {
415 | isa = PBXResourcesBuildPhase;
416 | buildActionMask = 2147483647;
417 | files = (
418 | );
419 | runOnlyForDeploymentPostprocessing = 0;
420 | };
421 | 42321C932226BD1000CE1DCB /* Resources */ = {
422 | isa = PBXResourcesBuildPhase;
423 | buildActionMask = 2147483647;
424 | files = (
425 | 42321CA22226BD1100CE1DCB /* LaunchScreen.storyboard in Resources */,
426 | 42321C9F2226BD1100CE1DCB /* Assets.xcassets in Resources */,
427 | 42321CBA2226BD8600CE1DCB /* ContentViewController.storyboard in Resources */,
428 | 42321C9D2226BD1000CE1DCB /* Main.storyboard in Resources */,
429 | );
430 | runOnlyForDeploymentPostprocessing = 0;
431 | };
432 | 42321CA62226BD1100CE1DCB /* Resources */ = {
433 | isa = PBXResourcesBuildPhase;
434 | buildActionMask = 2147483647;
435 | files = (
436 | );
437 | runOnlyForDeploymentPostprocessing = 0;
438 | };
439 | /* End PBXResourcesBuildPhase section */
440 |
441 | /* Begin PBXSourcesBuildPhase section */
442 | 42321BEB2226973500CE1DCB /* Sources */ = {
443 | isa = PBXSourcesBuildPhase;
444 | buildActionMask = 2147483647;
445 | files = (
446 | 42321C1E2226A7ED00CE1DCB /* EmbeddedScrollable.swift in Sources */,
447 | 42321C0B222697EA00CE1DCB /* TouchInterceptingView.swift in Sources */,
448 | 42321C162226987C00CE1DCB /* EmbeddableContentDelegate.swift in Sources */,
449 | 42321C182226987C00CE1DCB /* DrawerViewController.swift in Sources */,
450 | 42321C152226987C00CE1DCB /* DrawerCoordinator.swift in Sources */,
451 | 42321C172226987C00CE1DCB /* DrawerModels.swift in Sources */,
452 | 42321C1C2226A79F00CE1DCB /* Embeddable.swift in Sources */,
453 | 42321C0E2226982700CE1DCB /* UIView+Superview.swift in Sources */,
454 | );
455 | runOnlyForDeploymentPostprocessing = 0;
456 | };
457 | 42321BF42226973500CE1DCB /* Sources */ = {
458 | isa = PBXSourcesBuildPhase;
459 | buildActionMask = 2147483647;
460 | files = (
461 | 42321BFE2226973500CE1DCB /* DrawerTests.swift in Sources */,
462 | );
463 | runOnlyForDeploymentPostprocessing = 0;
464 | };
465 | 42321C912226BD1000CE1DCB /* Sources */ = {
466 | isa = PBXSourcesBuildPhase;
467 | buildActionMask = 2147483647;
468 | files = (
469 | 42321C9A2226BD1000CE1DCB /* ViewController.swift in Sources */,
470 | 42321CBB2226BD8600CE1DCB /* ContentViewController.swift in Sources */,
471 | 42321C982226BD1000CE1DCB /* AppDelegate.swift in Sources */,
472 | );
473 | runOnlyForDeploymentPostprocessing = 0;
474 | };
475 | 42321CA42226BD1100CE1DCB /* Sources */ = {
476 | isa = PBXSourcesBuildPhase;
477 | buildActionMask = 2147483647;
478 | files = (
479 | 42321CAD2226BD1100CE1DCB /* ExampleTests.swift in Sources */,
480 | );
481 | runOnlyForDeploymentPostprocessing = 0;
482 | };
483 | /* End PBXSourcesBuildPhase section */
484 |
485 | /* Begin PBXTargetDependency section */
486 | 42321BFB2226973500CE1DCB /* PBXTargetDependency */ = {
487 | isa = PBXTargetDependency;
488 | target = 42321BEE2226973500CE1DCB /* Drawer */;
489 | targetProxy = 42321BFA2226973500CE1DCB /* PBXContainerItemProxy */;
490 | };
491 | 42321CAA2226BD1100CE1DCB /* PBXTargetDependency */ = {
492 | isa = PBXTargetDependency;
493 | target = 42321C942226BD1000CE1DCB /* Example */;
494 | targetProxy = 42321CA92226BD1100CE1DCB /* PBXContainerItemProxy */;
495 | };
496 | 42321CEE2226BE8400CE1DCB /* PBXTargetDependency */ = {
497 | isa = PBXTargetDependency;
498 | target = 42321BEE2226973500CE1DCB /* Drawer */;
499 | targetProxy = 42321CED2226BE8400CE1DCB /* PBXContainerItemProxy */;
500 | };
501 | /* End PBXTargetDependency section */
502 |
503 | /* Begin PBXVariantGroup section */
504 | 42321C9B2226BD1000CE1DCB /* Main.storyboard */ = {
505 | isa = PBXVariantGroup;
506 | children = (
507 | 42321C9C2226BD1000CE1DCB /* Base */,
508 | );
509 | name = Main.storyboard;
510 | sourceTree = "";
511 | };
512 | 42321CA02226BD1100CE1DCB /* LaunchScreen.storyboard */ = {
513 | isa = PBXVariantGroup;
514 | children = (
515 | 42321CA12226BD1100CE1DCB /* Base */,
516 | );
517 | name = LaunchScreen.storyboard;
518 | sourceTree = "";
519 | };
520 | /* End PBXVariantGroup section */
521 |
522 | /* Begin XCBuildConfiguration section */
523 | 42321C012226973500CE1DCB /* Debug */ = {
524 | isa = XCBuildConfiguration;
525 | buildSettings = {
526 | ALWAYS_SEARCH_USER_PATHS = NO;
527 | CLANG_ANALYZER_NONNULL = YES;
528 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
529 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
530 | CLANG_CXX_LIBRARY = "libc++";
531 | CLANG_ENABLE_MODULES = YES;
532 | CLANG_ENABLE_OBJC_ARC = YES;
533 | CLANG_ENABLE_OBJC_WEAK = YES;
534 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
535 | CLANG_WARN_BOOL_CONVERSION = YES;
536 | CLANG_WARN_COMMA = YES;
537 | CLANG_WARN_CONSTANT_CONVERSION = YES;
538 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
539 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
540 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
541 | CLANG_WARN_EMPTY_BODY = YES;
542 | CLANG_WARN_ENUM_CONVERSION = YES;
543 | CLANG_WARN_INFINITE_RECURSION = YES;
544 | CLANG_WARN_INT_CONVERSION = YES;
545 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
546 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
547 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
548 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
549 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
550 | CLANG_WARN_STRICT_PROTOTYPES = YES;
551 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
552 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
553 | CLANG_WARN_UNREACHABLE_CODE = YES;
554 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
555 | CODE_SIGN_IDENTITY = "iPhone Developer";
556 | COPY_PHASE_STRIP = NO;
557 | CURRENT_PROJECT_VERSION = 1;
558 | DEBUG_INFORMATION_FORMAT = dwarf;
559 | ENABLE_STRICT_OBJC_MSGSEND = YES;
560 | ENABLE_TESTABILITY = YES;
561 | GCC_C_LANGUAGE_STANDARD = gnu11;
562 | GCC_DYNAMIC_NO_PIC = NO;
563 | GCC_NO_COMMON_BLOCKS = YES;
564 | GCC_OPTIMIZATION_LEVEL = 0;
565 | GCC_PREPROCESSOR_DEFINITIONS = (
566 | "DEBUG=1",
567 | "$(inherited)",
568 | );
569 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
570 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
571 | GCC_WARN_UNDECLARED_SELECTOR = YES;
572 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
573 | GCC_WARN_UNUSED_FUNCTION = YES;
574 | GCC_WARN_UNUSED_VARIABLE = YES;
575 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
576 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
577 | MTL_FAST_MATH = YES;
578 | ONLY_ACTIVE_ARCH = YES;
579 | SDKROOT = iphoneos;
580 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
581 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
582 | VERSIONING_SYSTEM = "apple-generic";
583 | VERSION_INFO_PREFIX = "";
584 | };
585 | name = Debug;
586 | };
587 | 42321C022226973500CE1DCB /* Release */ = {
588 | isa = XCBuildConfiguration;
589 | buildSettings = {
590 | ALWAYS_SEARCH_USER_PATHS = NO;
591 | CLANG_ANALYZER_NONNULL = YES;
592 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
593 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
594 | CLANG_CXX_LIBRARY = "libc++";
595 | CLANG_ENABLE_MODULES = YES;
596 | CLANG_ENABLE_OBJC_ARC = YES;
597 | CLANG_ENABLE_OBJC_WEAK = YES;
598 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
599 | CLANG_WARN_BOOL_CONVERSION = YES;
600 | CLANG_WARN_COMMA = YES;
601 | CLANG_WARN_CONSTANT_CONVERSION = YES;
602 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
603 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
604 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
605 | CLANG_WARN_EMPTY_BODY = YES;
606 | CLANG_WARN_ENUM_CONVERSION = YES;
607 | CLANG_WARN_INFINITE_RECURSION = YES;
608 | CLANG_WARN_INT_CONVERSION = YES;
609 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
610 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
611 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
612 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
613 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
614 | CLANG_WARN_STRICT_PROTOTYPES = YES;
615 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
616 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
617 | CLANG_WARN_UNREACHABLE_CODE = YES;
618 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
619 | CODE_SIGN_IDENTITY = "iPhone Developer";
620 | COPY_PHASE_STRIP = NO;
621 | CURRENT_PROJECT_VERSION = 1;
622 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
623 | ENABLE_NS_ASSERTIONS = NO;
624 | ENABLE_STRICT_OBJC_MSGSEND = YES;
625 | GCC_C_LANGUAGE_STANDARD = gnu11;
626 | GCC_NO_COMMON_BLOCKS = YES;
627 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
628 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
629 | GCC_WARN_UNDECLARED_SELECTOR = YES;
630 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
631 | GCC_WARN_UNUSED_FUNCTION = YES;
632 | GCC_WARN_UNUSED_VARIABLE = YES;
633 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
634 | MTL_ENABLE_DEBUG_INFO = NO;
635 | MTL_FAST_MATH = YES;
636 | SDKROOT = iphoneos;
637 | SWIFT_COMPILATION_MODE = wholemodule;
638 | SWIFT_OPTIMIZATION_LEVEL = "-O";
639 | VALIDATE_PRODUCT = YES;
640 | VERSIONING_SYSTEM = "apple-generic";
641 | VERSION_INFO_PREFIX = "";
642 | };
643 | name = Release;
644 | };
645 | 42321C042226973500CE1DCB /* Debug */ = {
646 | isa = XCBuildConfiguration;
647 | buildSettings = {
648 | CLANG_ENABLE_MODULES = YES;
649 | CODE_SIGN_IDENTITY = "";
650 | CODE_SIGN_STYLE = Automatic;
651 | DEFINES_MODULE = YES;
652 | DEVELOPMENT_TEAM = "";
653 | DYLIB_COMPATIBILITY_VERSION = 1;
654 | DYLIB_CURRENT_VERSION = 1;
655 | DYLIB_INSTALL_NAME_BASE = "@rpath";
656 | INFOPLIST_FILE = Drawer/Info.plist;
657 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
658 | LD_RUNPATH_SEARCH_PATHS = (
659 | "$(inherited)",
660 | "@executable_path/Frameworks",
661 | "@loader_path/Frameworks",
662 | );
663 | MARKETING_VERSION = 1.0.4;
664 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.Drawer;
665 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
666 | SKIP_INSTALL = YES;
667 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
668 | SWIFT_VERSION = 5.0;
669 | TARGETED_DEVICE_FAMILY = "1,2";
670 | };
671 | name = Debug;
672 | };
673 | 42321C052226973500CE1DCB /* Release */ = {
674 | isa = XCBuildConfiguration;
675 | buildSettings = {
676 | CLANG_ENABLE_MODULES = YES;
677 | CODE_SIGN_IDENTITY = "";
678 | CODE_SIGN_STYLE = Automatic;
679 | DEFINES_MODULE = YES;
680 | DEVELOPMENT_TEAM = "";
681 | DYLIB_COMPATIBILITY_VERSION = 1;
682 | DYLIB_CURRENT_VERSION = 1;
683 | DYLIB_INSTALL_NAME_BASE = "@rpath";
684 | INFOPLIST_FILE = Drawer/Info.plist;
685 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
686 | LD_RUNPATH_SEARCH_PATHS = (
687 | "$(inherited)",
688 | "@executable_path/Frameworks",
689 | "@loader_path/Frameworks",
690 | );
691 | MARKETING_VERSION = 1.0.4;
692 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.Drawer;
693 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
694 | SKIP_INSTALL = YES;
695 | SWIFT_VERSION = 5.0;
696 | TARGETED_DEVICE_FAMILY = "1,2";
697 | };
698 | name = Release;
699 | };
700 | 42321C072226973500CE1DCB /* Debug */ = {
701 | isa = XCBuildConfiguration;
702 | buildSettings = {
703 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
704 | CODE_SIGN_STYLE = Automatic;
705 | DEVELOPMENT_TEAM = MC6WZHXVVH;
706 | INFOPLIST_FILE = DrawerTests/Info.plist;
707 | LD_RUNPATH_SEARCH_PATHS = (
708 | "$(inherited)",
709 | "@executable_path/Frameworks",
710 | "@loader_path/Frameworks",
711 | );
712 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.DrawerTests;
713 | PRODUCT_NAME = "$(TARGET_NAME)";
714 | SWIFT_VERSION = 4.2;
715 | TARGETED_DEVICE_FAMILY = "1,2";
716 | };
717 | name = Debug;
718 | };
719 | 42321C082226973500CE1DCB /* Release */ = {
720 | isa = XCBuildConfiguration;
721 | buildSettings = {
722 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
723 | CODE_SIGN_STYLE = Automatic;
724 | DEVELOPMENT_TEAM = MC6WZHXVVH;
725 | INFOPLIST_FILE = DrawerTests/Info.plist;
726 | LD_RUNPATH_SEARCH_PATHS = (
727 | "$(inherited)",
728 | "@executable_path/Frameworks",
729 | "@loader_path/Frameworks",
730 | );
731 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.DrawerTests;
732 | PRODUCT_NAME = "$(TARGET_NAME)";
733 | SWIFT_VERSION = 4.2;
734 | TARGETED_DEVICE_FAMILY = "1,2";
735 | };
736 | name = Release;
737 | };
738 | 42321CAF2226BD1100CE1DCB /* Debug */ = {
739 | isa = XCBuildConfiguration;
740 | buildSettings = {
741 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
742 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
743 | CODE_SIGN_STYLE = Automatic;
744 | DEVELOPMENT_TEAM = M92A6H7EPZ;
745 | INFOPLIST_FILE = Example/Info.plist;
746 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
747 | LD_RUNPATH_SEARCH_PATHS = (
748 | "$(inherited)",
749 | "@executable_path/Frameworks",
750 | );
751 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.Example;
752 | PRODUCT_NAME = "$(TARGET_NAME)";
753 | SWIFT_VERSION = 5.0;
754 | TARGETED_DEVICE_FAMILY = "1,2";
755 | };
756 | name = Debug;
757 | };
758 | 42321CB02226BD1100CE1DCB /* Release */ = {
759 | isa = XCBuildConfiguration;
760 | buildSettings = {
761 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
762 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
763 | CODE_SIGN_STYLE = Automatic;
764 | DEVELOPMENT_TEAM = M92A6H7EPZ;
765 | INFOPLIST_FILE = Example/Info.plist;
766 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
767 | LD_RUNPATH_SEARCH_PATHS = (
768 | "$(inherited)",
769 | "@executable_path/Frameworks",
770 | );
771 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.Example;
772 | PRODUCT_NAME = "$(TARGET_NAME)";
773 | SWIFT_VERSION = 5.0;
774 | TARGETED_DEVICE_FAMILY = "1,2";
775 | };
776 | name = Release;
777 | };
778 | 42321CB12226BD1100CE1DCB /* Debug */ = {
779 | isa = XCBuildConfiguration;
780 | buildSettings = {
781 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
782 | BUNDLE_LOADER = "$(TEST_HOST)";
783 | CODE_SIGN_STYLE = Automatic;
784 | DEVELOPMENT_TEAM = MC6WZHXVVH;
785 | INFOPLIST_FILE = ExampleTests/Info.plist;
786 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
787 | LD_RUNPATH_SEARCH_PATHS = (
788 | "$(inherited)",
789 | "@executable_path/Frameworks",
790 | "@loader_path/Frameworks",
791 | );
792 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.ExampleTests;
793 | PRODUCT_NAME = "$(TARGET_NAME)";
794 | SWIFT_VERSION = 5.0;
795 | TARGETED_DEVICE_FAMILY = "1,2";
796 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
797 | };
798 | name = Debug;
799 | };
800 | 42321CB22226BD1100CE1DCB /* Release */ = {
801 | isa = XCBuildConfiguration;
802 | buildSettings = {
803 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
804 | BUNDLE_LOADER = "$(TEST_HOST)";
805 | CODE_SIGN_STYLE = Automatic;
806 | DEVELOPMENT_TEAM = MC6WZHXVVH;
807 | INFOPLIST_FILE = ExampleTests/Info.plist;
808 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
809 | LD_RUNPATH_SEARCH_PATHS = (
810 | "$(inherited)",
811 | "@executable_path/Frameworks",
812 | "@loader_path/Frameworks",
813 | );
814 | PRODUCT_BUNDLE_IDENTIFIER = dk.nodes.ExampleTests;
815 | PRODUCT_NAME = "$(TARGET_NAME)";
816 | SWIFT_VERSION = 5.0;
817 | TARGETED_DEVICE_FAMILY = "1,2";
818 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
819 | };
820 | name = Release;
821 | };
822 | /* End XCBuildConfiguration section */
823 |
824 | /* Begin XCConfigurationList section */
825 | 42321BE92226973500CE1DCB /* Build configuration list for PBXProject "Drawer" */ = {
826 | isa = XCConfigurationList;
827 | buildConfigurations = (
828 | 42321C012226973500CE1DCB /* Debug */,
829 | 42321C022226973500CE1DCB /* Release */,
830 | );
831 | defaultConfigurationIsVisible = 0;
832 | defaultConfigurationName = Release;
833 | };
834 | 42321C032226973500CE1DCB /* Build configuration list for PBXNativeTarget "Drawer" */ = {
835 | isa = XCConfigurationList;
836 | buildConfigurations = (
837 | 42321C042226973500CE1DCB /* Debug */,
838 | 42321C052226973500CE1DCB /* Release */,
839 | );
840 | defaultConfigurationIsVisible = 0;
841 | defaultConfigurationName = Release;
842 | };
843 | 42321C062226973500CE1DCB /* Build configuration list for PBXNativeTarget "DrawerTests" */ = {
844 | isa = XCConfigurationList;
845 | buildConfigurations = (
846 | 42321C072226973500CE1DCB /* Debug */,
847 | 42321C082226973500CE1DCB /* Release */,
848 | );
849 | defaultConfigurationIsVisible = 0;
850 | defaultConfigurationName = Release;
851 | };
852 | 42321CB32226BD1100CE1DCB /* Build configuration list for PBXNativeTarget "Example" */ = {
853 | isa = XCConfigurationList;
854 | buildConfigurations = (
855 | 42321CAF2226BD1100CE1DCB /* Debug */,
856 | 42321CB02226BD1100CE1DCB /* Release */,
857 | );
858 | defaultConfigurationIsVisible = 0;
859 | defaultConfigurationName = Release;
860 | };
861 | 42321CB42226BD1100CE1DCB /* Build configuration list for PBXNativeTarget "ExampleTests" */ = {
862 | isa = XCConfigurationList;
863 | buildConfigurations = (
864 | 42321CB12226BD1100CE1DCB /* Debug */,
865 | 42321CB22226BD1100CE1DCB /* Release */,
866 | );
867 | defaultConfigurationIsVisible = 0;
868 | defaultConfigurationName = Release;
869 | };
870 | /* End XCConfigurationList section */
871 | };
872 | rootObject = 42321BE62226973500CE1DCB /* Project object */;
873 | }
874 |
--------------------------------------------------------------------------------