├── .gitignore
├── .swift-version
├── .travis.yml
├── Example
├── .swiftlint.yml
├── Application
│ ├── Container.swift
│ ├── Delegate
│ │ ├── AppDelegate.swift
│ │ ├── AppDelegateAssembly.swift
│ │ └── Container_AppDelegateAssembly.swift
│ └── Info.plist
├── Resources
│ └── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ └── Contents.json
└── UI
│ ├── Base.lproj
│ └── LaunchScreen.storyboard
│ ├── Menu
│ ├── Container_MenuAssembly.swift
│ ├── MenuAssembly.swift
│ ├── ViewControllers
│ │ └── MenuViewController.swift
│ └── ViewModels
│ │ ├── MainMenuItemViewModel.swift
│ │ ├── MainMenuViewModel.swift
│ │ ├── MenuItemViewModel.swift
│ │ └── MenuViewModel.swift
│ └── TableExample
│ ├── Container_TableExampleAssembly.swift
│ ├── TableExampleAssembly.swift
│ ├── TableExampleCell.swift
│ └── TableExampleViewController.swift
├── ExampleTests
├── .swiftlint.yml
├── Application
│ └── AppDelegateSpec.swift
├── Doubles
│ ├── NavigationControllerSpy.swift
│ └── WindowSpy.swift
├── Info.plist
└── UI
│ ├── MainMenuItemViewModelSpec.swift
│ ├── MainMenuViewModelSpec.swift
│ ├── MenuViewControllerSpec.swift
│ ├── TableExampleCellSpec.swift
│ └── TableExampleViewControllerSpec.swift
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── Misc
└── SwipeToReveal-screenshot1.gif
├── Podfile
├── Podfile.lock
├── README.md
├── Source
└── SwipeToRevealView.swift
├── SwipeToReveal.podspec
├── SwipeToReveal.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ ├── SwipeToReveal Example Tests.xcscheme
│ ├── SwipeToReveal Example.xcscheme
│ └── SwipeToReveal Tests.xcscheme
├── SwipeToReveal.xcworkspace
└── contents.xcworkspacedata
└── Tests
├── Info.plist
└── SwipeToRevealViewSpec.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | ################################
2 | # OS X
3 |
4 | *.DS_Store
5 | *.swp
6 | .Trashes
7 |
8 | ################################
9 | # Xcode
10 |
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspective
18 | !default.perspective
19 | *.perspectivev3
20 | !default.perspectivev3
21 | *.xcuserstate
22 | project.xcworkspace/
23 | xcuserdata/
24 | build/
25 | dist/
26 | DerivedData/
27 | *.moved-aside
28 | *.xccheckout
29 |
30 | ################################
31 | # AppCode
32 |
33 | .idea
34 |
35 | ################################
36 | # Backup files
37 |
38 | *~
39 | *~.nib
40 | *~.xib
41 | \#*#
42 | .#*
43 |
44 | ################################
45 | # CocoaPods
46 |
47 | Pods/
48 | !Podfile.lock
49 |
50 | ################################
51 | # Fastlane
52 |
53 | fastlane/report.xml
54 | fastlane/test_output
55 | fastlane/screenshots
56 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode8.2
3 | cache: false
4 | sudo: false
5 | rvm:
6 | - 2.3.3
7 | before_install:
8 | - gem install bundler
9 | - bundle install --without=documentation
10 | - bundle exec pod install --repo-update
11 | script:
12 | - set -o pipefail && xcodebuild test -workspace SwipeToReveal.xcworkspace -scheme 'SwipeToReveal Tests' -destination 'id=34FA4749-C467-4D45-9F8E-E31AEDDC39C2' ONLY_ACTIVE_ARCH=NO | xcpretty
13 | - set -o pipefail && xcodebuild test -workspace SwipeToReveal.xcworkspace -scheme 'SwipeToReveal Example Tests' -destination 'id=34FA4749-C467-4D45-9F8E-E31AEDDC39C2' ONLY_ACTIVE_ARCH=NO | xcpretty
14 | - pod lib lint
15 |
--------------------------------------------------------------------------------
/Example/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | opt_in_rules:
2 | - empty_count
3 | - force_unwrapping
4 | - private_outlet
5 | - redundant_nil_coalesing
6 |
7 | excluded:
8 | - Pods
9 |
10 | line_length:
11 | warning: 120
12 | error: 200
13 |
14 | variable_name:
15 | excluded:
16 | - id
17 | - URL
18 | - to
19 | - rx
20 |
--------------------------------------------------------------------------------
/Example/Application/Container.swift:
--------------------------------------------------------------------------------
1 | class Container {}
2 |
--------------------------------------------------------------------------------
/Example/Application/Delegate/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder {
5 |
6 | override convenience init() {
7 | self.init(assembly: Container().appDelegateAssembly)
8 | }
9 |
10 | init(assembly: AppDelegateAssembly) {
11 | self.assembly = assembly
12 | super.init()
13 | }
14 |
15 | fileprivate let assembly: AppDelegateAssembly
16 | var window: UIWindow?
17 |
18 | }
19 |
20 | extension AppDelegate: UIApplicationDelegate {
21 |
22 | func application(_ application: UIApplication,
23 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
24 | window = assembly.window
25 | let navigationController = assembly.navigationController
26 | navigationController.viewControllers = [assembly.rootViewController]
27 | window?.rootViewController = navigationController
28 | window?.makeKeyAndVisible()
29 | return true
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Example/Application/Delegate/AppDelegateAssembly.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | protocol AppDelegateAssembly {
4 | var window: UIWindow { get }
5 | var navigationController: UINavigationController { get }
6 | var rootViewController: UIViewController { get }
7 | }
8 |
--------------------------------------------------------------------------------
/Example/Application/Delegate/Container_AppDelegateAssembly.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension Container {
4 | var appDelegateAssembly: AppDelegateAssembly {
5 | struct Assembly: AppDelegateAssembly {
6 |
7 | let container: Container
8 |
9 | var window: UIWindow {
10 | return UIWindow(frame: UIScreen.main.bounds)
11 | }
12 |
13 | var navigationController: UINavigationController {
14 | return UINavigationController()
15 | }
16 |
17 | var rootViewController: UIViewController {
18 | return MenuViewController(assembly: container.menuAssembly)
19 | }
20 |
21 | }
22 | return Assembly(container: self)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Example/Application/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeRight
33 | UIInterfaceOrientationLandscapeLeft
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Example/Resources/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 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/Example/UI/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 |
--------------------------------------------------------------------------------
/Example/UI/Menu/Container_MenuAssembly.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension Container {
4 | var menuAssembly: MenuAssembly {
5 | struct Assembly: MenuAssembly {
6 |
7 | let container: Container
8 |
9 | var viewModel: MenuViewModel {
10 | return MainMenuViewModel(assembly: self)
11 | }
12 |
13 | var tableExampleViewController: UIViewController {
14 | return TableExampleViewController(assembly: container.tableExampleAssembly)
15 | }
16 |
17 | }
18 | return Assembly(container: self)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Example/UI/Menu/MenuAssembly.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | protocol MenuAssembly {
4 | var viewModel: MenuViewModel { get }
5 | var tableExampleViewController: UIViewController { get }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/UI/Menu/ViewControllers/MenuViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class MenuViewController: UITableViewController, MenuViewModelDelegate {
4 |
5 | init(assembly: MenuAssembly) {
6 | self.assembly = assembly
7 | viewModel = assembly.viewModel
8 | super.init(nibName: nil, bundle: nil)
9 | viewModel.delegate = self
10 | }
11 |
12 | required init?(coder aDecoder: NSCoder) {
13 | fatalError("init(coder:) has not been implemented")
14 | }
15 |
16 | // MARK: View
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | navigationItem.title = viewModel.title
21 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
22 | tableView.tableFooterView = UIView(frame: .zero)
23 | }
24 |
25 | // MARK: UITableViewDataSource
26 |
27 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
28 | guard section == 0 else { return 0 }
29 | return viewModel.items.count
30 | }
31 |
32 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
33 | guard indexPath.section == 0 else { fatalError() }
34 | let viewModel = self.viewModel.items[indexPath.row]
35 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
36 | cell.accessoryType = .disclosureIndicator
37 | cell.textLabel?.text = viewModel.title
38 | return cell
39 | }
40 |
41 | // MARK: UITableViewDelegate
42 |
43 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
44 | guard indexPath.section == 0 else { fatalError() }
45 | let viewModel = self.viewModel.items[indexPath.row]
46 | viewModel.select()
47 | }
48 |
49 | // MARK: MenuViewModelDelegate
50 |
51 | func menuViewModel(_ viewModel: MenuViewModel, presentViewController viewController: UIViewController) {
52 | guard viewModel === self.viewModel else { fatalError() }
53 | navigationController?.pushViewController(viewController, animated: true)
54 | }
55 |
56 | // MARK: Private
57 |
58 | private let assembly: MenuAssembly
59 | private let viewModel: MenuViewModel
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Example/UI/Menu/ViewModels/MainMenuItemViewModel.swift:
--------------------------------------------------------------------------------
1 | class MainMenuItemViewModel: MenuItemViewModel {
2 |
3 | init(title: String) {
4 | self.title = title
5 | }
6 |
7 | // MARK: MenuItemViewModel
8 |
9 | weak var delegate: MenuItemViewModelDelegate?
10 |
11 | let title: String
12 |
13 | func select() {
14 | delegate?.menuItemViewModelDidSelect(self)
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Example/UI/Menu/ViewModels/MainMenuViewModel.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class MainMenuViewModel: MenuViewModel, MenuItemViewModelDelegate {
4 |
5 | init(assembly: MenuAssembly) {
6 | self.assembly = assembly
7 | tableViewExample.delegate = self
8 | }
9 |
10 | weak var delegate: MenuViewModelDelegate?
11 | private let assembly: MenuAssembly
12 | private let tableViewExample = MainMenuItemViewModel(title: "Table View Cell Example")
13 |
14 | // MARK: MenuViewModel
15 |
16 | let title = "SwipeToReveal"
17 |
18 | var items: [MenuItemViewModel] {
19 | return [tableViewExample]
20 | }
21 |
22 | // MARK: MenuItemViewModelDelegate
23 |
24 | func menuItemViewModelDidSelect(_ viewModel: MenuItemViewModel) {
25 | if viewModel === tableViewExample {
26 | let viewController = assembly.tableExampleViewController
27 | delegate?.menuViewModel(self, presentViewController: viewController)
28 | } else {
29 | fatalError()
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Example/UI/Menu/ViewModels/MenuItemViewModel.swift:
--------------------------------------------------------------------------------
1 | protocol MenuItemViewModel: class {
2 | weak var delegate: MenuItemViewModelDelegate? { get set }
3 | var title: String { get }
4 | func select()
5 | }
6 |
7 | protocol MenuItemViewModelDelegate: class {
8 | func menuItemViewModelDidSelect(_ viewModel: MenuItemViewModel)
9 | }
10 |
--------------------------------------------------------------------------------
/Example/UI/Menu/ViewModels/MenuViewModel.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | protocol MenuViewModel: class {
4 | weak var delegate: MenuViewModelDelegate? { get set }
5 | var title: String { get }
6 | var items: [MenuItemViewModel] { get }
7 | }
8 |
9 | protocol MenuViewModelDelegate: class {
10 | func menuViewModel(_ viewModel: MenuViewModel, presentViewController viewController: UIViewController)
11 | }
12 |
--------------------------------------------------------------------------------
/Example/UI/TableExample/Container_TableExampleAssembly.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension Container {
4 | var tableExampleAssembly: TableExampleAssembly {
5 | struct Assembly: TableExampleAssembly {}
6 | return Assembly()
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Example/UI/TableExample/TableExampleAssembly.swift:
--------------------------------------------------------------------------------
1 | protocol TableExampleAssembly {}
2 |
--------------------------------------------------------------------------------
/Example/UI/TableExample/TableExampleCell.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SnapKit
3 | import SwipeToReveal
4 | import Reusable
5 |
6 | class TableExampleCell: UITableViewCell, Reusable {
7 |
8 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
9 | super.init(style: style, reuseIdentifier: reuseIdentifier)
10 | loadSubviews()
11 | setupLayout()
12 | }
13 |
14 | required init?(coder aDecoder: NSCoder) {
15 | fatalError("init(coder:) has not been implemented")
16 | }
17 |
18 | override func prepareForReuse() {
19 | super.prepareForReuse()
20 | label.text = nil
21 | swipeToReveal.close(animated: false)
22 | }
23 |
24 | // MARK: Subviews
25 |
26 | let label = Factory.label
27 | let swipeToReveal = SwipeToRevealView(frame: .zero)
28 | let swipeButtonA = Factory.button(title: "Button A", color: .red)
29 | let swipeButtonB = Factory.button(title: "Button B", color: .blue)
30 |
31 | private func loadSubviews() {
32 | contentView.addSubview(swipeToReveal)
33 | swipeToReveal.contentView = swipeContentView
34 | swipeContentView.addSubview(label)
35 | swipeToReveal.rightView = swipeRightView
36 | swipeRightView.addSubview(swipeButtonA)
37 | swipeRightView.addSubview(swipeButtonB)
38 | }
39 |
40 | private let swipeContentView = Factory.view(layoutMargins: UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8))
41 | private let swipeRightView = Factory.view()
42 |
43 | // MARK: Layout
44 |
45 | private func setupLayout() {
46 | swipeToReveal.snp.makeConstraints {
47 | $0.edges.equalToSuperview()
48 | }
49 | label.snp.makeConstraints {
50 | guard let superview = label.superview else { fatalError() }
51 | $0.centerYWithinMargins.equalToSuperview()
52 | $0.top.greaterThanOrEqualTo(superview.snp.topMargin)
53 | $0.left.equalTo(superview.snp.leftMargin)
54 | $0.right.lessThanOrEqualTo(superview.snp.rightMargin)
55 | $0.bottom.lessThanOrEqualTo(superview.snp.bottomMargin)
56 | }
57 | swipeButtonA.snp.makeConstraints {
58 | $0.top.left.bottom.equalToSuperview()
59 | }
60 | swipeButtonB.snp.makeConstraints {
61 | $0.left.equalTo(swipeButtonA.snp.right)
62 | $0.top.right.bottom.equalToSuperview()
63 | }
64 | }
65 |
66 | }
67 |
68 | private extension TableExampleCell {
69 | struct Factory {
70 |
71 | static var label: UILabel {
72 | let label = UILabel(frame: .zero)
73 | label.font = UIFont.systemFont(ofSize: UIFont.systemFontSize)
74 | label.textColor = .darkText
75 | return label
76 | }
77 |
78 | static func button(title: String, color: UIColor) -> UIButton {
79 | let button = UIButton(frame: .zero)
80 | button.setTitle(title, for: .normal)
81 | button.setTitleColor(.white, for: .normal)
82 | button.backgroundColor = color
83 | button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
84 | return button
85 | }
86 |
87 | static func view(layoutMargins: UIEdgeInsets = .zero) -> UIView {
88 | let view = UIView(frame: .zero)
89 | view.layoutMargins = layoutMargins
90 | return view
91 | }
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Example/UI/TableExample/TableExampleViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Reusable
3 |
4 | class TableExampleViewController: UITableViewController {
5 |
6 | init(assembly: TableExampleAssembly) {
7 | self.assembly = assembly
8 | super.init(style: .plain)
9 | }
10 |
11 | required init?(coder aDecoder: NSCoder) {
12 | fatalError("init(coder:) has not been implemented")
13 | }
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | tableView.register(cellType: TableExampleCell.self)
18 | }
19 |
20 | // MARK: UITableViewDataSource
21 |
22 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
23 | switch section {
24 | case 0: return 100
25 | default: fatalError()
26 | }
27 | }
28 |
29 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
30 | let cell: TableExampleCell = tableView.dequeueReusableCell(for: indexPath)
31 | cell.label.text = "Cell \(indexPath.row + 1)"
32 | return cell
33 | }
34 |
35 | // MARK: UITableViewDelegate
36 |
37 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
38 | switch (indexPath.section, indexPath.row) {
39 | case (0, _):
40 | return 88
41 | default:
42 | fatalError()
43 | }
44 | }
45 |
46 | // MARK: Private
47 |
48 | private let assembly: TableExampleAssembly
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/ExampleTests/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | opt_in_rules:
2 | - empty_count
3 | - redundant_nil_coalesing
4 |
5 | disabled_rules:
6 | - line_length
7 | - variable_name
8 | - function_body_length
9 |
--------------------------------------------------------------------------------
/ExampleTests/Application/AppDelegateSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class AppDelegateSpec: QuickSpec {
6 |
7 | override func spec() {
8 | describe("AppDelegate") {
9 | var sut: AppDelegate!
10 | var assembly: Assembly!
11 |
12 | beforeEach {
13 | assembly = Assembly()
14 | sut = AppDelegate(assembly: assembly)
15 | }
16 |
17 | context("app did finish launching") {
18 | var returnValue: Bool!
19 |
20 | beforeEach {
21 | returnValue = sut.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)
22 | }
23 |
24 | it("should return true") {
25 | expect(returnValue).to(beTrue())
26 | }
27 |
28 | it("should make window key and visible") {
29 | expect(assembly.windowSpy.makeKeyAndVisibleCalled).to(beTrue())
30 | }
31 |
32 | describe("root navigation controller") {
33 | var controller: UINavigationController!
34 |
35 | beforeEach {
36 | controller = sut.window?.rootViewController as? UINavigationController
37 | }
38 |
39 | it("should be correct") {
40 | expect(controller).to(equal(assembly.navigationController))
41 | }
42 |
43 | it("should have correct root") {
44 | expect(controller.viewControllers.first).to(equal(assembly.rootViewController))
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
51 | struct Assembly: AppDelegateAssembly {
52 | let windowSpy = WindowSpy(frame: .zero)
53 | var window: UIWindow { return windowSpy }
54 | let navigationController = UINavigationController()
55 | let rootViewController = UIViewController(nibName: nil, bundle: nil)
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/ExampleTests/Doubles/NavigationControllerSpy.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class NavigationControllerSpy: UINavigationController {
4 |
5 | override func pushViewController(_ viewController: UIViewController, animated: Bool) {
6 | super.pushViewController(viewController, animated: animated)
7 | _didPushViewController = (viewController, animated)
8 | }
9 |
10 | private(set) var _didPushViewController: (viewController: UIViewController, animated: Bool)?
11 |
12 | func _reset() {
13 | _didPushViewController = nil
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/ExampleTests/Doubles/WindowSpy.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class WindowSpy: UIWindow {
4 |
5 | private(set) var makeKeyAndVisibleCalled = false
6 |
7 | override func makeKeyAndVisible() {
8 | makeKeyAndVisibleCalled = true
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/ExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ExampleTests/UI/MainMenuItemViewModelSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class MainMenuItemViewModelSpec: QuickSpec {
6 |
7 | override func spec() {
8 | describe("MainMenuItemViewModel") {
9 | var sut: MainMenuItemViewModel!
10 | var title: String!
11 | var delegate: Delegate!
12 |
13 | beforeEach {
14 | title = "Menu Item Title"
15 | delegate = Delegate()
16 | sut = MainMenuItemViewModel(title: title)
17 | sut.delegate = delegate
18 | }
19 |
20 | it("should have correct title") {
21 | expect(sut.title).to(equal(title))
22 | }
23 |
24 | context("did select") {
25 | beforeEach {
26 | sut.select()
27 | }
28 |
29 | it("should call delegate") {
30 | expect(delegate._menuItemViewModelDidSelect).to(be(sut))
31 | }
32 | }
33 | }
34 | }
35 |
36 | class Delegate: MenuItemViewModelDelegate {
37 |
38 | func menuItemViewModelDidSelect(_ viewModel: MenuItemViewModel) {
39 | _menuItemViewModelDidSelect = viewModel
40 | }
41 |
42 | private(set) var _menuItemViewModelDidSelect: MenuItemViewModel?
43 |
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/ExampleTests/UI/MainMenuViewModelSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class MainMenuViewModelSpec: QuickSpec {
6 |
7 | override func spec() {
8 | describe("MainMenuViewModel") {
9 | var sut: MainMenuViewModel!
10 | var assembly: Assembly!
11 | var delegate: Delegate!
12 |
13 | beforeEach {
14 | assembly = Assembly()
15 | delegate = Delegate()
16 | sut = MainMenuViewModel(assembly: assembly)
17 | sut.delegate = delegate
18 | }
19 |
20 | it("should have one item") {
21 | expect(sut.items.count).to(equal(1))
22 | }
23 |
24 | context("first item did select") {
25 | beforeEach {
26 | sut.menuItemViewModelDidSelect(sut.items.first!)
27 | }
28 |
29 | it("should call delegate") {
30 | expect(delegate._menuViewModelDidPresentViewController?.viewModel).to(be(sut))
31 | }
32 |
33 | it("should present correct view controller") {
34 | expect(delegate._menuViewModelDidPresentViewController?.viewController)
35 | .to(be(assembly.tableExampleViewController))
36 | }
37 | }
38 |
39 | context("unknown item did select") {
40 | it("should throw assertion") {
41 | expect { () -> Void in
42 | sut.menuItemViewModelDidSelect(MainMenuItemViewModel(title: "Unknown"))
43 | }.to(throwAssertion())
44 | }
45 | }
46 | }
47 | }
48 |
49 | struct Assembly: MenuAssembly {
50 | var viewModel: MenuViewModel { fatalError() }
51 | let tableExampleViewController = UIViewController(nibName: nil, bundle: nil)
52 | }
53 |
54 | class Delegate: MenuViewModelDelegate {
55 |
56 | func menuViewModel(_ viewModel: MenuViewModel,
57 | presentViewController viewController: UIViewController) {
58 | _menuViewModelDidPresentViewController = (viewModel, viewController)
59 | }
60 |
61 | private(set) var _menuViewModelDidPresentViewController:
62 | (viewModel: MenuViewModel, viewController: UIViewController)?
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/ExampleTests/UI/MenuViewControllerSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class MenuViewControllerSpec: QuickSpec {
6 |
7 | override func spec() {
8 | context("init with coder") {
9 | it("should throw asserion") {
10 | expect { () -> Void in _ = MenuViewController(coder: NSCoder()) }.to(throwAssertion())
11 | }
12 | }
13 |
14 | context("init") {
15 | var sut: MenuViewController!
16 | var assembly: Assembly!
17 | var viewModel: ViewModel!
18 |
19 | beforeEach {
20 | viewModel = ViewModel()
21 | assembly = Assembly(viewModel: viewModel)
22 | sut = MenuViewController(assembly: assembly)
23 | }
24 |
25 | context("load view") {
26 | beforeEach {
27 | _ = sut.view
28 | }
29 |
30 | it("should have correct title") {
31 | expect(sut.navigationItem.title).to(equal(viewModel.title))
32 | }
33 |
34 | describe("table view") {
35 | it("should have 1 section") {
36 | expect(sut.numberOfSections(in: sut.tableView)).to(equal(1))
37 | }
38 |
39 | it("should have 3 rows in first section") {
40 | expect(sut.tableView(sut.tableView, numberOfRowsInSection: 0)).to(equal(3))
41 | }
42 |
43 | it("should have 0 rows in second section") {
44 | expect(sut.tableView(sut.tableView, numberOfRowsInSection: 1)).to(equal(0))
45 | }
46 |
47 | func testCell(section: Int, row: Int) {
48 | describe("cell \(row) in section \(section)") {
49 | var cell: UITableViewCell!
50 |
51 | beforeEach {
52 | cell = sut.tableView(sut.tableView, cellForRowAt: IndexPath(row: row, section: section))
53 | }
54 |
55 | it("should have correct title") {
56 | expect(cell.textLabel?.text).to(equal(viewModel.items[row].title))
57 | }
58 |
59 | it("should have correct accessory type") {
60 | expect(cell.accessoryType).to(equal(UITableViewCellAccessoryType.disclosureIndicator))
61 | }
62 |
63 | it("should not be selected") {
64 | expect(viewModel._items[row]._isSelected).to(beFalse())
65 | }
66 |
67 | context("select") {
68 | beforeEach {
69 | sut.tableView(sut.tableView, didSelectRowAt: IndexPath(row: row, section: section))
70 | }
71 |
72 | it("should select view model") {
73 | expect(viewModel._items[row]._isSelected).to(beTrue())
74 | }
75 | }
76 | }
77 | }
78 |
79 | testCell(section: 0, row: 0)
80 | testCell(section: 0, row: 1)
81 | testCell(section: 0, row: 2)
82 |
83 | func testInvalidCell(section: Int, row: Int) {
84 | describe("invalid cell \(row) in section \(section)") {
85 | it("should throw assertion") {
86 | expect { () -> Void in
87 | _ = sut.tableView(sut.tableView, cellForRowAt: IndexPath(row: row, section: section))
88 | }.to(throwAssertion())
89 | }
90 |
91 | it("should throw assertion when selected") {
92 | expect { () -> Void in
93 | sut.tableView(sut.tableView, didSelectRowAt: IndexPath(row: row, section: section))
94 | }.to(throwAssertion())
95 | }
96 | }
97 | }
98 |
99 | testInvalidCell(section: 0, row: 3)
100 | testInvalidCell(section: 1, row: 0)
101 |
102 | }
103 | }
104 |
105 | context("embedded in UINavigationController") {
106 | var navigationController: NavigationControllerSpy!
107 |
108 | beforeEach {
109 | navigationController = NavigationControllerSpy(rootViewController: sut)
110 | _ = navigationController.view
111 | _ = sut.view
112 | navigationController._reset()
113 | }
114 |
115 | context("menu view model presents view controller") {
116 | var viewController: UIViewController!
117 |
118 | beforeEach {
119 | viewController = UIViewController(nibName: nil, bundle: nil)
120 | sut.menuViewModel(viewModel, presentViewController: viewController)
121 | }
122 |
123 | it("should push correct view controller animated") {
124 | let result = navigationController._didPushViewController
125 | expect(result?.viewController).to(be(viewController))
126 | expect(result?.animated).to(beTrue())
127 | }
128 | }
129 |
130 | context("unknown menu view model presents view controller") {
131 | it("should throw asserion") {
132 | expect { () -> Void in
133 | sut.menuViewModel(ViewModel(), presentViewController: UIViewController(nibName: nil, bundle: nil))
134 | }.to(throwAssertion())
135 | }
136 | }
137 | }
138 | }
139 | }
140 |
141 | struct Assembly: MenuAssembly {
142 | let viewModel: MenuViewModel
143 | var tableExampleViewController: UIViewController { fatalError() }
144 | }
145 |
146 | class ViewModel: MenuViewModel {
147 | weak var delegate: MenuViewModelDelegate?
148 |
149 | let title = "Menu Title"
150 |
151 | var items: [MenuItemViewModel] {
152 | return _items
153 | }
154 |
155 | let _items: [ItemViewModel] = [
156 | ItemViewModel(title: "Menu Item 1"),
157 | ItemViewModel(title: "Menu Item 2"),
158 | ItemViewModel(title: "Menu Item 3")
159 | ]
160 | }
161 |
162 | class ItemViewModel: MenuItemViewModel {
163 | init(title: String) {
164 | self.title = title
165 | }
166 |
167 | weak var delegate: MenuItemViewModelDelegate?
168 |
169 | let title: String
170 |
171 | func select() {
172 | _isSelected = true
173 | }
174 |
175 | private(set) var _isSelected = false
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/ExampleTests/UI/TableExampleCellSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class TableExampleCellSpec: QuickSpec {
6 |
7 | override func spec() {
8 | context("init with coder") {
9 | it("should throw asserion") {
10 | expect { () -> Void in _ = TableExampleCell(coder: NSCoder()) }.to(throwAssertion())
11 | }
12 | }
13 |
14 | context("init") {
15 | var sut: TableExampleCell!
16 |
17 | beforeEach {
18 | sut = TableExampleCell(style: .default, reuseIdentifier: "cell")
19 | }
20 |
21 | context("prepare for reuse") {
22 | beforeEach {
23 | sut.label.text = "Test"
24 | sut.prepareForReuse()
25 | }
26 |
27 | it("should clear label text") {
28 | expect(sut.label.text).to(beNil())
29 | }
30 | }
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/ExampleTests/UI/TableExampleViewControllerSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | @testable import SwipeToRevealExample
4 |
5 | class TableExampleViewControllerSpec: QuickSpec {
6 |
7 | override func spec() {
8 | context("init with coder") {
9 | it("should throw asserion") {
10 | expect { () -> Void in _ = TableExampleViewController(coder: NSCoder()) }.to(throwAssertion())
11 | }
12 | }
13 |
14 | context("init") {
15 | var sut: TableExampleViewController!
16 |
17 | beforeEach {
18 | sut = TableExampleViewController(assembly: Assembly())
19 | }
20 |
21 | context("load view") {
22 | beforeEach {
23 | _ = sut.view
24 | sut.view.frame = CGRect(x: 0, y: 0, width: 320, height: 240)
25 | }
26 |
27 | describe("table view") {
28 | it("should have 1 section") {
29 | expect(sut.numberOfSections(in: sut.tableView)).to(equal(1))
30 | }
31 |
32 | it("should have 100 rows in first section") {
33 | expect(sut.tableView(sut.tableView, numberOfRowsInSection: 0)).to(equal(100))
34 | }
35 |
36 | it("should throw when asked for number of rows in second section") {
37 | expect { () -> Void in
38 | _ = sut.tableView(sut.tableView, numberOfRowsInSection: 1)
39 | }.to(throwAssertion())
40 | }
41 |
42 | it("shuld not throw when asked for cell at valid index path") {
43 | expect { () -> Void in
44 | _ = sut.tableView(sut.tableView, cellForRowAt: IndexPath(row: 0, section: 0))
45 | }.notTo(throwAssertion())
46 | }
47 |
48 | it("should return correct height for a row") {
49 | expect(sut.tableView(sut.tableView, heightForRowAt: IndexPath(row: 0, section: 0)))
50 | .to(equal(88))
51 | }
52 |
53 | it("should throw when asked for row height at invalid index path") {
54 | expect { () -> Void in
55 | _ = sut.tableView(sut.tableView, heightForRowAt: IndexPath(row: 0, section: 1))
56 | }.to(throwAssertion())
57 | }
58 | }
59 | }
60 | }
61 | }
62 |
63 | struct Assembly: TableExampleAssembly {}
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'cocoapods', '~> 1.1', '>= 1.1.1'
4 | gem 'synx', '~> 0.2', '>= 0.2.1'
5 | gem 'xcpretty', '~> 0.2.4'
6 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (2.3.5)
5 | activesupport (4.2.9)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | claide (1.0.2)
11 | clamp (0.6.5)
12 | cocoapods (1.2.1)
13 | activesupport (>= 4.0.2, < 5)
14 | claide (>= 1.0.1, < 2.0)
15 | cocoapods-core (= 1.2.1)
16 | cocoapods-deintegrate (>= 1.0.1, < 2.0)
17 | cocoapods-downloader (>= 1.1.3, < 2.0)
18 | cocoapods-plugins (>= 1.0.0, < 2.0)
19 | cocoapods-search (>= 1.0.0, < 2.0)
20 | cocoapods-stats (>= 1.0.0, < 2.0)
21 | cocoapods-trunk (>= 1.2.0, < 2.0)
22 | cocoapods-try (>= 1.1.0, < 2.0)
23 | colored2 (~> 3.1)
24 | escape (~> 0.0.4)
25 | fourflusher (~> 2.0.1)
26 | gh_inspector (~> 1.0)
27 | molinillo (~> 0.5.7)
28 | nap (~> 1.0)
29 | ruby-macho (~> 1.1)
30 | xcodeproj (>= 1.4.4, < 2.0)
31 | cocoapods-core (1.2.1)
32 | activesupport (>= 4.0.2, < 5)
33 | fuzzy_match (~> 2.0.4)
34 | nap (~> 1.0)
35 | cocoapods-deintegrate (1.0.1)
36 | cocoapods-downloader (1.1.3)
37 | cocoapods-plugins (1.0.0)
38 | nap
39 | cocoapods-search (1.0.0)
40 | cocoapods-stats (1.0.0)
41 | cocoapods-trunk (1.2.0)
42 | nap (>= 0.8, < 2.0)
43 | netrc (= 0.7.8)
44 | cocoapods-try (1.1.0)
45 | colored2 (3.1.2)
46 | colorize (0.8.1)
47 | escape (0.0.4)
48 | fourflusher (2.0.1)
49 | fuzzy_match (2.0.4)
50 | gh_inspector (1.0.3)
51 | i18n (0.8.4)
52 | minitest (5.10.2)
53 | molinillo (0.5.7)
54 | nanaimo (0.2.3)
55 | nap (1.1.0)
56 | netrc (0.7.8)
57 | rouge (2.0.7)
58 | ruby-macho (1.1.0)
59 | synx (0.2.1)
60 | clamp (~> 0.6)
61 | colorize (~> 0.7)
62 | xcodeproj (~> 1.0)
63 | thread_safe (0.3.6)
64 | tzinfo (1.2.3)
65 | thread_safe (~> 0.1)
66 | xcodeproj (1.5.0)
67 | CFPropertyList (~> 2.3.3)
68 | claide (>= 1.0.2, < 2.0)
69 | colored2 (~> 3.1)
70 | nanaimo (~> 0.2.3)
71 | xcpretty (0.2.8)
72 | rouge (~> 2.0.7)
73 |
74 | PLATFORMS
75 | ruby
76 |
77 | DEPENDENCIES
78 | cocoapods (~> 1.1, >= 1.1.1)
79 | synx (~> 0.2, >= 0.2.1)
80 | xcpretty (~> 0.2.4)
81 |
82 | BUNDLED WITH
83 | 1.15.1
84 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Dariusz Rybicki Darrarski
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 |
--------------------------------------------------------------------------------
/Misc/SwipeToReveal-screenshot1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darrarski/SwipeToReveal-iOS/4507efca0fb0742ff98ca0700738fd174739b10b/Misc/SwipeToReveal-screenshot1.gif
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | source 'git://github.com/CocoaPods/Specs.git'
2 | platform :ios, '9.0'
3 | use_frameworks!
4 | inhibit_all_warnings!
5 |
6 | target 'SwipeToRevealExample' do
7 | pod 'SwipeToReveal', :path => '.'
8 | pod 'Reveal-SDK', :configurations => ['Debug']
9 | pod 'SnapKit', '~> 3.0'
10 | pod 'SwiftLint', '~> 0.16'
11 | pod 'Reusable', '~> 4.0'
12 | end
13 |
14 | target 'SwipeToRevealExampleTests' do
15 | pod 'SwipeToReveal', :path => '.'
16 | pod 'Quick', '~> 1.1'
17 | pod 'Nimble', '~> 7.0'
18 | end
19 |
20 | target 'SwipeToRevealTests' do
21 | pod 'SwipeToReveal', :path => '.'
22 | pod 'Quick', '~> 1.1'
23 | pod 'Nimble', '~> 7.0'
24 | end
25 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Nimble (7.0.1)
3 | - Quick (1.1.0)
4 | - Reusable (4.0.0):
5 | - Reusable/Storyboard (= 4.0.0)
6 | - Reusable/View (= 4.0.0)
7 | - Reusable/Storyboard (4.0.0)
8 | - Reusable/View (4.0.0)
9 | - Reveal-SDK (8)
10 | - SnapKit (3.2.0)
11 | - SwiftLint (0.20.1)
12 | - SwipeToReveal (1.0.4):
13 | - SnapKit (~> 3.0)
14 |
15 | DEPENDENCIES:
16 | - Nimble (~> 7.0)
17 | - Quick (~> 1.1)
18 | - Reusable (~> 4.0)
19 | - Reveal-SDK
20 | - SnapKit (~> 3.0)
21 | - SwiftLint (~> 0.16)
22 | - SwipeToReveal (from `.`)
23 |
24 | EXTERNAL SOURCES:
25 | SwipeToReveal:
26 | :path: "."
27 |
28 | SPEC CHECKSUMS:
29 | Nimble: 657d000e11df8aebe27cdaf9d244de7f30ed87f7
30 | Quick: dafc587e21eed9f4cab3249b9f9015b0b7a7f71d
31 | Reusable: 98e5fff1e0e2e00872199699b276dde08ee56c07
32 | Reveal-SDK: 43be4e662864e937960d0d04d005135e29c4e53b
33 | SnapKit: 1ca44df72cfa543218d177cb8aab029d10d86ea7
34 | SwiftLint: f60095dc173a3f3ec505bb34f5229c3dfd779a54
35 | SwipeToReveal: 363d2a93389dcfe558fb3839fa1a90960c18261f
36 |
37 | PODFILE CHECKSUM: 113efe820790c24ee8fde67dd0fe4f6961d9b39e
38 |
39 | COCOAPODS: 1.2.1
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwipeToReveal iOS
2 |
3 | 
4 | [](https://cocoapods.org/pods/SwipeToReveal)
5 | [](https://travis-ci.org/darrarski/SwipeToReveal-iOS)
6 |
7 | Customizable swipe-to-reveal menu for iOS apps.
8 |
9 | 
10 |
11 | ## Installation
12 |
13 | You can integrate `SwipeToReveal` with your project using CocoaPods. Just add this line to your `Podfile`:
14 |
15 | ```ruby
16 | pod 'SwipeToReveal', '~> 1.0'
17 | ```
18 |
19 | ## Usage
20 |
21 | Check out included example project. It shows how to use swipe menu on `UITableViewCell`, but component could be embedded **anywhere** in the view hierarchy. All public headers are documented.
22 |
23 |
24 | ## License
25 |
26 | MIT License - check out [LICENSE](LICENSE) file.
27 |
--------------------------------------------------------------------------------
/Source/SwipeToRevealView.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SnapKit
3 |
4 | public protocol SwipeToRevealViewDelegate: class {
5 | func swipeToRevealView(_ view: SwipeToRevealView, didCloseAnimated animated: Bool)
6 | func swipeToRevealView(_ view: SwipeToRevealView, didRevealRightAnimated animated: Bool)
7 | func swipeToRevealView(_ view: SwipeToRevealView, didPan pan: UIPanGestureRecognizer)
8 | }
9 |
10 | /// Swipe-to-reveal view
11 | public class SwipeToRevealView: UIView {
12 |
13 | public weak var delegate: SwipeToRevealViewDelegate?
14 |
15 | /// Create SwipeToRevealView
16 | ///
17 | /// - Parameter frame: frame
18 | override public init(frame: CGRect) {
19 | super.init(frame: frame)
20 | loadSubviews()
21 | setupLayout()
22 | setupGestureRecognizing()
23 | }
24 |
25 | required public init?(coder aDecoder: NSCoder) {
26 | fatalError("init(coder:) has not been implemented")
27 | }
28 |
29 | /// Close, so not extra content is revealed
30 | ///
31 | /// - Parameter animated: perform with animation
32 | public func close(animated: Bool) {
33 | contentOffset = closedOffset
34 | layoutIfNeeded(animated: animated)
35 | delegate?.swipeToRevealView(self, didCloseAnimated: animated)
36 | }
37 |
38 | /// Reveal right view
39 | ///
40 | /// - Parameter animated: perform with animation
41 | public func revealRight(animated: Bool) {
42 | contentOffset = rightRevealedOffset
43 | layoutIfNeeded(animated: animated)
44 | delegate?.swipeToRevealView(self, didRevealRightAnimated: animated)
45 | }
46 |
47 | // MARK: Subviews
48 |
49 | /// Main view, displayed fully when no extra content is revealed
50 | public var contentView: UIView? {
51 | didSet {
52 | if let oldValue = oldValue {
53 | oldValue.removeFromSuperview()
54 | }
55 | if let newValue = contentView {
56 | centerContainer.addSubview(newValue)
57 | newValue.snp.makeConstraints { $0.edges.equalToSuperview() }
58 | }
59 | }
60 | }
61 |
62 | /// Right view, hidden by default, can be revelead with swipe gesture
63 | public var rightView: UIView? {
64 | didSet {
65 | if let oldValue = oldValue {
66 | oldValue.removeFromSuperview()
67 | }
68 | if let newValue = rightView {
69 | rightContainer.addSubview(newValue)
70 | newValue.snp.makeConstraints { $0.edges.equalToSuperview() }
71 | }
72 | }
73 | }
74 |
75 | private func loadSubviews() {
76 | addSubview(centerContainer)
77 | addSubview(rightContainer)
78 | }
79 |
80 | private let centerContainer = UIView(frame: .zero)
81 | private let rightContainer = UIView(frame: .zero)
82 |
83 | // MARK: Layout
84 |
85 | /// Content offset - changes when swiping
86 | public var contentOffset = CGFloat(0) {
87 | didSet { centerContainer.snp.updateConstraints { $0.left.equalTo(contentOffset) } }
88 | }
89 |
90 | /// Value for content offset in default state
91 | public let closedOffset = CGFloat(0)
92 |
93 | /// Value for content offset when right view is fully revealed
94 | public var rightRevealedOffset: CGFloat {
95 | return -rightContainer.frame.width
96 | }
97 |
98 | private func setupLayout() {
99 | centerContainer.snp.makeConstraints {
100 | $0.top.equalToSuperview()
101 | $0.bottom.equalToSuperview()
102 | $0.size.equalToSuperview()
103 | $0.left.equalTo(contentOffset)
104 | }
105 | rightContainer.snp.makeConstraints {
106 | $0.top.equalTo(centerContainer.snp.top)
107 | $0.left.equalTo(centerContainer.snp.right)
108 | $0.bottom.equalTo(centerContainer.snp.bottom)
109 | }
110 | }
111 |
112 | private func layoutIfNeeded(animated: Bool) {
113 | guard animated else {
114 | super.layoutIfNeeded()
115 | return
116 | }
117 |
118 | UIView.animate(withDuration: 0.2,
119 | delay: 0,
120 | options: UIViewAnimationOptions.curveEaseInOut,
121 | animations: { [weak self] in self?.layoutIfNeeded() })
122 | }
123 |
124 | // MARK: Gesture recognizing
125 |
126 | private func setupGestureRecognizing() {
127 | panGeastureRecognizer.delegate = self
128 | panGeastureRecognizer.addTarget(self, action: #selector(self.panGestureRecognizerUpdate(_:)))
129 | addGestureRecognizer(panGeastureRecognizer)
130 | }
131 |
132 | private let panGeastureRecognizer = UIPanGestureRecognizer()
133 |
134 | private struct Pan {
135 | let startPoint: CGFloat
136 | let startOffset: CGFloat
137 |
138 | var currentPoint: CGFloat {
139 | didSet { previousPoint = oldValue }
140 | }
141 |
142 | private var previousPoint: CGFloat
143 |
144 | var lastDelta: CGFloat {
145 | return currentPoint - previousPoint
146 | }
147 |
148 | var delta: CGFloat {
149 | return currentPoint - startPoint
150 | }
151 |
152 | init(point: CGFloat, offset: CGFloat) {
153 | self.startPoint = point
154 | self.startOffset = offset
155 | self.currentPoint = point
156 | self.previousPoint = point
157 | }
158 | }
159 |
160 | private var pan: Pan?
161 |
162 | func panGestureRecognizerUpdate(_ pgr: UIPanGestureRecognizer) {
163 | switch pgr.state {
164 | case .possible: break
165 | case .began:
166 | handlePanBegan(point: pgr.translation(in: self).x)
167 | case .changed:
168 | handlePanChanged(point: pgr.translation(in: self).x)
169 | case .ended, .cancelled, .failed:
170 | handlePanEnded()
171 | }
172 |
173 | delegate?.swipeToRevealView(self, didPan: pgr)
174 | }
175 |
176 | private func handlePanBegan(point: CGFloat) {
177 | pan = Pan(point: point, offset: contentOffset)
178 | }
179 |
180 | private func handlePanChanged(point: CGFloat) {
181 | pan?.currentPoint = point
182 | guard let pan = pan else { return }
183 | let targetOffset = pan.startOffset + pan.delta
184 | contentOffset = max(rightRevealedOffset, min(closedOffset, targetOffset))
185 | }
186 |
187 | private func handlePanEnded() {
188 | guard let pan = pan else { return }
189 |
190 | if pan.lastDelta > 0 {
191 | contentOffset = closedOffset
192 | } else {
193 | contentOffset = rightRevealedOffset
194 | }
195 |
196 | layoutIfNeeded(animated: true)
197 | self.pan = nil
198 | }
199 |
200 | }
201 |
202 | extension SwipeToRevealView: UIGestureRecognizerDelegate {
203 |
204 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
205 | shouldRecognizeSimultaneouslyWith
206 | otherGestureRecognizer: UIGestureRecognizer) -> Bool {
207 | return false
208 | }
209 |
210 | override public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
211 | guard let pgr = gestureRecognizer as? UIPanGestureRecognizer else { fatalError() }
212 | let velocity = pgr.velocity(in: self)
213 | return fabs(velocity.x) > fabs(velocity.y)
214 | }
215 |
216 | }
217 |
--------------------------------------------------------------------------------
/SwipeToReveal.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'SwipeToReveal'
3 | s.version = '1.0.4'
4 | s.summary = 'Customizable swipe-to-reveal view for iOS apps'
5 | s.homepage = 'https://github.com/darrarski/SwipeToReveal-iOS'
6 | s.author = { 'Dariusz Rybicki' => 'darrarski@gmail.com' }
7 | s.social_media_url = 'https://twitter.com/darrarski'
8 | s.license = { :type => 'MIT',
9 | :file => 'LICENSE' }
10 | s.source = { :git => 'https://github.com/darrarski/SwipeToReveal-iOS.git',
11 | :tag => "v#{s.version}" }
12 | s.platform = :ios
13 | s.ios.deployment_target = '9.0'
14 | s.source_files = 'Source'
15 | s.requires_arc = true
16 | s.frameworks = 'UIKit'
17 |
18 | s.dependency 'SnapKit', '~> 3.0'
19 | end
20 |
--------------------------------------------------------------------------------
/SwipeToReveal.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 310FC2CA9FD77D1D1EBAC032 /* Pods_SwipeToRevealExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42DF1915B99875D21FA7B4DA /* Pods_SwipeToRevealExampleTests.framework */; };
11 | 311714D81E5A6B640029A012 /* MainMenuItemViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311714D61E5A6AF60029A012 /* MainMenuItemViewModelSpec.swift */; };
12 | 311714DB1E5A6D5C0029A012 /* MainMenuViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311714D91E5A6CBA0029A012 /* MainMenuViewModelSpec.swift */; };
13 | 314A558E1E48E1CC00DD410B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314A558D1E48E1CC00DD410B /* AppDelegate.swift */; };
14 | 314A55901E48E1CC00DD410B /* TableExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314A558F1E48E1CC00DD410B /* TableExampleViewController.swift */; };
15 | 314A55951E48E1CC00DD410B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 314A55941E48E1CC00DD410B /* Assets.xcassets */; };
16 | 314A55981E48E1CC00DD410B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 314A55961E48E1CC00DD410B /* LaunchScreen.storyboard */; };
17 | 314A55A31E48E8BA00DD410B /* TableExampleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314A55A21E48E8BA00DD410B /* TableExampleCell.swift */; };
18 | 315BBE071E5BA976006148B7 /* NavigationControllerSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BBE061E5BA976006148B7 /* NavigationControllerSpy.swift */; };
19 | 318DD17B1E5D07F600F1A091 /* SwipeToRevealViewSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318DD1751E5CDCA100F1A091 /* SwipeToRevealViewSpec.swift */; };
20 | 318EB7EB1E5A43D70072426E /* MenuViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318EB7E91E5A43340072426E /* MenuViewControllerSpec.swift */; };
21 | 318EB7ED1E5A44610072426E /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318EB7EC1E5A44610072426E /* MenuViewModel.swift */; };
22 | 318EB7EF1E5A44AA0072426E /* MenuItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318EB7EE1E5A44AA0072426E /* MenuItemViewModel.swift */; };
23 | 318EB7F11E5A44F60072426E /* MainMenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318EB7F01E5A44F60072426E /* MainMenuViewModel.swift */; };
24 | 318EB7F31E5A453D0072426E /* MainMenuItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 318EB7F21E5A453D0072426E /* MainMenuItemViewModel.swift */; };
25 | 31A076851E57C2FB00D82BD7 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076841E57C2FB00D82BD7 /* Container.swift */; };
26 | 31A076871E57C31500D82BD7 /* AppDelegateAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076861E57C31500D82BD7 /* AppDelegateAssembly.swift */; };
27 | 31A076891E57C33B00D82BD7 /* Container_AppDelegateAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076881E57C33B00D82BD7 /* Container_AppDelegateAssembly.swift */; };
28 | 31A076981E57C6E100D82BD7 /* AppDelegateSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076961E57C67F00D82BD7 /* AppDelegateSpec.swift */; };
29 | 31A076A31E57CD8A00D82BD7 /* WindowSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076A11E57CD6900D82BD7 /* WindowSpy.swift */; };
30 | 31A076A81E57CEA400D82BD7 /* TableExampleAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076A71E57CEA400D82BD7 /* TableExampleAssembly.swift */; };
31 | 31A076AA1E57CEB200D82BD7 /* Container_TableExampleAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076A91E57CEB200D82BD7 /* Container_TableExampleAssembly.swift */; };
32 | 31A076AD1E57D27700D82BD7 /* MenuAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076AC1E57D27700D82BD7 /* MenuAssembly.swift */; };
33 | 31A076AF1E57D28000D82BD7 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076AE1E57D28000D82BD7 /* MenuViewController.swift */; };
34 | 31A076B11E57D29000D82BD7 /* Container_MenuAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A076B01E57D29000D82BD7 /* Container_MenuAssembly.swift */; };
35 | 31D017871E5BB15800F89A35 /* TableExampleViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D017851E5BB15500F89A35 /* TableExampleViewControllerSpec.swift */; };
36 | 31D0178A1E5BB76300F89A35 /* TableExampleCellSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D017881E5BB75000F89A35 /* TableExampleCellSpec.swift */; };
37 | 7EA899CDFED923D2FBF21F26 /* Pods_SwipeToRevealExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53EFD90C736845F0F5D16D61 /* Pods_SwipeToRevealExample.framework */; };
38 | DCEB024567E3A2397088E635 /* Pods_SwipeToRevealTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE8394623A061A1D76EEDCF /* Pods_SwipeToRevealTests.framework */; };
39 | /* End PBXBuildFile section */
40 |
41 | /* Begin PBXContainerItemProxy section */
42 | 31A0769F1E57C8D900D82BD7 /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = 314A55821E48E1CC00DD410B /* Project object */;
45 | proxyType = 1;
46 | remoteGlobalIDString = 314A55891E48E1CC00DD410B;
47 | remoteInfo = SwipeToRevealExample;
48 | };
49 | /* End PBXContainerItemProxy section */
50 |
51 | /* Begin PBXFileReference section */
52 | 0598EC71861C2CB0F06509AC /* Pods-SwipeToRevealTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealTests/Pods-SwipeToRevealTests.debug.xcconfig"; sourceTree = ""; };
53 | 1EBACFF15A65C0ED772D25B3 /* Pods-SwipeToRevealExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealExample/Pods-SwipeToRevealExample.release.xcconfig"; sourceTree = ""; };
54 | 2AE8394623A061A1D76EEDCF /* Pods_SwipeToRevealTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwipeToRevealTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
55 | 311714D61E5A6AF60029A012 /* MainMenuItemViewModelSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenuItemViewModelSpec.swift; sourceTree = ""; };
56 | 311714D91E5A6CBA0029A012 /* MainMenuViewModelSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenuViewModelSpec.swift; sourceTree = ""; };
57 | 314A558A1E48E1CC00DD410B /* SwipeToRevealExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwipeToRevealExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 314A558D1E48E1CC00DD410B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
59 | 314A558F1E48E1CC00DD410B /* TableExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableExampleViewController.swift; sourceTree = ""; };
60 | 314A55941E48E1CC00DD410B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
61 | 314A55971E48E1CC00DD410B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
62 | 314A55991E48E1CC00DD410B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 314A55A21E48E8BA00DD410B /* TableExampleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableExampleCell.swift; sourceTree = ""; };
64 | 315BBE061E5BA976006148B7 /* NavigationControllerSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationControllerSpy.swift; sourceTree = ""; };
65 | 318DD16D1E5CDA9100F1A091 /* SwipeToRevealTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwipeToRevealTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
66 | 318DD1711E5CDA9100F1A091 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
67 | 318DD1751E5CDCA100F1A091 /* SwipeToRevealViewSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwipeToRevealViewSpec.swift; sourceTree = ""; };
68 | 318EB7E91E5A43340072426E /* MenuViewControllerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuViewControllerSpec.swift; sourceTree = ""; };
69 | 318EB7EC1E5A44610072426E /* MenuViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuViewModel.swift; sourceTree = ""; };
70 | 318EB7EE1E5A44AA0072426E /* MenuItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuItemViewModel.swift; sourceTree = ""; };
71 | 318EB7F01E5A44F60072426E /* MainMenuViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenuViewModel.swift; sourceTree = ""; };
72 | 318EB7F21E5A453D0072426E /* MainMenuItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainMenuItemViewModel.swift; sourceTree = ""; };
73 | 31A076841E57C2FB00D82BD7 /* Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; };
74 | 31A076861E57C31500D82BD7 /* AppDelegateAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegateAssembly.swift; sourceTree = ""; };
75 | 31A076881E57C33B00D82BD7 /* Container_AppDelegateAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container_AppDelegateAssembly.swift; sourceTree = ""; };
76 | 31A0768E1E57C48A00D82BD7 /* SwipeToRevealExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwipeToRevealExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
77 | 31A076921E57C48A00D82BD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
78 | 31A076961E57C67F00D82BD7 /* AppDelegateSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegateSpec.swift; sourceTree = ""; };
79 | 31A076A11E57CD6900D82BD7 /* WindowSpy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowSpy.swift; sourceTree = ""; };
80 | 31A076A71E57CEA400D82BD7 /* TableExampleAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableExampleAssembly.swift; sourceTree = ""; };
81 | 31A076A91E57CEB200D82BD7 /* Container_TableExampleAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container_TableExampleAssembly.swift; sourceTree = ""; };
82 | 31A076AC1E57D27700D82BD7 /* MenuAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuAssembly.swift; sourceTree = ""; };
83 | 31A076AE1E57D28000D82BD7 /* MenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuViewController.swift; sourceTree = ""; };
84 | 31A076B01E57D29000D82BD7 /* Container_MenuAssembly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Container_MenuAssembly.swift; sourceTree = ""; };
85 | 31D017851E5BB15500F89A35 /* TableExampleViewControllerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableExampleViewControllerSpec.swift; sourceTree = ""; };
86 | 31D017881E5BB75000F89A35 /* TableExampleCellSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableExampleCellSpec.swift; sourceTree = ""; };
87 | 42DF1915B99875D21FA7B4DA /* Pods_SwipeToRevealExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwipeToRevealExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
88 | 53EFD90C736845F0F5D16D61 /* Pods_SwipeToRevealExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwipeToRevealExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
89 | 5B4979947EEC3481468A09BD /* Pods-SwipeToRevealExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealExampleTests/Pods-SwipeToRevealExampleTests.debug.xcconfig"; sourceTree = ""; };
90 | 965BBCD85442586E700FFB28 /* Pods-SwipeToRevealExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealExample/Pods-SwipeToRevealExample.debug.xcconfig"; sourceTree = ""; };
91 | E08F4E7EEFE7CC457E74E83D /* Pods-SwipeToRevealTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealTests/Pods-SwipeToRevealTests.release.xcconfig"; sourceTree = ""; };
92 | F736ACAA48911E20D6BD4B89 /* Pods-SwipeToRevealExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwipeToRevealExampleTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwipeToRevealExampleTests/Pods-SwipeToRevealExampleTests.release.xcconfig"; sourceTree = ""; };
93 | /* End PBXFileReference section */
94 |
95 | /* Begin PBXFrameworksBuildPhase section */
96 | 314A55871E48E1CC00DD410B /* Frameworks */ = {
97 | isa = PBXFrameworksBuildPhase;
98 | buildActionMask = 2147483647;
99 | files = (
100 | 7EA899CDFED923D2FBF21F26 /* Pods_SwipeToRevealExample.framework in Frameworks */,
101 | );
102 | runOnlyForDeploymentPostprocessing = 0;
103 | };
104 | 318DD16A1E5CDA9100F1A091 /* Frameworks */ = {
105 | isa = PBXFrameworksBuildPhase;
106 | buildActionMask = 2147483647;
107 | files = (
108 | DCEB024567E3A2397088E635 /* Pods_SwipeToRevealTests.framework in Frameworks */,
109 | );
110 | runOnlyForDeploymentPostprocessing = 0;
111 | };
112 | 31A0768B1E57C48A00D82BD7 /* Frameworks */ = {
113 | isa = PBXFrameworksBuildPhase;
114 | buildActionMask = 2147483647;
115 | files = (
116 | 310FC2CA9FD77D1D1EBAC032 /* Pods_SwipeToRevealExampleTests.framework in Frameworks */,
117 | );
118 | runOnlyForDeploymentPostprocessing = 0;
119 | };
120 | /* End PBXFrameworksBuildPhase section */
121 |
122 | /* Begin PBXGroup section */
123 | 311714DC1E5A6EE10029A012 /* ViewModels */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 318EB7F21E5A453D0072426E /* MainMenuItemViewModel.swift */,
127 | 318EB7F01E5A44F60072426E /* MainMenuViewModel.swift */,
128 | 318EB7EE1E5A44AA0072426E /* MenuItemViewModel.swift */,
129 | 318EB7EC1E5A44610072426E /* MenuViewModel.swift */,
130 | );
131 | path = ViewModels;
132 | sourceTree = "";
133 | };
134 | 311714DD1E5A6EE70029A012 /* ViewControllers */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 31A076AE1E57D28000D82BD7 /* MenuViewController.swift */,
138 | );
139 | path = ViewControllers;
140 | sourceTree = "";
141 | };
142 | 314A55811E48E1CC00DD410B = {
143 | isa = PBXGroup;
144 | children = (
145 | 314A558C1E48E1CC00DD410B /* Example */,
146 | 31A0768F1E57C48A00D82BD7 /* ExampleTests */,
147 | C69363D1A96F41166FC06D26 /* Frameworks */,
148 | BCB2B849A7B008448623F7A5 /* Pods */,
149 | 314A558B1E48E1CC00DD410B /* Products */,
150 | 318DD16E1E5CDA9100F1A091 /* Tests */,
151 | );
152 | sourceTree = "";
153 | };
154 | 314A558B1E48E1CC00DD410B /* Products */ = {
155 | isa = PBXGroup;
156 | children = (
157 | 314A558A1E48E1CC00DD410B /* SwipeToRevealExample.app */,
158 | 31A0768E1E57C48A00D82BD7 /* SwipeToRevealExampleTests.xctest */,
159 | 318DD16D1E5CDA9100F1A091 /* SwipeToRevealTests.xctest */,
160 | );
161 | name = Products;
162 | sourceTree = "";
163 | };
164 | 314A558C1E48E1CC00DD410B /* Example */ = {
165 | isa = PBXGroup;
166 | children = (
167 | 314A559F1E48E36500DD410B /* Application */,
168 | 314A55A01E48E36F00DD410B /* Resources */,
169 | 314A55A11E48E37A00DD410B /* UI */,
170 | );
171 | path = Example;
172 | sourceTree = "";
173 | };
174 | 314A559F1E48E36500DD410B /* Application */ = {
175 | isa = PBXGroup;
176 | children = (
177 | 31A076B21E57D6D000D82BD7 /* Delegate */,
178 | 31A076841E57C2FB00D82BD7 /* Container.swift */,
179 | 314A55991E48E1CC00DD410B /* Info.plist */,
180 | );
181 | path = Application;
182 | sourceTree = "";
183 | };
184 | 314A55A01E48E36F00DD410B /* Resources */ = {
185 | isa = PBXGroup;
186 | children = (
187 | 314A55941E48E1CC00DD410B /* Assets.xcassets */,
188 | );
189 | path = Resources;
190 | sourceTree = "";
191 | };
192 | 314A55A11E48E37A00DD410B /* UI */ = {
193 | isa = PBXGroup;
194 | children = (
195 | 31A076AB1E57D26E00D82BD7 /* Menu */,
196 | 31A076831E57C0F600D82BD7 /* TableExample */,
197 | 314A55961E48E1CC00DD410B /* LaunchScreen.storyboard */,
198 | );
199 | path = UI;
200 | sourceTree = "";
201 | };
202 | 315BBE051E5BA8ED006148B7 /* Doubles */ = {
203 | isa = PBXGroup;
204 | children = (
205 | 315BBE061E5BA976006148B7 /* NavigationControllerSpy.swift */,
206 | 31A076A11E57CD6900D82BD7 /* WindowSpy.swift */,
207 | );
208 | path = Doubles;
209 | sourceTree = "";
210 | };
211 | 318DD16E1E5CDA9100F1A091 /* Tests */ = {
212 | isa = PBXGroup;
213 | children = (
214 | 318DD1711E5CDA9100F1A091 /* Info.plist */,
215 | 318DD1751E5CDCA100F1A091 /* SwipeToRevealViewSpec.swift */,
216 | );
217 | path = Tests;
218 | sourceTree = "";
219 | };
220 | 318EB7E81E5A43260072426E /* UI */ = {
221 | isa = PBXGroup;
222 | children = (
223 | 311714D61E5A6AF60029A012 /* MainMenuItemViewModelSpec.swift */,
224 | 311714D91E5A6CBA0029A012 /* MainMenuViewModelSpec.swift */,
225 | 318EB7E91E5A43340072426E /* MenuViewControllerSpec.swift */,
226 | 31D017881E5BB75000F89A35 /* TableExampleCellSpec.swift */,
227 | 31D017851E5BB15500F89A35 /* TableExampleViewControllerSpec.swift */,
228 | );
229 | path = UI;
230 | sourceTree = "";
231 | };
232 | 31A076831E57C0F600D82BD7 /* TableExample */ = {
233 | isa = PBXGroup;
234 | children = (
235 | 31A076A91E57CEB200D82BD7 /* Container_TableExampleAssembly.swift */,
236 | 31A076A71E57CEA400D82BD7 /* TableExampleAssembly.swift */,
237 | 314A55A21E48E8BA00DD410B /* TableExampleCell.swift */,
238 | 314A558F1E48E1CC00DD410B /* TableExampleViewController.swift */,
239 | );
240 | path = TableExample;
241 | sourceTree = "";
242 | };
243 | 31A0768F1E57C48A00D82BD7 /* ExampleTests */ = {
244 | isa = PBXGroup;
245 | children = (
246 | 31A076A51E57CDB700D82BD7 /* Application */,
247 | 315BBE051E5BA8ED006148B7 /* Doubles */,
248 | 318EB7E81E5A43260072426E /* UI */,
249 | 31A076921E57C48A00D82BD7 /* Info.plist */,
250 | );
251 | path = ExampleTests;
252 | sourceTree = "";
253 | };
254 | 31A076A51E57CDB700D82BD7 /* Application */ = {
255 | isa = PBXGroup;
256 | children = (
257 | 31A076961E57C67F00D82BD7 /* AppDelegateSpec.swift */,
258 | );
259 | path = Application;
260 | sourceTree = "";
261 | };
262 | 31A076AB1E57D26E00D82BD7 /* Menu */ = {
263 | isa = PBXGroup;
264 | children = (
265 | 311714DD1E5A6EE70029A012 /* ViewControllers */,
266 | 311714DC1E5A6EE10029A012 /* ViewModels */,
267 | 31A076B01E57D29000D82BD7 /* Container_MenuAssembly.swift */,
268 | 31A076AC1E57D27700D82BD7 /* MenuAssembly.swift */,
269 | );
270 | path = Menu;
271 | sourceTree = "";
272 | };
273 | 31A076B21E57D6D000D82BD7 /* Delegate */ = {
274 | isa = PBXGroup;
275 | children = (
276 | 314A558D1E48E1CC00DD410B /* AppDelegate.swift */,
277 | 31A076861E57C31500D82BD7 /* AppDelegateAssembly.swift */,
278 | 31A076881E57C33B00D82BD7 /* Container_AppDelegateAssembly.swift */,
279 | );
280 | path = Delegate;
281 | sourceTree = "";
282 | };
283 | BCB2B849A7B008448623F7A5 /* Pods */ = {
284 | isa = PBXGroup;
285 | children = (
286 | 965BBCD85442586E700FFB28 /* Pods-SwipeToRevealExample.debug.xcconfig */,
287 | 1EBACFF15A65C0ED772D25B3 /* Pods-SwipeToRevealExample.release.xcconfig */,
288 | 5B4979947EEC3481468A09BD /* Pods-SwipeToRevealExampleTests.debug.xcconfig */,
289 | F736ACAA48911E20D6BD4B89 /* Pods-SwipeToRevealExampleTests.release.xcconfig */,
290 | 0598EC71861C2CB0F06509AC /* Pods-SwipeToRevealTests.debug.xcconfig */,
291 | E08F4E7EEFE7CC457E74E83D /* Pods-SwipeToRevealTests.release.xcconfig */,
292 | );
293 | name = Pods;
294 | sourceTree = "";
295 | };
296 | C69363D1A96F41166FC06D26 /* Frameworks */ = {
297 | isa = PBXGroup;
298 | children = (
299 | 53EFD90C736845F0F5D16D61 /* Pods_SwipeToRevealExample.framework */,
300 | 42DF1915B99875D21FA7B4DA /* Pods_SwipeToRevealExampleTests.framework */,
301 | 2AE8394623A061A1D76EEDCF /* Pods_SwipeToRevealTests.framework */,
302 | );
303 | name = Frameworks;
304 | sourceTree = "";
305 | };
306 | /* End PBXGroup section */
307 |
308 | /* Begin PBXNativeTarget section */
309 | 314A55891E48E1CC00DD410B /* SwipeToRevealExample */ = {
310 | isa = PBXNativeTarget;
311 | buildConfigurationList = 314A559C1E48E1CC00DD410B /* Build configuration list for PBXNativeTarget "SwipeToRevealExample" */;
312 | buildPhases = (
313 | AA4CD1C2AB847AF1BB96EF69 /* [CP] Check Pods Manifest.lock */,
314 | 318C5D7F1E49258900F41A97 /* SwiftLint */,
315 | 314A55861E48E1CC00DD410B /* Sources */,
316 | 314A55871E48E1CC00DD410B /* Frameworks */,
317 | 314A55881E48E1CC00DD410B /* Resources */,
318 | C262E636F62C6644F88B968D /* [CP] Embed Pods Frameworks */,
319 | 0F88EC1106ADB641B578B551 /* [CP] Copy Pods Resources */,
320 | );
321 | buildRules = (
322 | );
323 | dependencies = (
324 | );
325 | name = SwipeToRevealExample;
326 | productName = SwipeToReveal;
327 | productReference = 314A558A1E48E1CC00DD410B /* SwipeToRevealExample.app */;
328 | productType = "com.apple.product-type.application";
329 | };
330 | 318DD16C1E5CDA9100F1A091 /* SwipeToRevealTests */ = {
331 | isa = PBXNativeTarget;
332 | buildConfigurationList = 318DD1741E5CDA9100F1A091 /* Build configuration list for PBXNativeTarget "SwipeToRevealTests" */;
333 | buildPhases = (
334 | 9EB6C548AD7FC88BBCF43864 /* [CP] Check Pods Manifest.lock */,
335 | 318DD1691E5CDA9100F1A091 /* Sources */,
336 | 318DD16A1E5CDA9100F1A091 /* Frameworks */,
337 | 318DD16B1E5CDA9100F1A091 /* Resources */,
338 | B0F66F529111FE74320D711D /* [CP] Embed Pods Frameworks */,
339 | 2E2916B0D5B5F1D23A0CA30E /* [CP] Copy Pods Resources */,
340 | );
341 | buildRules = (
342 | );
343 | dependencies = (
344 | );
345 | name = SwipeToRevealTests;
346 | productName = SwipeToRevealTests;
347 | productReference = 318DD16D1E5CDA9100F1A091 /* SwipeToRevealTests.xctest */;
348 | productType = "com.apple.product-type.bundle.unit-test";
349 | };
350 | 31A0768D1E57C48A00D82BD7 /* SwipeToRevealExampleTests */ = {
351 | isa = PBXNativeTarget;
352 | buildConfigurationList = 31A076931E57C48A00D82BD7 /* Build configuration list for PBXNativeTarget "SwipeToRevealExampleTests" */;
353 | buildPhases = (
354 | 99A4A0FB20A5163EC2AC6A82 /* [CP] Check Pods Manifest.lock */,
355 | 318EB7F41E5A54DE0072426E /* SwiftLint */,
356 | 31A0768A1E57C48A00D82BD7 /* Sources */,
357 | 31A0768B1E57C48A00D82BD7 /* Frameworks */,
358 | 31A0768C1E57C48A00D82BD7 /* Resources */,
359 | 2C205B5580F89473F535612E /* [CP] Embed Pods Frameworks */,
360 | EF924DFD64A744014DBA68DD /* [CP] Copy Pods Resources */,
361 | );
362 | buildRules = (
363 | );
364 | dependencies = (
365 | 31A076A01E57C8D900D82BD7 /* PBXTargetDependency */,
366 | );
367 | name = SwipeToRevealExampleTests;
368 | productName = SwipeToRevealExampleTests;
369 | productReference = 31A0768E1E57C48A00D82BD7 /* SwipeToRevealExampleTests.xctest */;
370 | productType = "com.apple.product-type.bundle.unit-test";
371 | };
372 | /* End PBXNativeTarget section */
373 |
374 | /* Begin PBXProject section */
375 | 314A55821E48E1CC00DD410B /* Project object */ = {
376 | isa = PBXProject;
377 | attributes = {
378 | LastSwiftUpdateCheck = 0820;
379 | LastUpgradeCheck = 0820;
380 | ORGANIZATIONNAME = Darrarski;
381 | TargetAttributes = {
382 | 314A55891E48E1CC00DD410B = {
383 | CreatedOnToolsVersion = 8.2.1;
384 | ProvisioningStyle = Manual;
385 | };
386 | 318DD16C1E5CDA9100F1A091 = {
387 | CreatedOnToolsVersion = 8.2.1;
388 | ProvisioningStyle = Manual;
389 | };
390 | 31A0768D1E57C48A00D82BD7 = {
391 | CreatedOnToolsVersion = 8.2.1;
392 | ProvisioningStyle = Manual;
393 | TestTargetID = 314A55891E48E1CC00DD410B;
394 | };
395 | };
396 | };
397 | buildConfigurationList = 314A55851E48E1CC00DD410B /* Build configuration list for PBXProject "SwipeToReveal" */;
398 | compatibilityVersion = "Xcode 3.2";
399 | developmentRegion = English;
400 | hasScannedForEncodings = 0;
401 | knownRegions = (
402 | en,
403 | Base,
404 | );
405 | mainGroup = 314A55811E48E1CC00DD410B;
406 | productRefGroup = 314A558B1E48E1CC00DD410B /* Products */;
407 | projectDirPath = "";
408 | projectRoot = "";
409 | targets = (
410 | 314A55891E48E1CC00DD410B /* SwipeToRevealExample */,
411 | 31A0768D1E57C48A00D82BD7 /* SwipeToRevealExampleTests */,
412 | 318DD16C1E5CDA9100F1A091 /* SwipeToRevealTests */,
413 | );
414 | };
415 | /* End PBXProject section */
416 |
417 | /* Begin PBXResourcesBuildPhase section */
418 | 314A55881E48E1CC00DD410B /* Resources */ = {
419 | isa = PBXResourcesBuildPhase;
420 | buildActionMask = 2147483647;
421 | files = (
422 | 314A55981E48E1CC00DD410B /* LaunchScreen.storyboard in Resources */,
423 | 314A55951E48E1CC00DD410B /* Assets.xcassets in Resources */,
424 | );
425 | runOnlyForDeploymentPostprocessing = 0;
426 | };
427 | 318DD16B1E5CDA9100F1A091 /* Resources */ = {
428 | isa = PBXResourcesBuildPhase;
429 | buildActionMask = 2147483647;
430 | files = (
431 | );
432 | runOnlyForDeploymentPostprocessing = 0;
433 | };
434 | 31A0768C1E57C48A00D82BD7 /* Resources */ = {
435 | isa = PBXResourcesBuildPhase;
436 | buildActionMask = 2147483647;
437 | files = (
438 | );
439 | runOnlyForDeploymentPostprocessing = 0;
440 | };
441 | /* End PBXResourcesBuildPhase section */
442 |
443 | /* Begin PBXShellScriptBuildPhase section */
444 | 0F88EC1106ADB641B578B551 /* [CP] Copy Pods Resources */ = {
445 | isa = PBXShellScriptBuildPhase;
446 | buildActionMask = 2147483647;
447 | files = (
448 | );
449 | inputPaths = (
450 | );
451 | name = "[CP] Copy Pods Resources";
452 | outputPaths = (
453 | );
454 | runOnlyForDeploymentPostprocessing = 0;
455 | shellPath = /bin/sh;
456 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealExample/Pods-SwipeToRevealExample-resources.sh\"\n";
457 | showEnvVarsInLog = 0;
458 | };
459 | 2C205B5580F89473F535612E /* [CP] Embed Pods Frameworks */ = {
460 | isa = PBXShellScriptBuildPhase;
461 | buildActionMask = 2147483647;
462 | files = (
463 | );
464 | inputPaths = (
465 | );
466 | name = "[CP] Embed Pods Frameworks";
467 | outputPaths = (
468 | );
469 | runOnlyForDeploymentPostprocessing = 0;
470 | shellPath = /bin/sh;
471 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealExampleTests/Pods-SwipeToRevealExampleTests-frameworks.sh\"\n";
472 | showEnvVarsInLog = 0;
473 | };
474 | 2E2916B0D5B5F1D23A0CA30E /* [CP] Copy Pods Resources */ = {
475 | isa = PBXShellScriptBuildPhase;
476 | buildActionMask = 2147483647;
477 | files = (
478 | );
479 | inputPaths = (
480 | );
481 | name = "[CP] Copy Pods Resources";
482 | outputPaths = (
483 | );
484 | runOnlyForDeploymentPostprocessing = 0;
485 | shellPath = /bin/sh;
486 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealTests/Pods-SwipeToRevealTests-resources.sh\"\n";
487 | showEnvVarsInLog = 0;
488 | };
489 | 318C5D7F1E49258900F41A97 /* SwiftLint */ = {
490 | isa = PBXShellScriptBuildPhase;
491 | buildActionMask = 2147483647;
492 | files = (
493 | );
494 | inputPaths = (
495 | );
496 | name = SwiftLint;
497 | outputPaths = (
498 | );
499 | runOnlyForDeploymentPostprocessing = 0;
500 | shellPath = /bin/sh;
501 | shellScript = "cd Example/; ${PODS_ROOT}/SwiftLint/swiftlint";
502 | };
503 | 318EB7F41E5A54DE0072426E /* SwiftLint */ = {
504 | isa = PBXShellScriptBuildPhase;
505 | buildActionMask = 2147483647;
506 | files = (
507 | );
508 | inputPaths = (
509 | );
510 | name = SwiftLint;
511 | outputPaths = (
512 | );
513 | runOnlyForDeploymentPostprocessing = 0;
514 | shellPath = /bin/sh;
515 | shellScript = "cd ExampleTests/; ${PODS_ROOT}/SwiftLint/swiftlint";
516 | };
517 | 99A4A0FB20A5163EC2AC6A82 /* [CP] Check Pods Manifest.lock */ = {
518 | isa = PBXShellScriptBuildPhase;
519 | buildActionMask = 2147483647;
520 | files = (
521 | );
522 | inputPaths = (
523 | );
524 | name = "[CP] Check Pods Manifest.lock";
525 | outputPaths = (
526 | );
527 | runOnlyForDeploymentPostprocessing = 0;
528 | shellPath = /bin/sh;
529 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
530 | showEnvVarsInLog = 0;
531 | };
532 | 9EB6C548AD7FC88BBCF43864 /* [CP] Check Pods Manifest.lock */ = {
533 | isa = PBXShellScriptBuildPhase;
534 | buildActionMask = 2147483647;
535 | files = (
536 | );
537 | inputPaths = (
538 | );
539 | name = "[CP] Check Pods Manifest.lock";
540 | outputPaths = (
541 | );
542 | runOnlyForDeploymentPostprocessing = 0;
543 | shellPath = /bin/sh;
544 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
545 | showEnvVarsInLog = 0;
546 | };
547 | AA4CD1C2AB847AF1BB96EF69 /* [CP] Check Pods Manifest.lock */ = {
548 | isa = PBXShellScriptBuildPhase;
549 | buildActionMask = 2147483647;
550 | files = (
551 | );
552 | inputPaths = (
553 | );
554 | name = "[CP] Check Pods Manifest.lock";
555 | outputPaths = (
556 | );
557 | runOnlyForDeploymentPostprocessing = 0;
558 | shellPath = /bin/sh;
559 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
560 | showEnvVarsInLog = 0;
561 | };
562 | B0F66F529111FE74320D711D /* [CP] Embed Pods Frameworks */ = {
563 | isa = PBXShellScriptBuildPhase;
564 | buildActionMask = 2147483647;
565 | files = (
566 | );
567 | inputPaths = (
568 | );
569 | name = "[CP] Embed Pods Frameworks";
570 | outputPaths = (
571 | );
572 | runOnlyForDeploymentPostprocessing = 0;
573 | shellPath = /bin/sh;
574 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealTests/Pods-SwipeToRevealTests-frameworks.sh\"\n";
575 | showEnvVarsInLog = 0;
576 | };
577 | C262E636F62C6644F88B968D /* [CP] Embed Pods Frameworks */ = {
578 | isa = PBXShellScriptBuildPhase;
579 | buildActionMask = 2147483647;
580 | files = (
581 | );
582 | inputPaths = (
583 | );
584 | name = "[CP] Embed Pods Frameworks";
585 | outputPaths = (
586 | );
587 | runOnlyForDeploymentPostprocessing = 0;
588 | shellPath = /bin/sh;
589 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealExample/Pods-SwipeToRevealExample-frameworks.sh\"\n";
590 | showEnvVarsInLog = 0;
591 | };
592 | EF924DFD64A744014DBA68DD /* [CP] Copy Pods Resources */ = {
593 | isa = PBXShellScriptBuildPhase;
594 | buildActionMask = 2147483647;
595 | files = (
596 | );
597 | inputPaths = (
598 | );
599 | name = "[CP] Copy Pods Resources";
600 | outputPaths = (
601 | );
602 | runOnlyForDeploymentPostprocessing = 0;
603 | shellPath = /bin/sh;
604 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwipeToRevealExampleTests/Pods-SwipeToRevealExampleTests-resources.sh\"\n";
605 | showEnvVarsInLog = 0;
606 | };
607 | /* End PBXShellScriptBuildPhase section */
608 |
609 | /* Begin PBXSourcesBuildPhase section */
610 | 314A55861E48E1CC00DD410B /* Sources */ = {
611 | isa = PBXSourcesBuildPhase;
612 | buildActionMask = 2147483647;
613 | files = (
614 | 314A55901E48E1CC00DD410B /* TableExampleViewController.swift in Sources */,
615 | 31A076891E57C33B00D82BD7 /* Container_AppDelegateAssembly.swift in Sources */,
616 | 318EB7F11E5A44F60072426E /* MainMenuViewModel.swift in Sources */,
617 | 314A558E1E48E1CC00DD410B /* AppDelegate.swift in Sources */,
618 | 31A076871E57C31500D82BD7 /* AppDelegateAssembly.swift in Sources */,
619 | 31A076AF1E57D28000D82BD7 /* MenuViewController.swift in Sources */,
620 | 318EB7F31E5A453D0072426E /* MainMenuItemViewModel.swift in Sources */,
621 | 31A076AA1E57CEB200D82BD7 /* Container_TableExampleAssembly.swift in Sources */,
622 | 31A076B11E57D29000D82BD7 /* Container_MenuAssembly.swift in Sources */,
623 | 31A076851E57C2FB00D82BD7 /* Container.swift in Sources */,
624 | 318EB7EF1E5A44AA0072426E /* MenuItemViewModel.swift in Sources */,
625 | 31A076AD1E57D27700D82BD7 /* MenuAssembly.swift in Sources */,
626 | 31A076A81E57CEA400D82BD7 /* TableExampleAssembly.swift in Sources */,
627 | 318EB7ED1E5A44610072426E /* MenuViewModel.swift in Sources */,
628 | 314A55A31E48E8BA00DD410B /* TableExampleCell.swift in Sources */,
629 | );
630 | runOnlyForDeploymentPostprocessing = 0;
631 | };
632 | 318DD1691E5CDA9100F1A091 /* Sources */ = {
633 | isa = PBXSourcesBuildPhase;
634 | buildActionMask = 2147483647;
635 | files = (
636 | 318DD17B1E5D07F600F1A091 /* SwipeToRevealViewSpec.swift in Sources */,
637 | );
638 | runOnlyForDeploymentPostprocessing = 0;
639 | };
640 | 31A0768A1E57C48A00D82BD7 /* Sources */ = {
641 | isa = PBXSourcesBuildPhase;
642 | buildActionMask = 2147483647;
643 | files = (
644 | 31D017871E5BB15800F89A35 /* TableExampleViewControllerSpec.swift in Sources */,
645 | 315BBE071E5BA976006148B7 /* NavigationControllerSpy.swift in Sources */,
646 | 31A076981E57C6E100D82BD7 /* AppDelegateSpec.swift in Sources */,
647 | 318EB7EB1E5A43D70072426E /* MenuViewControllerSpec.swift in Sources */,
648 | 31D0178A1E5BB76300F89A35 /* TableExampleCellSpec.swift in Sources */,
649 | 31A076A31E57CD8A00D82BD7 /* WindowSpy.swift in Sources */,
650 | 311714D81E5A6B640029A012 /* MainMenuItemViewModelSpec.swift in Sources */,
651 | 311714DB1E5A6D5C0029A012 /* MainMenuViewModelSpec.swift in Sources */,
652 | );
653 | runOnlyForDeploymentPostprocessing = 0;
654 | };
655 | /* End PBXSourcesBuildPhase section */
656 |
657 | /* Begin PBXTargetDependency section */
658 | 31A076A01E57C8D900D82BD7 /* PBXTargetDependency */ = {
659 | isa = PBXTargetDependency;
660 | target = 314A55891E48E1CC00DD410B /* SwipeToRevealExample */;
661 | targetProxy = 31A0769F1E57C8D900D82BD7 /* PBXContainerItemProxy */;
662 | };
663 | /* End PBXTargetDependency section */
664 |
665 | /* Begin PBXVariantGroup section */
666 | 314A55961E48E1CC00DD410B /* LaunchScreen.storyboard */ = {
667 | isa = PBXVariantGroup;
668 | children = (
669 | 314A55971E48E1CC00DD410B /* Base */,
670 | );
671 | name = LaunchScreen.storyboard;
672 | path = .;
673 | sourceTree = "";
674 | };
675 | /* End PBXVariantGroup section */
676 |
677 | /* Begin XCBuildConfiguration section */
678 | 314A559A1E48E1CC00DD410B /* Debug */ = {
679 | isa = XCBuildConfiguration;
680 | buildSettings = {
681 | ALWAYS_SEARCH_USER_PATHS = NO;
682 | CLANG_ANALYZER_NONNULL = YES;
683 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
684 | CLANG_CXX_LIBRARY = "libc++";
685 | CLANG_ENABLE_MODULES = YES;
686 | CLANG_ENABLE_OBJC_ARC = YES;
687 | CLANG_WARN_BOOL_CONVERSION = YES;
688 | CLANG_WARN_CONSTANT_CONVERSION = YES;
689 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
690 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
691 | CLANG_WARN_EMPTY_BODY = YES;
692 | CLANG_WARN_ENUM_CONVERSION = YES;
693 | CLANG_WARN_INFINITE_RECURSION = YES;
694 | CLANG_WARN_INT_CONVERSION = YES;
695 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
696 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
697 | CLANG_WARN_UNREACHABLE_CODE = YES;
698 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
699 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
700 | COPY_PHASE_STRIP = NO;
701 | DEBUG_INFORMATION_FORMAT = dwarf;
702 | ENABLE_STRICT_OBJC_MSGSEND = YES;
703 | ENABLE_TESTABILITY = YES;
704 | GCC_C_LANGUAGE_STANDARD = gnu99;
705 | GCC_DYNAMIC_NO_PIC = NO;
706 | GCC_NO_COMMON_BLOCKS = YES;
707 | GCC_OPTIMIZATION_LEVEL = 0;
708 | GCC_PREPROCESSOR_DEFINITIONS = (
709 | "DEBUG=1",
710 | "$(inherited)",
711 | );
712 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
713 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
714 | GCC_WARN_UNDECLARED_SELECTOR = YES;
715 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
716 | GCC_WARN_UNUSED_FUNCTION = YES;
717 | GCC_WARN_UNUSED_VARIABLE = YES;
718 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
719 | MTL_ENABLE_DEBUG_INFO = YES;
720 | ONLY_ACTIVE_ARCH = YES;
721 | OTHER_SWIFT_FLAGS = "-Onone -Xfrontend -debug-time-function-bodies";
722 | SDKROOT = iphoneos;
723 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
724 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
725 | };
726 | name = Debug;
727 | };
728 | 314A559B1E48E1CC00DD410B /* Release */ = {
729 | isa = XCBuildConfiguration;
730 | buildSettings = {
731 | ALWAYS_SEARCH_USER_PATHS = NO;
732 | CLANG_ANALYZER_NONNULL = YES;
733 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
734 | CLANG_CXX_LIBRARY = "libc++";
735 | CLANG_ENABLE_MODULES = YES;
736 | CLANG_ENABLE_OBJC_ARC = YES;
737 | CLANG_WARN_BOOL_CONVERSION = YES;
738 | CLANG_WARN_CONSTANT_CONVERSION = YES;
739 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
740 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
741 | CLANG_WARN_EMPTY_BODY = YES;
742 | CLANG_WARN_ENUM_CONVERSION = YES;
743 | CLANG_WARN_INFINITE_RECURSION = YES;
744 | CLANG_WARN_INT_CONVERSION = YES;
745 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
746 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
747 | CLANG_WARN_UNREACHABLE_CODE = YES;
748 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
749 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
750 | COPY_PHASE_STRIP = NO;
751 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
752 | ENABLE_NS_ASSERTIONS = NO;
753 | ENABLE_STRICT_OBJC_MSGSEND = YES;
754 | GCC_C_LANGUAGE_STANDARD = gnu99;
755 | GCC_NO_COMMON_BLOCKS = YES;
756 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
757 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
758 | GCC_WARN_UNDECLARED_SELECTOR = YES;
759 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
760 | GCC_WARN_UNUSED_FUNCTION = YES;
761 | GCC_WARN_UNUSED_VARIABLE = YES;
762 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
763 | MTL_ENABLE_DEBUG_INFO = NO;
764 | SDKROOT = iphoneos;
765 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
766 | VALIDATE_PRODUCT = YES;
767 | };
768 | name = Release;
769 | };
770 | 314A559D1E48E1CC00DD410B /* Debug */ = {
771 | isa = XCBuildConfiguration;
772 | baseConfigurationReference = 965BBCD85442586E700FFB28 /* Pods-SwipeToRevealExample.debug.xcconfig */;
773 | buildSettings = {
774 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
775 | DEVELOPMENT_TEAM = "";
776 | INFOPLIST_FILE = Example/Application/Info.plist;
777 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
778 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealExample;
779 | PRODUCT_NAME = "$(TARGET_NAME)";
780 | SWIFT_VERSION = 3.0;
781 | };
782 | name = Debug;
783 | };
784 | 314A559E1E48E1CC00DD410B /* Release */ = {
785 | isa = XCBuildConfiguration;
786 | baseConfigurationReference = 1EBACFF15A65C0ED772D25B3 /* Pods-SwipeToRevealExample.release.xcconfig */;
787 | buildSettings = {
788 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
789 | DEVELOPMENT_TEAM = "";
790 | INFOPLIST_FILE = Example/Application/Info.plist;
791 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
792 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealExample;
793 | PRODUCT_NAME = "$(TARGET_NAME)";
794 | SWIFT_VERSION = 3.0;
795 | };
796 | name = Release;
797 | };
798 | 318DD1721E5CDA9100F1A091 /* Debug */ = {
799 | isa = XCBuildConfiguration;
800 | baseConfigurationReference = 0598EC71861C2CB0F06509AC /* Pods-SwipeToRevealTests.debug.xcconfig */;
801 | buildSettings = {
802 | INFOPLIST_FILE = Tests/Info.plist;
803 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
804 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealTests;
805 | PRODUCT_NAME = "$(TARGET_NAME)";
806 | SWIFT_VERSION = 3.0;
807 | };
808 | name = Debug;
809 | };
810 | 318DD1731E5CDA9100F1A091 /* Release */ = {
811 | isa = XCBuildConfiguration;
812 | baseConfigurationReference = E08F4E7EEFE7CC457E74E83D /* Pods-SwipeToRevealTests.release.xcconfig */;
813 | buildSettings = {
814 | INFOPLIST_FILE = Tests/Info.plist;
815 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
816 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealTests;
817 | PRODUCT_NAME = "$(TARGET_NAME)";
818 | SWIFT_VERSION = 3.0;
819 | };
820 | name = Release;
821 | };
822 | 31A076941E57C48A00D82BD7 /* Debug */ = {
823 | isa = XCBuildConfiguration;
824 | baseConfigurationReference = 5B4979947EEC3481468A09BD /* Pods-SwipeToRevealExampleTests.debug.xcconfig */;
825 | buildSettings = {
826 | BUNDLE_LOADER = "$(TEST_HOST)";
827 | DEVELOPMENT_TEAM = "";
828 | INFOPLIST_FILE = ExampleTests/Info.plist;
829 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
830 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealExampleTests;
831 | PRODUCT_NAME = "$(TARGET_NAME)";
832 | SWIFT_VERSION = 3.0;
833 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwipeToRevealExample.app/SwipeToRevealExample";
834 | };
835 | name = Debug;
836 | };
837 | 31A076951E57C48A00D82BD7 /* Release */ = {
838 | isa = XCBuildConfiguration;
839 | baseConfigurationReference = F736ACAA48911E20D6BD4B89 /* Pods-SwipeToRevealExampleTests.release.xcconfig */;
840 | buildSettings = {
841 | BUNDLE_LOADER = "$(TEST_HOST)";
842 | DEVELOPMENT_TEAM = "";
843 | INFOPLIST_FILE = ExampleTests/Info.plist;
844 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
845 | PRODUCT_BUNDLE_IDENTIFIER = pl.darrarski.SwipeToRevealExampleTests;
846 | PRODUCT_NAME = "$(TARGET_NAME)";
847 | SWIFT_VERSION = 3.0;
848 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwipeToRevealExample.app/SwipeToRevealExample";
849 | };
850 | name = Release;
851 | };
852 | /* End XCBuildConfiguration section */
853 |
854 | /* Begin XCConfigurationList section */
855 | 314A55851E48E1CC00DD410B /* Build configuration list for PBXProject "SwipeToReveal" */ = {
856 | isa = XCConfigurationList;
857 | buildConfigurations = (
858 | 314A559A1E48E1CC00DD410B /* Debug */,
859 | 314A559B1E48E1CC00DD410B /* Release */,
860 | );
861 | defaultConfigurationIsVisible = 0;
862 | defaultConfigurationName = Release;
863 | };
864 | 314A559C1E48E1CC00DD410B /* Build configuration list for PBXNativeTarget "SwipeToRevealExample" */ = {
865 | isa = XCConfigurationList;
866 | buildConfigurations = (
867 | 314A559D1E48E1CC00DD410B /* Debug */,
868 | 314A559E1E48E1CC00DD410B /* Release */,
869 | );
870 | defaultConfigurationIsVisible = 0;
871 | defaultConfigurationName = Release;
872 | };
873 | 318DD1741E5CDA9100F1A091 /* Build configuration list for PBXNativeTarget "SwipeToRevealTests" */ = {
874 | isa = XCConfigurationList;
875 | buildConfigurations = (
876 | 318DD1721E5CDA9100F1A091 /* Debug */,
877 | 318DD1731E5CDA9100F1A091 /* Release */,
878 | );
879 | defaultConfigurationIsVisible = 0;
880 | defaultConfigurationName = Release;
881 | };
882 | 31A076931E57C48A00D82BD7 /* Build configuration list for PBXNativeTarget "SwipeToRevealExampleTests" */ = {
883 | isa = XCConfigurationList;
884 | buildConfigurations = (
885 | 31A076941E57C48A00D82BD7 /* Debug */,
886 | 31A076951E57C48A00D82BD7 /* Release */,
887 | );
888 | defaultConfigurationIsVisible = 0;
889 | defaultConfigurationName = Release;
890 | };
891 | /* End XCConfigurationList section */
892 | };
893 | rootObject = 314A55821E48E1CC00DD410B /* Project object */;
894 | }
895 |
--------------------------------------------------------------------------------
/SwipeToReveal.xcodeproj/xcshareddata/xcschemes/SwipeToReveal Example Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
104 |
105 |
106 |
107 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/SwipeToReveal.xcodeproj/xcshareddata/xcschemes/SwipeToReveal Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/SwipeToReveal.xcodeproj/xcshareddata/xcschemes/SwipeToReveal Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
16 |
18 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
40 |
41 |
42 |
43 |
49 |
50 |
52 |
53 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/SwipeToReveal.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/SwipeToRevealViewSpec.swift:
--------------------------------------------------------------------------------
1 | import Quick
2 | import Nimble
3 | import SwipeToReveal
4 |
5 | class SwipeToRevealViewSpec: QuickSpec {
6 |
7 | override func spec() {
8 | context("init with coder") {
9 | it("should throw asserion") {
10 | expect { () -> Void in _ = SwipeToRevealView(coder: NSCoder()) }.to(throwAssertion())
11 | }
12 | }
13 |
14 | context("init") {
15 | var sut: SwipeToRevealView!
16 | var size: CGSize!
17 |
18 | beforeEach {
19 | size = CGSize(width: 100, height: 20)
20 | sut = SwipeToRevealView(frame: .zero)
21 | sut.translatesAutoresizingMaskIntoConstraints = false
22 | sut.widthAnchor.constraint(equalToConstant: size.width).isActive = true
23 | sut.heightAnchor.constraint(equalToConstant: size.height).isActive = true
24 | sut.setNeedsLayout()
25 | sut.layoutIfNeeded()
26 | }
27 |
28 | it("should not have content view") {
29 | expect(sut.contentView).to(beNil())
30 | }
31 |
32 | it("should not have right view") {
33 | expect(sut.rightView).to(beNil())
34 | }
35 |
36 | it("should have correct size") {
37 | expect(sut.frame.size).to(equal(size))
38 | }
39 |
40 | context("set content view") {
41 | var contentView: UIView!
42 |
43 | beforeEach {
44 | contentView = UIView(frame: .zero)
45 | sut.contentView = contentView
46 | sut.setNeedsLayout()
47 | sut.layoutIfNeeded()
48 | }
49 |
50 | it("should have correct content view") {
51 | expect(sut.contentView).to(be(contentView))
52 | }
53 |
54 | it("should content view have superview") {
55 | expect(contentView.superview).notTo(beNil())
56 | }
57 |
58 | it("should content view have correct size") {
59 | expect(contentView.frame.size).to(equal(sut.frame.size))
60 | }
61 |
62 | it("should content view have correct origin") {
63 | let origin = contentView.convert(contentView.frame.origin, to: sut)
64 | expect(origin).to(equal(CGPoint.zero))
65 | }
66 |
67 | context("change content view") {
68 | var newContentView: UIView!
69 |
70 | beforeEach {
71 | newContentView = UIView(frame: .zero)
72 | sut.contentView = newContentView
73 | sut.setNeedsLayout()
74 | sut.layoutIfNeeded()
75 | }
76 |
77 | it("should have correct content view") {
78 | expect(sut.contentView).to(be(newContentView))
79 | }
80 |
81 | it("should new content view have superview") {
82 | expect(newContentView.superview).notTo(beNil())
83 | }
84 |
85 | it("should previous content view not have superview") {
86 | expect(contentView.superview).to(beNil())
87 | }
88 | }
89 |
90 | context("set right view") {
91 | var rightView: UIView!
92 | var rightViewWidth: CGFloat!
93 |
94 | beforeEach {
95 | rightViewWidth = 30
96 | rightView = UIView(frame: .zero)
97 | rightView.translatesAutoresizingMaskIntoConstraints = false
98 | rightView.widthAnchor.constraint(equalToConstant: rightViewWidth).isActive = true
99 | sut.rightView = rightView
100 | sut.setNeedsLayout()
101 | sut.layoutIfNeeded()
102 | }
103 |
104 | it("should have correct right view") {
105 | expect(sut.rightView).to(be(rightView))
106 | }
107 |
108 | it("should right view have superview") {
109 | expect(rightView.superview).notTo(beNil())
110 | }
111 |
112 | it("should right view have correct size") {
113 | expect(rightView.frame.width).to(equal(rightViewWidth))
114 | expect(rightView.frame.height).to(equal(sut.bounds.height))
115 | }
116 |
117 | it("should right view have correct origin") {
118 | let origin = rightView.convert(rightView.frame.origin, to: sut)
119 | let expectation = CGPoint(x: sut.bounds.maxX, y: sut.bounds.minY)
120 | expect(origin).to(equal(expectation))
121 | }
122 |
123 | context("change right view") {
124 | var newRightView: UIView!
125 |
126 | beforeEach {
127 | newRightView = UIView(frame: .zero)
128 | sut.rightView = newRightView
129 | sut.setNeedsLayout()
130 | sut.layoutIfNeeded()
131 | }
132 |
133 | it("should have correct right view") {
134 | expect(sut.rightView).to(be(newRightView))
135 | }
136 |
137 | it("should new right view have superview") {
138 | expect(newRightView.superview).notTo(beNil())
139 | }
140 |
141 | it("should previous right view not have superview") {
142 | expect(rightView.superview).to(beNil())
143 | }
144 | }
145 |
146 | context("reveal right") {
147 | beforeEach {
148 | sut.revealRight(animated: false)
149 | sut.setNeedsLayout()
150 | sut.layoutIfNeeded()
151 | }
152 |
153 | it("should right view have correct size") {
154 | expect(rightView.frame.width).to(equal(rightViewWidth))
155 | expect(rightView.frame.height).to(equal(sut.bounds.height))
156 | }
157 |
158 | it("should right view have correct origin") {
159 | let origin = rightView.convert(rightView.frame.origin, to: sut)
160 | let expectation = CGPoint(
161 | x: sut.bounds.maxX - rightView.frame.width,
162 | y: sut.bounds.minY
163 | )
164 | expect(origin).to(equal(expectation))
165 | }
166 |
167 | context("close") {
168 | beforeEach {
169 | sut.close(animated: false)
170 | sut.setNeedsLayout()
171 | sut.layoutIfNeeded()
172 | }
173 |
174 | it("should right view have correct size") {
175 | expect(rightView.frame.width).to(equal(rightViewWidth))
176 | expect(rightView.frame.height).to(equal(sut.bounds.height))
177 | }
178 |
179 | it("should right view have correct origin") {
180 | let origin = rightView.convert(rightView.frame.origin, to: sut)
181 | let expectation = CGPoint(x: sut.bounds.maxX, y: sut.bounds.minY)
182 | expect(origin).to(equal(expectation))
183 | }
184 | }
185 | }
186 | }
187 | }
188 | }
189 | }
190 |
191 | }
192 |
--------------------------------------------------------------------------------