├── .gitignore
├── .travis.yml
├── Cartfile
├── Cartfile.resolved
├── Carthage.xcconfig
├── Info.plist
├── LICENSE
├── PMKUIKit.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ └── PMKUIKit.xcscheme
├── Package.resolved
├── Package.swift
├── README.markdown
├── Sources
├── PMKUIKit.h
├── UIImagePickerController+Promise.swift
├── UIView+AnyPromise.h
├── UIView+AnyPromise.m
├── UIView+Promise.swift
├── UIViewController+AnyPromise.h
├── UIViewController+AnyPromise.m
└── UIViewPropertyAnimator+Promise.swift
├── Tests
├── TestUIImagePickerController.swift
├── TestUIView.swift
├── TestUIViewController.m
└── infrastructure.swift
└── UITests
├── Default-568h@2x.png
├── Entitlements.plist
├── TestUIImagePickerController.swift
└── app.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | *.xcodeproj/**/xcuserdata/
2 | *.xcscmblueprint
3 | /Carthage
4 | /.build
5 | .DS_Store
6 | .swiftpm/
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os: osx
2 | language: swift
3 | osx_image: xcode10.2
4 |
5 | branches:
6 | only:
7 | - master
8 | stages:
9 | - lint
10 | - carthage
11 | - test
12 | jobs:
13 | include:
14 | - &pod
15 | stage: lint
16 | osx_image: xcode8.3
17 | env: SWIFT=3.1
18 | before_install:
19 | gem install cocoapods --prerelease --version 1.7.0.beta.3
20 | install:
21 | carthage bootstrap --no-build PromiseKit
22 | script: |
23 | cd Carthage/Checkouts/PromiseKit
24 | mv .github/PromiseKit.podspec .
25 | rm -rf Extensions/UIKit/Sources
26 | cp -R ../../../Sources Extensions/UIKit
27 | pod lib lint --subspec=PromiseKit/UIKit --fail-fast --swift-version=$SWIFT
28 | - <<: *pod
29 | osx_image: xcode9.2
30 | env: SWIFT=3.2
31 | - <<: *pod
32 | osx_image: xcode9.4
33 | env: SWIFT=3.3
34 | - <<: *pod
35 | osx_image: xcode10.1
36 | env: SWIFT=3.4
37 | - <<: *pod
38 | osx_image: xcode9.2
39 | env: SWIFT=4.0
40 | - <<: *pod
41 | osx_image: xcode9.4
42 | env: SWIFT=4.1
43 | - <<: *pod
44 | osx_image: xcode10.1
45 | env: SWIFT=4.2
46 | - <<: *pod
47 | osx_image: xcode10.2
48 | env: SWIFT=5.0
49 |
50 | - &carthage
51 | stage: carthage
52 | osx_image: xcode9.2
53 | script: |
54 | carthage bootstrap --cache-builds
55 | sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj
56 | carthage build --no-skip-current
57 | cache:
58 | directories:
59 | - Carthage
60 | - <<: *carthage
61 | osx_image: xcode9.4
62 | - <<: *carthage
63 | osx_image: xcode10.1
64 | - <<: *carthage
65 | osx_image: xcode10.2
66 |
67 | - &test
68 | stage: test
69 | xcode_scheme: PMKUIKit
70 | xcode_project: PMKUIKit.xcodeproj
71 | xcode_destination: 'platform=iOS Simulator,OS=12.2,name=iPhone SE'
72 | cache:
73 | directories:
74 | - Carthage
75 | before_install:
76 | carthage bootstrap --cache-builds --no-use-binaries
77 | - <<: *test
78 | xcode_destination: 'platform=tvOS Simulator,OS=12.2,name=Apple TV'
79 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "mxcl/PromiseKit" ~> 8.2.0
2 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "mxcl/PromiseKit" "8.2.0"
2 |
--------------------------------------------------------------------------------
/Carthage.xcconfig:
--------------------------------------------------------------------------------
1 | // Created by Kevin Ballard on 12/14/15.
2 | // Copyright © 2015 Postmates. All rights reserved.
3 |
4 | FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SRCROOT)/Carthage/Build/Mac/ $(inherited)
5 | FRAMEWORK_SEARCH_PATHS[sdk=iphone*] = $(SRCROOT)/Carthage/Build/iOS/ $(inherited)
6 | FRAMEWORK_SEARCH_PATHS[sdk=watch*] = $(SRCROOT)/Carthage/Build/watchOS/ $(inherited)
7 | FRAMEWORK_SEARCH_PATHS[sdk=appletv*] = $(SRCROOT)/Carthage/Build/tvOS/ $(inherited)
8 |
--------------------------------------------------------------------------------
/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 | $(BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016-present, Max Howell; mxcl@me.com
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included
12 | in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/PMKUIKit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6304D6FE1D5F986A00CE6C99 /* PMKUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6304D6FD1D5F986A00CE6C99 /* PMKUIKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 630B2E161D5D0B3200DC10E9 /* TestUIImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 630B2DF71D5D0AD400DC10E9 /* TestUIImagePickerController.swift */; };
12 | 632B573520324C4C00FCD5E1 /* UIViewPropertyAnimator+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 632B573420324C4C00FCD5E1 /* UIViewPropertyAnimator+Promise.swift */; };
13 | 6332142B1D83CD17009F67CE /* TestUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6332142A1D83CD17009F67CE /* TestUIView.swift */; };
14 | 637E2C841D5C2E0B0043E370 /* UIView+AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 637E2C771D5C2E0B0043E370 /* UIView+AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
15 | 637E2C851D5C2E0B0043E370 /* UIView+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C781D5C2E0B0043E370 /* UIView+AnyPromise.m */; };
16 | 637E2C861D5C2E0B0043E370 /* UIView+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C791D5C2E0B0043E370 /* UIView+Promise.swift */; };
17 | 637E2C871D5C2E0B0043E370 /* UIViewController+AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 637E2C7A1D5C2E0B0043E370 /* UIViewController+AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | 637E2C881D5C2E0B0043E370 /* UIViewController+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C7B1D5C2E0B0043E370 /* UIViewController+AnyPromise.m */; };
19 | 637E2C951D5C2E720043E370 /* TestUIImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C8E1D5C2E720043E370 /* TestUIImagePickerController.swift */; };
20 | 637E2C961D5C2E720043E370 /* TestUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C8F1D5C2E720043E370 /* TestUIViewController.m */; };
21 | 637E2C9B1D5C2F600043E370 /* infrastructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C9A1D5C2F600043E370 /* infrastructure.swift */; };
22 | 63A686811D88E93300D1C66B /* UIImagePickerController+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */; };
23 | 63C7FFF71D5C020D003BAE60 /* PMKUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; };
24 | 63C9C4571D5D339900101ECE /* app.swift in Sources */ = {isa = PBXBuildFile; fileRef = 630B2DF41D5D0AD400DC10E9 /* app.swift */; };
25 | 63C9C4581D5D339B00101ECE /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 630B2DF51D5D0AD400DC10E9 /* Default-568h@2x.png */; };
26 | 63C9C45E1D5D341600101ECE /* PMKUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; };
27 | 63C9C45F1D5D341600101ECE /* PMKUIKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXContainerItemProxy section */
31 | 63C7FFF81D5C020D003BAE60 /* PBXContainerItemProxy */ = {
32 | isa = PBXContainerItemProxy;
33 | containerPortal = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
34 | proxyType = 1;
35 | remoteGlobalIDString = 63C7FFA61D5BEE09003BAE60;
36 | remoteInfo = PMKUIKit;
37 | };
38 | 63C9C4591D5D33A900101ECE /* PBXContainerItemProxy */ = {
39 | isa = PBXContainerItemProxy;
40 | containerPortal = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
41 | proxyType = 1;
42 | remoteGlobalIDString = 63C9C4441D5D334700101ECE;
43 | remoteInfo = PMKTestsHost;
44 | };
45 | 63C9C45B1D5D33AB00101ECE /* PBXContainerItemProxy */ = {
46 | isa = PBXContainerItemProxy;
47 | containerPortal = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
48 | proxyType = 1;
49 | remoteGlobalIDString = 63C9C4441D5D334700101ECE;
50 | remoteInfo = PMKTestsHost;
51 | };
52 | 63C9C4601D5D341600101ECE /* PBXContainerItemProxy */ = {
53 | isa = PBXContainerItemProxy;
54 | containerPortal = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
55 | proxyType = 1;
56 | remoteGlobalIDString = 63C7FFA61D5BEE09003BAE60;
57 | remoteInfo = PMKUIKit;
58 | };
59 | /* End PBXContainerItemProxy section */
60 |
61 | /* Begin PBXCopyFilesBuildPhase section */
62 | 63C9C4621D5D341600101ECE /* Embed Frameworks */ = {
63 | isa = PBXCopyFilesBuildPhase;
64 | buildActionMask = 2147483647;
65 | dstPath = "";
66 | dstSubfolderSpec = 10;
67 | files = (
68 | 63C9C45F1D5D341600101ECE /* PMKUIKit.framework in Embed Frameworks */,
69 | );
70 | name = "Embed Frameworks";
71 | runOnlyForDeploymentPostprocessing = 0;
72 | };
73 | /* End PBXCopyFilesBuildPhase section */
74 |
75 | /* Begin PBXFileReference section */
76 | 6304D6FD1D5F986A00CE6C99 /* PMKUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PMKUIKit.h; path = Sources/PMKUIKit.h; sourceTree = SOURCE_ROOT; };
77 | 630B2DF41D5D0AD400DC10E9 /* app.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = app.swift; path = UITests/app.swift; sourceTree = ""; };
78 | 630B2DF51D5D0AD400DC10E9 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Default-568h@2x.png"; path = "UITests/Default-568h@2x.png"; sourceTree = ""; };
79 | 630B2DF71D5D0AD400DC10E9 /* TestUIImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestUIImagePickerController.swift; path = UITests/TestUIImagePickerController.swift; sourceTree = ""; };
80 | 630B2E131D5D0AF500DC10E9 /* PMKUIUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKUIUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
81 | 632B573420324C4C00FCD5E1 /* UIViewPropertyAnimator+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewPropertyAnimator+Promise.swift"; sourceTree = ""; };
82 | 6332142A1D83CD17009F67CE /* TestUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestUIView.swift; path = Tests/TestUIView.swift; sourceTree = SOURCE_ROOT; };
83 | 637E2C771D5C2E0B0043E370 /* UIView+AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+AnyPromise.h"; path = "Sources/UIView+AnyPromise.h"; sourceTree = SOURCE_ROOT; };
84 | 637E2C781D5C2E0B0043E370 /* UIView+AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+AnyPromise.m"; path = "Sources/UIView+AnyPromise.m"; sourceTree = SOURCE_ROOT; };
85 | 637E2C791D5C2E0B0043E370 /* UIView+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Promise.swift"; path = "Sources/UIView+Promise.swift"; sourceTree = SOURCE_ROOT; };
86 | 637E2C7A1D5C2E0B0043E370 /* UIViewController+AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+AnyPromise.h"; path = "Sources/UIViewController+AnyPromise.h"; sourceTree = SOURCE_ROOT; };
87 | 637E2C7B1D5C2E0B0043E370 /* UIViewController+AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+AnyPromise.m"; path = "Sources/UIViewController+AnyPromise.m"; sourceTree = SOURCE_ROOT; };
88 | 637E2C8E1D5C2E720043E370 /* TestUIImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestUIImagePickerController.swift; path = Tests/TestUIImagePickerController.swift; sourceTree = SOURCE_ROOT; };
89 | 637E2C8F1D5C2E720043E370 /* TestUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TestUIViewController.m; path = Tests/TestUIViewController.m; sourceTree = SOURCE_ROOT; };
90 | 637E2C9A1D5C2F600043E370 /* infrastructure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = infrastructure.swift; path = Tests/infrastructure.swift; sourceTree = SOURCE_ROOT; };
91 | 63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImagePickerController+Promise.swift"; path = "Sources/UIImagePickerController+Promise.swift"; sourceTree = SOURCE_ROOT; };
92 | 63C700091D5C0253003BAE60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
93 | 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PMKUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
94 | 63C7FFF21D5C020D003BAE60 /* PMKUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
95 | 63C9C4451D5D334700101ECE /* PMKTestsHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PMKTestsHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
96 | 63CCF8121D5C0C4E00503216 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; };
97 | 63CCF8171D5C11B500503216 /* Carthage.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Carthage.xcconfig; sourceTree = ""; };
98 | /* End PBXFileReference section */
99 |
100 | /* Begin PBXFrameworksBuildPhase section */
101 | 630B2E0D1D5D0AF500DC10E9 /* Frameworks */ = {
102 | isa = PBXFrameworksBuildPhase;
103 | buildActionMask = 2147483647;
104 | files = (
105 | );
106 | runOnlyForDeploymentPostprocessing = 0;
107 | };
108 | 63C7FFA31D5BEE09003BAE60 /* Frameworks */ = {
109 | isa = PBXFrameworksBuildPhase;
110 | buildActionMask = 2147483647;
111 | files = (
112 | );
113 | runOnlyForDeploymentPostprocessing = 0;
114 | };
115 | 63C7FFEF1D5C020D003BAE60 /* Frameworks */ = {
116 | isa = PBXFrameworksBuildPhase;
117 | buildActionMask = 2147483647;
118 | files = (
119 | 63C7FFF71D5C020D003BAE60 /* PMKUIKit.framework in Frameworks */,
120 | );
121 | runOnlyForDeploymentPostprocessing = 0;
122 | };
123 | 63C9C4421D5D334700101ECE /* Frameworks */ = {
124 | isa = PBXFrameworksBuildPhase;
125 | buildActionMask = 2147483647;
126 | files = (
127 | 63C9C45E1D5D341600101ECE /* PMKUIKit.framework in Frameworks */,
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | /* End PBXFrameworksBuildPhase section */
132 |
133 | /* Begin PBXGroup section */
134 | 630B2DF31D5D0ABF00DC10E9 /* TestsHost */ = {
135 | isa = PBXGroup;
136 | children = (
137 | 630B2DF41D5D0AD400DC10E9 /* app.swift */,
138 | 630B2DF51D5D0AD400DC10E9 /* Default-568h@2x.png */,
139 | 630B2DF71D5D0AD400DC10E9 /* TestUIImagePickerController.swift */,
140 | );
141 | name = TestsHost;
142 | sourceTree = "";
143 | };
144 | 63C7FF9D1D5BEE09003BAE60 = {
145 | isa = PBXGroup;
146 | children = (
147 | 63C700091D5C0253003BAE60 /* Info.plist */,
148 | 63CCF8121D5C0C4E00503216 /* Cartfile */,
149 | 63CCF8171D5C11B500503216 /* Carthage.xcconfig */,
150 | 63C7FFA91D5BEE09003BAE60 /* Sources */,
151 | 63C7FFF31D5C020D003BAE60 /* Tests */,
152 | 630B2DF31D5D0ABF00DC10E9 /* TestsHost */,
153 | 63C7FFA81D5BEE09003BAE60 /* Products */,
154 | );
155 | sourceTree = "";
156 | };
157 | 63C7FFA81D5BEE09003BAE60 /* Products */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */,
161 | 63C7FFF21D5C020D003BAE60 /* PMKUITests.xctest */,
162 | 630B2E131D5D0AF500DC10E9 /* PMKUIUITests.xctest */,
163 | 63C9C4451D5D334700101ECE /* PMKTestsHost.app */,
164 | );
165 | name = Products;
166 | sourceTree = "";
167 | };
168 | 63C7FFA91D5BEE09003BAE60 /* Sources */ = {
169 | isa = PBXGroup;
170 | children = (
171 | 6304D6FD1D5F986A00CE6C99 /* PMKUIKit.h */,
172 | 637E2C771D5C2E0B0043E370 /* UIView+AnyPromise.h */,
173 | 637E2C781D5C2E0B0043E370 /* UIView+AnyPromise.m */,
174 | 637E2C791D5C2E0B0043E370 /* UIView+Promise.swift */,
175 | 637E2C7A1D5C2E0B0043E370 /* UIViewController+AnyPromise.h */,
176 | 637E2C7B1D5C2E0B0043E370 /* UIViewController+AnyPromise.m */,
177 | 63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */,
178 | 632B573420324C4C00FCD5E1 /* UIViewPropertyAnimator+Promise.swift */,
179 | );
180 | path = Sources;
181 | sourceTree = SOURCE_ROOT;
182 | };
183 | 63C7FFF31D5C020D003BAE60 /* Tests */ = {
184 | isa = PBXGroup;
185 | children = (
186 | 637E2C8E1D5C2E720043E370 /* TestUIImagePickerController.swift */,
187 | 637E2C8F1D5C2E720043E370 /* TestUIViewController.m */,
188 | 6332142A1D83CD17009F67CE /* TestUIView.swift */,
189 | 637E2C9A1D5C2F600043E370 /* infrastructure.swift */,
190 | );
191 | path = Tests;
192 | sourceTree = SOURCE_ROOT;
193 | };
194 | /* End PBXGroup section */
195 |
196 | /* Begin PBXHeadersBuildPhase section */
197 | 63C7FFA41D5BEE09003BAE60 /* Headers */ = {
198 | isa = PBXHeadersBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | 6304D6FE1D5F986A00CE6C99 /* PMKUIKit.h in Headers */,
202 | 637E2C871D5C2E0B0043E370 /* UIViewController+AnyPromise.h in Headers */,
203 | 637E2C841D5C2E0B0043E370 /* UIView+AnyPromise.h in Headers */,
204 | );
205 | runOnlyForDeploymentPostprocessing = 0;
206 | };
207 | /* End PBXHeadersBuildPhase section */
208 |
209 | /* Begin PBXNativeTarget section */
210 | 630B2DFF1D5D0AF500DC10E9 /* PMKUIUITests */ = {
211 | isa = PBXNativeTarget;
212 | buildConfigurationList = 630B2E101D5D0AF500DC10E9 /* Build configuration list for PBXNativeTarget "PMKUIUITests" */;
213 | buildPhases = (
214 | 630B2E041D5D0AF500DC10E9 /* Sources */,
215 | 630B2E0D1D5D0AF500DC10E9 /* Frameworks */,
216 | );
217 | buildRules = (
218 | );
219 | dependencies = (
220 | 63C9C45A1D5D33A900101ECE /* PBXTargetDependency */,
221 | );
222 | name = PMKUIUITests;
223 | productName = PMKUIUITests;
224 | productReference = 630B2E131D5D0AF500DC10E9 /* PMKUIUITests.xctest */;
225 | productType = "com.apple.product-type.bundle.ui-testing";
226 | };
227 | 63C7FFA61D5BEE09003BAE60 /* PMKUIKit */ = {
228 | isa = PBXNativeTarget;
229 | buildConfigurationList = 63C7FFAF1D5BEE09003BAE60 /* Build configuration list for PBXNativeTarget "PMKUIKit" */;
230 | buildPhases = (
231 | 63C7FFA21D5BEE09003BAE60 /* Sources */,
232 | 63C7FFA31D5BEE09003BAE60 /* Frameworks */,
233 | 63C7FFA41D5BEE09003BAE60 /* Headers */,
234 | );
235 | buildRules = (
236 | );
237 | dependencies = (
238 | );
239 | name = PMKUIKit;
240 | productName = PMKUIKit;
241 | productReference = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */;
242 | productType = "com.apple.product-type.framework";
243 | };
244 | 63C7FFF11D5C020D003BAE60 /* PMKUITests */ = {
245 | isa = PBXNativeTarget;
246 | buildConfigurationList = 63C7FFFA1D5C020D003BAE60 /* Build configuration list for PBXNativeTarget "PMKUITests" */;
247 | buildPhases = (
248 | 63C7FFEE1D5C020D003BAE60 /* Sources */,
249 | 63C7FFEF1D5C020D003BAE60 /* Frameworks */,
250 | 6332EC8D1D5D085F00480270 /* Embed Carthage Frameworks */,
251 | );
252 | buildRules = (
253 | );
254 | dependencies = (
255 | 63C7FFF91D5C020D003BAE60 /* PBXTargetDependency */,
256 | 63C9C45C1D5D33AB00101ECE /* PBXTargetDependency */,
257 | );
258 | name = PMKUITests;
259 | productName = PMKUITests;
260 | productReference = 63C7FFF21D5C020D003BAE60 /* PMKUITests.xctest */;
261 | productType = "com.apple.product-type.bundle.unit-test";
262 | };
263 | 63C9C4441D5D334700101ECE /* PMKTestsHost */ = {
264 | isa = PBXNativeTarget;
265 | buildConfigurationList = 63C9C4541D5D334800101ECE /* Build configuration list for PBXNativeTarget "PMKTestsHost" */;
266 | buildPhases = (
267 | 63C9C4411D5D334700101ECE /* Sources */,
268 | 63C9C4421D5D334700101ECE /* Frameworks */,
269 | 63C9C4431D5D334700101ECE /* Resources */,
270 | 63C9C45D1D5D33E700101ECE /* Embed Carthage Frameworks */,
271 | 63C9C4621D5D341600101ECE /* Embed Frameworks */,
272 | );
273 | buildRules = (
274 | );
275 | dependencies = (
276 | 63C9C4611D5D341600101ECE /* PBXTargetDependency */,
277 | );
278 | name = PMKTestsHost;
279 | productName = PMKTestsHost;
280 | productReference = 63C9C4451D5D334700101ECE /* PMKTestsHost.app */;
281 | productType = "com.apple.product-type.application";
282 | };
283 | /* End PBXNativeTarget section */
284 |
285 | /* Begin PBXProject section */
286 | 63C7FF9E1D5BEE09003BAE60 /* Project object */ = {
287 | isa = PBXProject;
288 | attributes = {
289 | LastSwiftUpdateCheck = 0800;
290 | LastUpgradeCheck = 1020;
291 | ORGANIZATIONNAME = "Max Howell";
292 | TargetAttributes = {
293 | 630B2DFF1D5D0AF500DC10E9 = {
294 | LastSwiftMigration = 1020;
295 | TestTargetID = 63C9C4441D5D334700101ECE;
296 | };
297 | 63C7FFA61D5BEE09003BAE60 = {
298 | CreatedOnToolsVersion = 8.0;
299 | LastSwiftMigration = 1020;
300 | ProvisioningStyle = Automatic;
301 | };
302 | 63C7FFF11D5C020D003BAE60 = {
303 | CreatedOnToolsVersion = 8.0;
304 | LastSwiftMigration = 1020;
305 | ProvisioningStyle = Automatic;
306 | TestTargetID = 63C9C4441D5D334700101ECE;
307 | };
308 | 63C9C4441D5D334700101ECE = {
309 | CreatedOnToolsVersion = 8.0;
310 | LastSwiftMigration = 1020;
311 | ProvisioningStyle = Automatic;
312 | };
313 | };
314 | };
315 | buildConfigurationList = 63C7FFA11D5BEE09003BAE60 /* Build configuration list for PBXProject "PMKUIKit" */;
316 | compatibilityVersion = "Xcode 3.2";
317 | developmentRegion = en;
318 | hasScannedForEncodings = 0;
319 | knownRegions = (
320 | en,
321 | Base,
322 | );
323 | mainGroup = 63C7FF9D1D5BEE09003BAE60;
324 | productRefGroup = 63C7FFA81D5BEE09003BAE60 /* Products */;
325 | projectDirPath = "";
326 | projectRoot = "";
327 | targets = (
328 | 63C7FFA61D5BEE09003BAE60 /* PMKUIKit */,
329 | 63C7FFF11D5C020D003BAE60 /* PMKUITests */,
330 | 630B2DFF1D5D0AF500DC10E9 /* PMKUIUITests */,
331 | 63C9C4441D5D334700101ECE /* PMKTestsHost */,
332 | );
333 | };
334 | /* End PBXProject section */
335 |
336 | /* Begin PBXResourcesBuildPhase section */
337 | 63C9C4431D5D334700101ECE /* Resources */ = {
338 | isa = PBXResourcesBuildPhase;
339 | buildActionMask = 2147483647;
340 | files = (
341 | 63C9C4581D5D339B00101ECE /* Default-568h@2x.png in Resources */,
342 | );
343 | runOnlyForDeploymentPostprocessing = 0;
344 | };
345 | /* End PBXResourcesBuildPhase section */
346 |
347 | /* Begin PBXShellScriptBuildPhase section */
348 | 6332EC8D1D5D085F00480270 /* Embed Carthage Frameworks */ = {
349 | isa = PBXShellScriptBuildPhase;
350 | buildActionMask = 2147483647;
351 | files = (
352 | );
353 | inputPaths = (
354 | PromiseKit,
355 | );
356 | name = "Embed Carthage Frameworks";
357 | outputPaths = (
358 | );
359 | runOnlyForDeploymentPostprocessing = 0;
360 | shellPath = /bin/sh;
361 | shellScript = "case \"$PLATFORM_NAME\" in\nmacosx) plat=Mac;;\niphone*) plat=iOS;;\nwatch*) plat=watchOS;;\nappletv*) plat=tvOS;;\n*) echo \"error: Unknown PLATFORM_NAME: $PLATFORM_NAME\"; exit 1;;\nesac\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nframework=$(basename \"${!VAR}\")\nexport SCRIPT_INPUT_FILE_$n=\"$SRCROOT\"/Carthage/Build/$plat/\"$framework\".framework\ndone\n\n/usr/local/bin/carthage copy-frameworks || exit\n\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nsource=${!VAR}.dSYM\ndest=${BUILT_PRODUCTS_DIR}/$(basename \"$source\")\nditto \"$source\" \"$dest\" || exit\ndone";
362 | };
363 | 63C9C45D1D5D33E700101ECE /* Embed Carthage Frameworks */ = {
364 | isa = PBXShellScriptBuildPhase;
365 | buildActionMask = 2147483647;
366 | files = (
367 | );
368 | inputPaths = (
369 | PromiseKit,
370 | );
371 | name = "Embed Carthage Frameworks";
372 | outputPaths = (
373 | );
374 | runOnlyForDeploymentPostprocessing = 0;
375 | shellPath = /bin/sh;
376 | shellScript = "case \"$PLATFORM_NAME\" in\nmacosx) plat=Mac;;\niphone*) plat=iOS;;\nwatch*) plat=watchOS;;\nappletv*) plat=tvOS;;\n*) echo \"error: Unknown PLATFORM_NAME: $PLATFORM_NAME\"; exit 1;;\nesac\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nframework=$(basename \"${!VAR}\")\nexport SCRIPT_INPUT_FILE_$n=\"$SRCROOT\"/Carthage/Build/$plat/\"$framework\".framework\ndone\n\n/usr/local/bin/carthage copy-frameworks || exit\n\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nsource=${!VAR}.dSYM\ndest=${BUILT_PRODUCTS_DIR}/$(basename \"$source\")\nditto \"$source\" \"$dest\" || exit\ndone";
377 | };
378 | /* End PBXShellScriptBuildPhase section */
379 |
380 | /* Begin PBXSourcesBuildPhase section */
381 | 630B2E041D5D0AF500DC10E9 /* Sources */ = {
382 | isa = PBXSourcesBuildPhase;
383 | buildActionMask = 2147483647;
384 | files = (
385 | 630B2E161D5D0B3200DC10E9 /* TestUIImagePickerController.swift in Sources */,
386 | );
387 | runOnlyForDeploymentPostprocessing = 0;
388 | };
389 | 63C7FFA21D5BEE09003BAE60 /* Sources */ = {
390 | isa = PBXSourcesBuildPhase;
391 | buildActionMask = 2147483647;
392 | files = (
393 | 63A686811D88E93300D1C66B /* UIImagePickerController+Promise.swift in Sources */,
394 | 637E2C861D5C2E0B0043E370 /* UIView+Promise.swift in Sources */,
395 | 637E2C851D5C2E0B0043E370 /* UIView+AnyPromise.m in Sources */,
396 | 632B573520324C4C00FCD5E1 /* UIViewPropertyAnimator+Promise.swift in Sources */,
397 | 637E2C881D5C2E0B0043E370 /* UIViewController+AnyPromise.m in Sources */,
398 | );
399 | runOnlyForDeploymentPostprocessing = 0;
400 | };
401 | 63C7FFEE1D5C020D003BAE60 /* Sources */ = {
402 | isa = PBXSourcesBuildPhase;
403 | buildActionMask = 2147483647;
404 | files = (
405 | 637E2C951D5C2E720043E370 /* TestUIImagePickerController.swift in Sources */,
406 | 637E2C961D5C2E720043E370 /* TestUIViewController.m in Sources */,
407 | 637E2C9B1D5C2F600043E370 /* infrastructure.swift in Sources */,
408 | 6332142B1D83CD17009F67CE /* TestUIView.swift in Sources */,
409 | );
410 | runOnlyForDeploymentPostprocessing = 0;
411 | };
412 | 63C9C4411D5D334700101ECE /* Sources */ = {
413 | isa = PBXSourcesBuildPhase;
414 | buildActionMask = 2147483647;
415 | files = (
416 | 63C9C4571D5D339900101ECE /* app.swift in Sources */,
417 | );
418 | runOnlyForDeploymentPostprocessing = 0;
419 | };
420 | /* End PBXSourcesBuildPhase section */
421 |
422 | /* Begin PBXTargetDependency section */
423 | 63C7FFF91D5C020D003BAE60 /* PBXTargetDependency */ = {
424 | isa = PBXTargetDependency;
425 | target = 63C7FFA61D5BEE09003BAE60 /* PMKUIKit */;
426 | targetProxy = 63C7FFF81D5C020D003BAE60 /* PBXContainerItemProxy */;
427 | };
428 | 63C9C45A1D5D33A900101ECE /* PBXTargetDependency */ = {
429 | isa = PBXTargetDependency;
430 | target = 63C9C4441D5D334700101ECE /* PMKTestsHost */;
431 | targetProxy = 63C9C4591D5D33A900101ECE /* PBXContainerItemProxy */;
432 | };
433 | 63C9C45C1D5D33AB00101ECE /* PBXTargetDependency */ = {
434 | isa = PBXTargetDependency;
435 | target = 63C9C4441D5D334700101ECE /* PMKTestsHost */;
436 | targetProxy = 63C9C45B1D5D33AB00101ECE /* PBXContainerItemProxy */;
437 | };
438 | 63C9C4611D5D341600101ECE /* PBXTargetDependency */ = {
439 | isa = PBXTargetDependency;
440 | target = 63C7FFA61D5BEE09003BAE60 /* PMKUIKit */;
441 | targetProxy = 63C9C4601D5D341600101ECE /* PBXContainerItemProxy */;
442 | };
443 | /* End PBXTargetDependency section */
444 |
445 | /* Begin XCBuildConfiguration section */
446 | 630B2E111D5D0AF500DC10E9 /* Debug */ = {
447 | isa = XCBuildConfiguration;
448 | buildSettings = {
449 | BUNDLE_PACKAGE_TYPE = BNDL;
450 | CLANG_ENABLE_MODULES = YES;
451 | GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
452 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
454 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.ui.UIKit;
455 | PRODUCT_NAME = "$(TARGET_NAME)";
456 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
457 | SWIFT_SUPPRESS_WARNINGS = YES;
458 | SWIFT_VERSION = 4.0;
459 | TEST_TARGET_NAME = PMKTestsHost;
460 | };
461 | name = Debug;
462 | };
463 | 630B2E121D5D0AF500DC10E9 /* Release */ = {
464 | isa = XCBuildConfiguration;
465 | buildSettings = {
466 | BUNDLE_PACKAGE_TYPE = BNDL;
467 | CLANG_ENABLE_MODULES = YES;
468 | GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
469 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
470 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
471 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.ui.UIKit;
472 | PRODUCT_NAME = "$(TARGET_NAME)";
473 | SWIFT_SUPPRESS_WARNINGS = YES;
474 | SWIFT_VERSION = 4.0;
475 | TEST_TARGET_NAME = PMKTestsHost;
476 | };
477 | name = Release;
478 | };
479 | 63C7FFAD1D5BEE09003BAE60 /* Debug */ = {
480 | isa = XCBuildConfiguration;
481 | baseConfigurationReference = 63CCF8171D5C11B500503216 /* Carthage.xcconfig */;
482 | buildSettings = {
483 | ALWAYS_SEARCH_USER_PATHS = NO;
484 | BUNDLE_PACKAGE_TYPE = FMWK;
485 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
486 | CLANG_ANALYZER_NONNULL = YES;
487 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
488 | CLANG_CXX_LIBRARY = "libc++";
489 | CLANG_ENABLE_MODULES = YES;
490 | CLANG_ENABLE_OBJC_ARC = YES;
491 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
492 | CLANG_WARN_BOOL_CONVERSION = YES;
493 | CLANG_WARN_COMMA = YES;
494 | CLANG_WARN_CONSTANT_CONVERSION = YES;
495 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
496 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
497 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
498 | CLANG_WARN_EMPTY_BODY = YES;
499 | CLANG_WARN_ENUM_CONVERSION = YES;
500 | CLANG_WARN_INFINITE_RECURSION = YES;
501 | CLANG_WARN_INT_CONVERSION = YES;
502 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
503 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
504 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
505 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
506 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
507 | CLANG_WARN_STRICT_PROTOTYPES = YES;
508 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
509 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
510 | CLANG_WARN_UNREACHABLE_CODE = YES;
511 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
512 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
513 | CURRENT_PROJECT_VERSION = 1.0.3;
514 | DEBUG_INFORMATION_FORMAT = dwarf;
515 | ENABLE_STRICT_OBJC_MSGSEND = YES;
516 | ENABLE_TESTABILITY = YES;
517 | GCC_C_LANGUAGE_STANDARD = gnu99;
518 | GCC_DYNAMIC_NO_PIC = NO;
519 | GCC_NO_COMMON_BLOCKS = YES;
520 | GCC_OPTIMIZATION_LEVEL = 0;
521 | GCC_PREPROCESSOR_DEFINITIONS = (
522 | "DEBUG=1",
523 | "$(inherited)",
524 | );
525 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
526 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
527 | GCC_WARN_UNDECLARED_SELECTOR = YES;
528 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
529 | GCC_WARN_UNUSED_FUNCTION = YES;
530 | GCC_WARN_UNUSED_VARIABLE = YES;
531 | INFOPLIST_FILE = Info.plist;
532 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
533 | MACOSX_DEPLOYMENT_TARGET = 10.10;
534 | MTL_ENABLE_DEBUG_INFO = YES;
535 | ONLY_ACTIVE_ARCH = YES;
536 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.UIKit;
537 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos";
538 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
539 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
540 | SWIFT_VERSION = 4.0;
541 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
542 | TVOS_DEPLOYMENT_TARGET = 9.0;
543 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
544 | };
545 | name = Debug;
546 | };
547 | 63C7FFAE1D5BEE09003BAE60 /* Release */ = {
548 | isa = XCBuildConfiguration;
549 | baseConfigurationReference = 63CCF8171D5C11B500503216 /* Carthage.xcconfig */;
550 | buildSettings = {
551 | ALWAYS_SEARCH_USER_PATHS = NO;
552 | BUNDLE_PACKAGE_TYPE = FMWK;
553 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
554 | CLANG_ANALYZER_NONNULL = YES;
555 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
556 | CLANG_CXX_LIBRARY = "libc++";
557 | CLANG_ENABLE_MODULES = YES;
558 | CLANG_ENABLE_OBJC_ARC = YES;
559 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
560 | CLANG_WARN_BOOL_CONVERSION = YES;
561 | CLANG_WARN_COMMA = YES;
562 | CLANG_WARN_CONSTANT_CONVERSION = YES;
563 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
564 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
565 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
566 | CLANG_WARN_EMPTY_BODY = YES;
567 | CLANG_WARN_ENUM_CONVERSION = YES;
568 | CLANG_WARN_INFINITE_RECURSION = YES;
569 | CLANG_WARN_INT_CONVERSION = YES;
570 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
571 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
572 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
573 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
574 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
575 | CLANG_WARN_STRICT_PROTOTYPES = YES;
576 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
577 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
578 | CLANG_WARN_UNREACHABLE_CODE = YES;
579 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
580 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
581 | CURRENT_PROJECT_VERSION = 1.0.3;
582 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
583 | ENABLE_NS_ASSERTIONS = NO;
584 | ENABLE_STRICT_OBJC_MSGSEND = YES;
585 | GCC_C_LANGUAGE_STANDARD = gnu99;
586 | GCC_NO_COMMON_BLOCKS = YES;
587 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
588 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
589 | GCC_WARN_UNDECLARED_SELECTOR = YES;
590 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
591 | GCC_WARN_UNUSED_FUNCTION = YES;
592 | GCC_WARN_UNUSED_VARIABLE = YES;
593 | INFOPLIST_FILE = Info.plist;
594 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
595 | MACOSX_DEPLOYMENT_TARGET = 10.10;
596 | MTL_ENABLE_DEBUG_INFO = NO;
597 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.UIKit;
598 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos";
599 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
600 | SWIFT_VERSION = 4.0;
601 | TARGETED_DEVICE_FAMILY = "1,2,3,4";
602 | TVOS_DEPLOYMENT_TARGET = 9.0;
603 | VALIDATE_PRODUCT = YES;
604 | WATCHOS_DEPLOYMENT_TARGET = 2.0;
605 | };
606 | name = Release;
607 | };
608 | 63C7FFB01D5BEE09003BAE60 /* Debug */ = {
609 | isa = XCBuildConfiguration;
610 | buildSettings = {
611 | APPLICATION_EXTENSION_API_ONLY = YES;
612 | CLANG_ENABLE_MODULES = YES;
613 | CODE_SIGN_IDENTITY = "";
614 | DEFINES_MODULE = YES;
615 | DYLIB_COMPATIBILITY_VERSION = 1;
616 | DYLIB_CURRENT_VERSION = 1;
617 | DYLIB_INSTALL_NAME_BASE = "@rpath";
618 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
619 | PRODUCT_MODULE_NAME = "${TARGET_NAME}";
620 | PRODUCT_NAME = "$(TARGET_NAME)";
621 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
622 | SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
623 | };
624 | name = Debug;
625 | };
626 | 63C7FFB11D5BEE09003BAE60 /* Release */ = {
627 | isa = XCBuildConfiguration;
628 | buildSettings = {
629 | APPLICATION_EXTENSION_API_ONLY = YES;
630 | CLANG_ENABLE_MODULES = YES;
631 | CODE_SIGN_IDENTITY = "";
632 | DEFINES_MODULE = YES;
633 | DYLIB_COMPATIBILITY_VERSION = 1;
634 | DYLIB_CURRENT_VERSION = 1;
635 | DYLIB_INSTALL_NAME_BASE = "@rpath";
636 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
637 | PRODUCT_MODULE_NAME = "${TARGET_NAME}";
638 | PRODUCT_NAME = "$(TARGET_NAME)";
639 | SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;
640 | };
641 | name = Release;
642 | };
643 | 63C7FFFB1D5C020D003BAE60 /* Debug */ = {
644 | isa = XCBuildConfiguration;
645 | buildSettings = {
646 | BUNDLE_PACKAGE_TYPE = BNDL;
647 | CLANG_ENABLE_MODULES = YES;
648 | GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
649 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
650 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.UIKit;
651 | PRODUCT_NAME = "$(TARGET_NAME)";
652 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
653 | SWIFT_SUPPRESS_WARNINGS = YES;
654 | SWIFT_VERSION = 4.0;
655 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PMKTestsHost.app/PMKTestsHost";
656 | };
657 | name = Debug;
658 | };
659 | 63C7FFFC1D5C020D003BAE60 /* Release */ = {
660 | isa = XCBuildConfiguration;
661 | buildSettings = {
662 | BUNDLE_PACKAGE_TYPE = BNDL;
663 | CLANG_ENABLE_MODULES = YES;
664 | GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
665 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
666 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.UIKit;
667 | PRODUCT_NAME = "$(TARGET_NAME)";
668 | SWIFT_SUPPRESS_WARNINGS = YES;
669 | SWIFT_VERSION = 4.0;
670 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PMKTestsHost.app/PMKTestsHost";
671 | };
672 | name = Release;
673 | };
674 | 63C9C4551D5D334800101ECE /* Debug */ = {
675 | isa = XCBuildConfiguration;
676 | buildSettings = {
677 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
678 | BUNDLE_PACKAGE_TYPE = APPL;
679 | CODE_SIGN_ENTITLEMENTS = UITests/Entitlements.plist;
680 | COPY_PHASE_STRIP = NO;
681 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
682 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
683 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.host.UIKit;
684 | PRODUCT_NAME = "$(TARGET_NAME)";
685 | SDKROOT = iphoneos;
686 | SWIFT_VERSION = 4.0;
687 | };
688 | name = Debug;
689 | };
690 | 63C9C4561D5D334800101ECE /* Release */ = {
691 | isa = XCBuildConfiguration;
692 | buildSettings = {
693 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
694 | BUNDLE_PACKAGE_TYPE = APPL;
695 | CODE_SIGN_ENTITLEMENTS = UITests/Entitlements.plist;
696 | COPY_PHASE_STRIP = NO;
697 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
698 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
699 | PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.tests.host.UIKit;
700 | PRODUCT_NAME = "$(TARGET_NAME)";
701 | SDKROOT = iphoneos;
702 | SWIFT_VERSION = 4.0;
703 | };
704 | name = Release;
705 | };
706 | /* End XCBuildConfiguration section */
707 |
708 | /* Begin XCConfigurationList section */
709 | 630B2E101D5D0AF500DC10E9 /* Build configuration list for PBXNativeTarget "PMKUIUITests" */ = {
710 | isa = XCConfigurationList;
711 | buildConfigurations = (
712 | 630B2E111D5D0AF500DC10E9 /* Debug */,
713 | 630B2E121D5D0AF500DC10E9 /* Release */,
714 | );
715 | defaultConfigurationIsVisible = 0;
716 | defaultConfigurationName = Release;
717 | };
718 | 63C7FFA11D5BEE09003BAE60 /* Build configuration list for PBXProject "PMKUIKit" */ = {
719 | isa = XCConfigurationList;
720 | buildConfigurations = (
721 | 63C7FFAD1D5BEE09003BAE60 /* Debug */,
722 | 63C7FFAE1D5BEE09003BAE60 /* Release */,
723 | );
724 | defaultConfigurationIsVisible = 0;
725 | defaultConfigurationName = Release;
726 | };
727 | 63C7FFAF1D5BEE09003BAE60 /* Build configuration list for PBXNativeTarget "PMKUIKit" */ = {
728 | isa = XCConfigurationList;
729 | buildConfigurations = (
730 | 63C7FFB01D5BEE09003BAE60 /* Debug */,
731 | 63C7FFB11D5BEE09003BAE60 /* Release */,
732 | );
733 | defaultConfigurationIsVisible = 0;
734 | defaultConfigurationName = Release;
735 | };
736 | 63C7FFFA1D5C020D003BAE60 /* Build configuration list for PBXNativeTarget "PMKUITests" */ = {
737 | isa = XCConfigurationList;
738 | buildConfigurations = (
739 | 63C7FFFB1D5C020D003BAE60 /* Debug */,
740 | 63C7FFFC1D5C020D003BAE60 /* Release */,
741 | );
742 | defaultConfigurationIsVisible = 0;
743 | defaultConfigurationName = Release;
744 | };
745 | 63C9C4541D5D334800101ECE /* Build configuration list for PBXNativeTarget "PMKTestsHost" */ = {
746 | isa = XCConfigurationList;
747 | buildConfigurations = (
748 | 63C9C4551D5D334800101ECE /* Debug */,
749 | 63C9C4561D5D334800101ECE /* Release */,
750 | );
751 | defaultConfigurationIsVisible = 0;
752 | defaultConfigurationName = Release;
753 | };
754 | /* End XCConfigurationList section */
755 | };
756 | rootObject = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
757 | }
758 |
--------------------------------------------------------------------------------
/PMKUIKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PMKUIKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PMKUIKit.xcodeproj/xcshareddata/xcschemes/PMKUIKit.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
57 |
63 |
64 |
65 |
67 |
68 |
70 |
71 |
73 |
74 |
75 |
76 |
77 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
99 |
100 |
106 |
107 |
108 |
109 |
110 |
111 |
117 |
118 |
124 |
125 |
126 |
127 |
129 |
130 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "PromiseKit",
6 | "repositoryURL": "https://github.com/mxcl/PromiseKit.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "2bc44395edb4f8391902a9ff7c220471882a4d07",
10 | "version": "8.2.0"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 |
3 | import PackageDescription
4 |
5 | let pkg = Package(name: "PMKUIKit")
6 | pkg.products = [
7 | .library(name: "PMKUIKit", targets: ["PMKUIKit"]),
8 | ]
9 | pkg.dependencies = [
10 | .package(url: "https://github.com/mxcl/PromiseKit.git", from: "8.2.0")
11 | ]
12 | pkg.swiftLanguageVersions = [.v4, .v4_2, .v5]
13 |
14 | let target: Target = .target(name: "PMKUIKit")
15 | target.path = "Sources"
16 | target.exclude = ["UIView", "UIViewController"].flatMap {
17 | ["\($0)+AnyPromise.m", "\($0)+AnyPromise.h"]
18 | }
19 | target.exclude.append("PMKUIKit.h")
20 |
21 | target.dependencies = [
22 | "PromiseKit"
23 | ]
24 |
25 | pkg.targets = [target]
26 |
27 | pkg.platforms = [
28 | .iOS(.v8)
29 | ]
30 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # PromiseKit UIKit Extensions ![Build Status]
2 |
3 | This project adds promises to Apple’s UIKit framework.
4 |
5 | This project supports Swift 3.0, 3.1, 3.2 and 4.0; iOS 9, 10 and 11; tvOS 10 and
6 | 11; CocoaPods and Carthage; Xcode 8.0, 8.1, 8.2, 8.3 and 9.0.
7 |
8 | ## CocoaPods
9 |
10 | ```ruby
11 | pod "PromiseKit/UIKit", "~> 6.0"
12 | ```
13 |
14 | The extensions are built into `PromiseKit.framework` thus `import PromiseKit` is
15 | all that is needed.
16 |
17 | ## Carthage
18 |
19 | ```ruby
20 | github "PromiseKit/UIKit" ~> 3.0
21 | ```
22 |
23 | The extensions are built into their own framework:
24 |
25 | ```swift
26 | // swift
27 | import PromiseKit
28 | import PMKUIKit
29 | ```
30 |
31 | ```objc
32 | // objc
33 | @import PromiseKit;
34 | @import PMKUIKit;
35 | ```
36 |
37 | # `UIImagePickerController`
38 |
39 | Due to iOS 10 requiring an entry in your app’s `Info.plist` for any usage of `UIImagePickerController` (even if you don’t actually call it directly), we have removed UIImagePickerController from the default `UIKit` pod. To use it you must add an additional subspec:
40 |
41 | ```ruby
42 | pod "PromiseKit/UIImagePickerController"
43 | ```
44 |
45 | Sorry, but there’s not an easier way.
46 |
47 |
48 | [Build Status]: https://travis-ci.org/PromiseKit/UIKit.svg?branch=master
49 |
--------------------------------------------------------------------------------
/Sources/PMKUIKit.h:
--------------------------------------------------------------------------------
1 | #import "UIView+AnyPromise.h"
2 | #import "UIViewController+AnyPromise.h"
3 |
4 | typedef NS_OPTIONS(NSInteger, PMKAnimationOptions) {
5 | PMKAnimationOptionsNone = 1 << 0,
6 | PMKAnimationOptionsAppear = 1 << 1,
7 | PMKAnimationOptionsDisappear = 1 << 2,
8 | };
9 |
--------------------------------------------------------------------------------
/Sources/UIImagePickerController+Promise.swift:
--------------------------------------------------------------------------------
1 | #if !PMKCocoaPods
2 | import PromiseKit
3 | #endif
4 | import UIKit
5 |
6 | #if !os(tvOS)
7 |
8 | public struct AnimationOptions: OptionSet {
9 | public let rawValue: Int
10 |
11 | public static let appear = AnimationOptions(rawValue: 1 << 1)
12 | public static let disappear = AnimationOptions(rawValue: 1 << 2)
13 |
14 | public init(rawValue: Int) {
15 | self.rawValue = rawValue
16 | }
17 | }
18 |
19 | extension UIViewController {
20 | #if swift(>=4.2)
21 | /// Presents the UIImagePickerController, resolving with the user action.
22 | public func promise(_ vc: UIImagePickerController, animate: AnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[UIImagePickerController.InfoKey: Any]> {
23 | let animated = animate.contains(.appear)
24 | let proxy = UIImagePickerControllerProxy()
25 | vc.delegate = proxy
26 | present(vc, animated: animated, completion: completion)
27 | return proxy.promise.ensure {
28 | vc.presentingViewController?.dismiss(animated: animated, completion: nil)
29 | }
30 | }
31 | #else
32 | /// Presents the UIImagePickerController, resolving with the user action.
33 | public func promise(_ vc: UIImagePickerController, animate: AnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[String: Any]> {
34 | let animated = animate.contains(.appear)
35 | let proxy = UIImagePickerControllerProxy()
36 | vc.delegate = proxy
37 | present(vc, animated: animated, completion: completion)
38 | return proxy.promise.ensure {
39 | vc.presentingViewController?.dismiss(animated: animated, completion: nil)
40 | }
41 | }
42 | #endif
43 | }
44 |
45 | @objc private class UIImagePickerControllerProxy: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
46 | #if swift(>=4.2)
47 | let (promise, seal) = Promise<[UIImagePickerController.InfoKey: Any]>.pending()
48 | #else
49 | let (promise, seal) = Promise<[String: Any]>.pending()
50 | #endif
51 | var retainCycle: AnyObject?
52 |
53 | required override init() {
54 | super.init()
55 | retainCycle = self
56 | }
57 |
58 | #if swift(>=4.2)
59 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
60 | seal.fulfill(info)
61 | retainCycle = nil
62 | }
63 | #else
64 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
65 | seal.fulfill(info)
66 | retainCycle = nil
67 | }
68 | #endif
69 |
70 | func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
71 | seal.reject(UIImagePickerController.PMKError.cancelled)
72 | retainCycle = nil
73 | }
74 | }
75 |
76 | extension UIImagePickerController {
77 | /// Errors representing PromiseKit UIImagePickerController failures
78 | public enum PMKError: CancellableError {
79 | /// The user cancelled the UIImagePickerController.
80 | case cancelled
81 | /// - Returns: true
82 | public var isCancelled: Bool {
83 | switch self {
84 | case .cancelled:
85 | return true
86 | }
87 | }
88 | }
89 | }
90 |
91 | #endif
92 |
--------------------------------------------------------------------------------
/Sources/UIView+AnyPromise.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | // Created by Masafumi Yoshida on 2014/07/11.
5 | // Copyright (c) 2014年 DeNA. All rights reserved.
6 |
7 | /**
8 | To import the `UIView` category:
9 |
10 | use_frameworks!
11 | pod "PromiseKit/UIKit"
12 |
13 | Or `UIKit` is one of the categories imported by the umbrella pod:
14 |
15 | use_frameworks!
16 | pod "PromiseKit"
17 |
18 | And then in your sources:
19 |
20 | @import PromiseKit;
21 | */
22 | @interface UIView (PromiseKit)
23 |
24 | /**
25 | Animate changes to one or more views using the specified duration.
26 |
27 | @param duration The total duration of the animations, measured in
28 | seconds. If you specify a negative value or 0, the changes are made
29 | without animating them.
30 |
31 | @param animations A block object containing the changes to commit to the
32 | views.
33 |
34 | @return A promise that fulfills with a boolean NSNumber indicating
35 | whether or not the animations actually finished.
36 | */
37 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_REFINED_FOR_SWIFT;
38 |
39 | /**
40 | Animate changes to one or more views using the specified duration, delay,
41 | options, and completion handler.
42 |
43 | @param duration The total duration of the animations, measured in
44 | seconds. If you specify a negative value or 0, the changes are made
45 | without animating them.
46 |
47 | @param delay The amount of time (measured in seconds) to wait before
48 | beginning the animations. Specify a value of 0 to begin the animations
49 | immediately.
50 |
51 | @param options A mask of options indicating how you want to perform the
52 | animations. For a list of valid constants, see UIViewAnimationOptions.
53 |
54 | @param animations A block object containing the changes to commit to the
55 | views.
56 |
57 | @return A promise that fulfills with a boolean NSNumber indicating
58 | whether or not the animations actually finished.
59 | */
60 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations NS_REFINED_FOR_SWIFT;
61 |
62 | /**
63 | Performs a view animation using a timing curve corresponding to the
64 | motion of a physical spring.
65 |
66 | @return A promise that fulfills with a boolean NSNumber indicating
67 | whether or not the animations actually finished.
68 | */
69 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations NS_REFINED_FOR_SWIFT;
70 |
71 | /**
72 | Creates an animation block object that can be used to set up
73 | keyframe-based animations for the current view.
74 |
75 | @return A promise that fulfills with a boolean NSNumber indicating
76 | whether or not the animations actually finished.
77 | */
78 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options keyframeAnimations:(void (^)(void))animations NS_REFINED_FOR_SWIFT;
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/Sources/UIView+AnyPromise.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+PromiseKit_UIAnimation.m
3 | // YahooDenaStudy
4 | //
5 | // Created by Masafumi Yoshida on 2014/07/11.
6 | // Copyright (c) 2014年 DeNA. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "UIView+AnyPromise.h"
11 |
12 |
13 | #define CopyPasta \
14 | NSAssert([NSThread isMainThread], @"UIKit animation must be performed on the main thread"); \
15 | \
16 | if (![NSThread isMainThread]) { \
17 | id error = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:@{NSLocalizedDescriptionKey: @"Animation was attempted on a background thread"}]; \
18 | return [AnyPromise promiseWithValue:error]; \
19 | } \
20 | \
21 | PMKResolver resolve = nil; \
22 | AnyPromise *promise = [[AnyPromise alloc] initWithResolver:&resolve];
23 |
24 |
25 | @implementation UIView (PromiseKit)
26 |
27 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations {
28 | return [self promiseWithDuration:duration delay:0 options:0 animations:animations];
29 | }
30 |
31 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void(^)(void))animations
32 | {
33 | CopyPasta;
34 |
35 | [UIView animateWithDuration:duration delay:delay options:options animations:animations completion:^(BOOL finished) {
36 | resolve(@(finished));
37 | }];
38 |
39 | return promise;
40 | }
41 |
42 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void(^)(void))animations
43 | {
44 | CopyPasta;
45 |
46 | [UIView animateWithDuration:duration delay:delay usingSpringWithDamping:dampingRatio initialSpringVelocity:velocity options:options animations:animations completion:^(BOOL finished) {
47 | resolve(@(finished));
48 | }];
49 |
50 | return promise;
51 | }
52 |
53 | + (AnyPromise *)promiseWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options keyframeAnimations:(void(^)(void))animations
54 | {
55 | CopyPasta;
56 |
57 | [UIView animateKeyframesWithDuration:duration delay:delay options:options animations:animations completion:^(BOOL finished) {
58 | resolve(@(finished));
59 | }];
60 |
61 | return promise;
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/Sources/UIView+Promise.swift:
--------------------------------------------------------------------------------
1 | import UIKit.UIView
2 | #if !PMKCocoaPods
3 | import PromiseKit
4 | #endif
5 |
6 | /**
7 | To import the `UIView` category:
8 |
9 | use_frameworks!
10 | pod "PromiseKit/UIKit"
11 |
12 | Or `UIKit` is one of the categories imported by the umbrella pod:
13 |
14 | use_frameworks!
15 | pod "PromiseKit"
16 |
17 | And then in your sources:
18 |
19 | import PromiseKit
20 | */
21 | public extension UIView {
22 | #if swift(>=4.2)
23 | /**
24 | Animate changes to one or more views using the specified duration, delay,
25 | options, and completion handler.
26 |
27 | - Parameter duration: The total duration of the animations, measured in
28 | seconds. If you specify a negative value or 0, the changes are made
29 | without animating them.
30 |
31 | - Parameter delay: The amount of time (measured in seconds) to wait before
32 | beginning the animations. Specify a value of 0 to begin the animations
33 | immediately.
34 |
35 | - Parameter options: A mask of options indicating how you want to perform the
36 | animations. For a list of valid constants, see UIViewAnimationOptions.
37 |
38 | - Parameter animations: A block object containing the changes to commit to the
39 | views.
40 |
41 | - Returns: A promise that fulfills with a boolean NSNumber indicating
42 | whether or not the animations actually finished.
43 | */
44 | @discardableResult
45 | static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval = 0, options: UIView.AnimationOptions = [], animations: @escaping () -> Void) -> Guarantee {
46 | return Guarantee { animate(withDuration: duration, delay: delay, options: options, animations: animations, completion: $0) }
47 | }
48 |
49 | @discardableResult
50 | static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval, usingSpringWithDamping damping: CGFloat, initialSpringVelocity: CGFloat, options: UIView.AnimationOptions = [], animations: @escaping () -> Void) -> Guarantee {
51 | return Guarantee { animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: $0) }
52 | }
53 |
54 | @discardableResult
55 | static func transition(_: PMKNamespacer, with view: UIView, duration: TimeInterval, options: UIView.AnimationOptions = [], animations: (() -> Void)?) -> Guarantee {
56 | return Guarantee { transition(with: view, duration: duration, options: options, animations: animations, completion: $0) }
57 | }
58 |
59 | @discardableResult
60 | static func transition(_: PMKNamespacer, from: UIView, to: UIView, duration: TimeInterval, options: UIView.AnimationOptions = []) -> Guarantee {
61 | return Guarantee { transition(from: from, to: to, duration: duration, options: options, completion: $0) }
62 | }
63 |
64 | @discardableResult
65 | static func perform(_: PMKNamespacer, animation: UIView.SystemAnimation, on views: [UIView], options: UIView.AnimationOptions = [], animations: (() -> Void)?) -> Guarantee {
66 | return Guarantee { perform(animation, on: views, options: options, animations: animations, completion: $0) }
67 | }
68 | #else
69 | /**
70 | Animate changes to one or more views using the specified duration, delay,
71 | options, and completion handler.
72 |
73 | - Parameter duration: The total duration of the animations, measured in
74 | seconds. If you specify a negative value or 0, the changes are made
75 | without animating them.
76 |
77 | - Parameter delay: The amount of time (measured in seconds) to wait before
78 | beginning the animations. Specify a value of 0 to begin the animations
79 | immediately.
80 |
81 | - Parameter options: A mask of options indicating how you want to perform the
82 | animations. For a list of valid constants, see UIViewAnimationOptions.
83 |
84 | - Parameter animations: A block object containing the changes to commit to the
85 | views.
86 |
87 | - Returns: A promise that fulfills with a boolean NSNumber indicating
88 | whether or not the animations actually finished.
89 | */
90 | @discardableResult
91 | static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval = 0, options: UIViewAnimationOptions = [], animations: @escaping () -> Void) -> Guarantee {
92 | return Guarantee { animate(withDuration: duration, delay: delay, options: options, animations: animations, completion: $0) }
93 | }
94 |
95 | @discardableResult
96 | static func animate(_: PMKNamespacer, duration: TimeInterval, delay: TimeInterval, usingSpringWithDamping damping: CGFloat, initialSpringVelocity: CGFloat, options: UIViewAnimationOptions = [], animations: @escaping () -> Void) -> Guarantee {
97 | return Guarantee { animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: initialSpringVelocity, options: options, animations: animations, completion: $0) }
98 | }
99 |
100 | @discardableResult
101 | static func transition(_: PMKNamespacer, with view: UIView, duration: TimeInterval, options: UIViewAnimationOptions = [], animations: (() -> Void)?) -> Guarantee {
102 | return Guarantee { transition(with: view, duration: duration, options: options, animations: animations, completion: $0) }
103 | }
104 |
105 | @discardableResult
106 | static func transition(_: PMKNamespacer, from: UIView, to: UIView, duration: TimeInterval, options: UIViewAnimationOptions = []) -> Guarantee {
107 | return Guarantee { transition(from: from, to: to, duration: duration, options: options, completion: $0) }
108 | }
109 |
110 | @discardableResult
111 | static func perform(_: PMKNamespacer, animation: UISystemAnimation, on views: [UIView], options: UIViewAnimationOptions = [], animations: (() -> Void)?) -> Guarantee {
112 | return Guarantee { perform(animation, on: views, options: options, animations: animations, completion: $0) }
113 | }
114 | #endif
115 | }
116 |
--------------------------------------------------------------------------------
/Sources/UIViewController+AnyPromise.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | /**
5 | To import the `UIViewController` category:
6 |
7 | use_frameworks!
8 | pod "PromiseKit/UIKit"
9 |
10 | Or `UIKit` is one of the categories imported by the umbrella pod:
11 |
12 | use_frameworks!
13 | pod "PromiseKit"
14 |
15 | And then in your sources:
16 |
17 | @import PromiseKit;
18 | */
19 | @interface UIViewController (PromiseKit)
20 |
21 | /**
22 | Presents a view controller modally.
23 |
24 | If the view controller is one of the following:
25 |
26 | - MFMailComposeViewController
27 | - MFMessageComposeViewController
28 | - UIImagePickerController
29 | - SLComposeViewController
30 |
31 | Then PromiseKit presents the view controller returning a promise that is
32 | resolved as per the documentation for those classes. Eg. if you present a
33 | `UIImagePickerController` the view controller will be presented for you
34 | and the returned promise will resolve with the media the user selected.
35 |
36 | [self promiseViewController:[MFMailComposeViewController new] animated:YES completion:nil].then(^{
37 | //…
38 | });
39 |
40 | Otherwise PromiseKit expects your view controller to implement a
41 | `promise` property. This promise will be returned from this method and
42 | presentation and dismissal of the presented view controller will be
43 | managed for you.
44 |
45 | \@interface MyViewController: UIViewController
46 | @property (readonly) AnyPromise *promise;
47 | @end
48 |
49 | @implementation MyViewController {
50 | PMKResolver resolve;
51 | }
52 |
53 | - (void)viewDidLoad {
54 | _promise = [[AnyPromise alloc] initWithResolver:&resolve];
55 | }
56 |
57 | - (void)later {
58 | resolve(@"some fulfilled value");
59 | }
60 |
61 | @end
62 |
63 | [self promiseViewController:[MyViewController new] aniamted:YES completion:nil].then(^(id value){
64 | // value == @"some fulfilled value"
65 | });
66 |
67 | @return A promise that can be resolved by the presented view controller.
68 | */
69 | - (AnyPromise *)promiseViewController:(UIViewController *)vc animated:(BOOL)animated completion:(void (^)(void))block NS_REFINED_FOR_SWIFT;
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/Sources/UIViewController+AnyPromise.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import "UIViewController+AnyPromise.h"
3 | #import
4 |
5 | #if PMKImagePickerController
6 | #import
7 | #endif
8 |
9 | @interface PMKGenericDelegate : NSObject {
10 | @public
11 | PMKResolver resolve;
12 | }
13 | + (instancetype)delegateWithPromise:(AnyPromise **)promise;
14 | @end
15 |
16 | @interface UIViewController ()
17 | - (AnyPromise*) promise;
18 | @end
19 |
20 | @implementation UIViewController (PromiseKit)
21 |
22 | - (AnyPromise *)promiseViewController:(UIViewController *)vc animated:(BOOL)animated completion:(void (^)(void))block {
23 | __kindof UIViewController *vc2present = vc;
24 | AnyPromise *promise = nil;
25 |
26 | if ([vc isKindOfClass:NSClassFromString(@"MFMailComposeViewController")]) {
27 | PMKGenericDelegate *delegate = [PMKGenericDelegate delegateWithPromise:&promise];
28 | [vc setValue:delegate forKey:@"mailComposeDelegate"];
29 | }
30 | else if ([vc isKindOfClass:NSClassFromString(@"MFMessageComposeViewController")]) {
31 | PMKGenericDelegate *delegate = [PMKGenericDelegate delegateWithPromise:&promise];
32 | [vc setValue:delegate forKey:@"messageComposeDelegate"];
33 | }
34 | #ifdef PMKImagePickerController
35 | else if ([vc isKindOfClass:[UIImagePickerController class]]) {
36 | PMKGenericDelegate *delegate = [PMKGenericDelegate delegateWithPromise:&promise];
37 | [vc setValue:delegate forKey:@"delegate"];
38 | }
39 | #endif
40 | else if ([vc isKindOfClass:NSClassFromString(@"SLComposeViewController")]) {
41 | PMKResolver resolve;
42 | promise = [[AnyPromise alloc] initWithResolver:&resolve];
43 | [vc setValue:^(NSInteger result){
44 | if (result == 0) {
45 | resolve([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]);
46 | } else {
47 | resolve(@(result));
48 | }
49 | } forKey:@"completionHandler"];
50 | }
51 | else if ([vc isKindOfClass:[UINavigationController class]])
52 | vc = [(id)vc viewControllers].firstObject;
53 |
54 | if (!vc) {
55 | id userInfo = @{NSLocalizedDescriptionKey: @"nil or effective nil passed to promiseViewController"};
56 | id err = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:userInfo];
57 | return [AnyPromise promiseWithValue:err];
58 | }
59 |
60 | if (!promise) {
61 | if (![vc respondsToSelector:@selector(promise)]) {
62 | id userInfo = @{NSLocalizedDescriptionKey: @"ViewController is not promisable"};
63 | id err = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:userInfo];
64 | return [AnyPromise promiseWithValue:err];
65 | }
66 |
67 | promise = [vc valueForKey:@"promise"];
68 |
69 | if (![promise isKindOfClass:[AnyPromise class]]) {
70 | id userInfo = @{NSLocalizedDescriptionKey: @"The promise property is nil or not of type AnyPromise"};
71 | id err = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:userInfo];
72 | return [AnyPromise promiseWithValue:err];
73 | }
74 | }
75 |
76 | if (!promise.pending)
77 | return promise;
78 |
79 | [self presentViewController:vc2present animated:animated completion:block];
80 |
81 | promise.ensure(^{
82 | [vc2present.presentingViewController dismissViewControllerAnimated:animated completion:nil];
83 | });
84 |
85 | return promise;
86 | }
87 |
88 | @end
89 |
90 |
91 |
92 | @implementation PMKGenericDelegate {
93 | id retainCycle;
94 | }
95 |
96 | + (instancetype)delegateWithPromise:(AnyPromise **)promise; {
97 | PMKGenericDelegate *d = [PMKGenericDelegate new];
98 | d->retainCycle = d;
99 | *promise = [[AnyPromise alloc] initWithResolver:&d->resolve];
100 | return d;
101 | }
102 |
103 | - (void)mailComposeController:(id)controller didFinishWithResult:(int)result error:(NSError *)error {
104 | if (error != nil) {
105 | resolve(error);
106 | } else if (result == 0) {
107 | resolve([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]);
108 | } else {
109 | resolve(@(result));
110 | }
111 | retainCycle = nil;
112 | }
113 |
114 | - (void)messageComposeViewController:(id)controller didFinishWithResult:(int)result {
115 | if (result == 2) {
116 | id userInfo = @{NSLocalizedDescriptionKey: @"The attempt to save or send the message was unsuccessful."};
117 | id error = [NSError errorWithDomain:PMKErrorDomain code:PMKOperationFailed userInfo:userInfo];
118 | resolve(error);
119 | } else {
120 | resolve(@(result));
121 | }
122 | retainCycle = nil;
123 | }
124 |
125 | #ifdef PMKImagePickerController
126 |
127 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
128 | id img = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
129 | resolve(PMKManifold(img, info));
130 | retainCycle = nil;
131 | }
132 |
133 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
134 | resolve([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]);
135 | retainCycle = nil;
136 | }
137 |
138 | #endif
139 |
140 | @end
141 |
--------------------------------------------------------------------------------
/Sources/UIViewPropertyAnimator+Promise.swift:
--------------------------------------------------------------------------------
1 | #if !PMKCocoaPods
2 | import PromiseKit
3 | #endif
4 | import UIKit
5 |
6 | @available(iOS 10, tvOS 10, *)
7 | public extension UIViewPropertyAnimator {
8 | func startAnimation(_: PMKNamespacer) -> Guarantee {
9 | return Guarantee {
10 | addCompletion($0)
11 | startAnimation()
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Tests/TestUIImagePickerController.swift:
--------------------------------------------------------------------------------
1 | import PromiseKit
2 | import PMKUIKit
3 | import XCTest
4 | import UIKit
5 |
6 | #if os(iOS)
7 |
8 | class Test_UIImagePickerController_Swift: XCTestCase {
9 | func test() {
10 | class Mock: UIViewController {
11 | var info = [String:AnyObject]()
12 |
13 | override func present(_ vc: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
14 | let ipc = vc as! UIImagePickerController
15 | after(seconds: 0.05).done {
16 | ipc.delegate?.imagePickerController?(ipc, didFinishPickingMediaWithInfo: self.info)
17 | }
18 | }
19 | }
20 |
21 | let (originalImage, editedImage) = (UIImage(), UIImage())
22 |
23 | let mockvc = Mock()
24 | mockvc.info = [UIImagePickerControllerOriginalImage: originalImage, UIImagePickerControllerEditedImage: editedImage]
25 |
26 | let ex = expectation(description: "")
27 | mockvc.promise(UIImagePickerController(), animate: []).done { _ in
28 | ex.fulfill()
29 | }
30 | waitForExpectations(timeout: 10, handler: nil)
31 | }
32 | }
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/Tests/TestUIView.swift:
--------------------------------------------------------------------------------
1 | import PromiseKit
2 | import PMKUIKit
3 | import XCTest
4 | import UIKit
5 |
6 | class UIViewTests: XCTestCase {
7 | func test() {
8 | let ex1 = expectation(description: "")
9 | let ex2 = expectation(description: "")
10 |
11 | UIView.animate(.promise, duration: 0.1) {
12 | ex1.fulfill()
13 | }.done { _ in
14 | ex2.fulfill()
15 | }
16 |
17 | waitForExpectations(timeout: 1)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Tests/TestUIViewController.m:
--------------------------------------------------------------------------------
1 | @import PromiseKit;
2 | @import PMKUIKit;
3 | @import XCTest;
4 | @import UIKit;
5 |
6 |
7 | @interface MyViewController: UIViewController
8 | @property AnyPromise *promise;
9 | @end
10 | @implementation MyViewController
11 | @end
12 |
13 |
14 | @implementation UIViewControllerTests: XCTestCase {
15 | UIViewController *rootvc;
16 | }
17 |
18 | - (void)setUp {
19 | rootvc = [UIApplication sharedApplication].keyWindow.rootViewController = [UIViewController new];
20 | }
21 |
22 | - (void)tearDown {
23 | [UIApplication sharedApplication].keyWindow.rootViewController = nil;
24 | }
25 |
26 | // view controller is presented and dismissed when promise is resolved
27 | - (void)test1 {
28 | XCTestExpectation *ex = [self expectationWithDescription:@""];
29 |
30 | PMKResolver resolve;
31 |
32 | MyViewController *myvc = [MyViewController new];
33 | myvc.promise = [[AnyPromise alloc] initWithResolver:&resolve];
34 | [rootvc promiseViewController:myvc animated:NO completion:nil].then(^{
35 | // seems to take another tick for the dismissal to complete
36 | }).then(^{
37 | [ex fulfill];
38 | });
39 |
40 | XCTAssertNotNil(rootvc.presentedViewController);
41 |
42 | PMKAfter(1).then(^{
43 | resolve(@1);
44 | });
45 |
46 | [self waitForExpectationsWithTimeout:10 handler:nil];
47 |
48 | XCTAssertNil(rootvc.presentedViewController);
49 | }
50 |
51 | // view controller is not presented if promise is resolved
52 | - (void)test2 {
53 | MyViewController *myvc = [MyViewController new];
54 | myvc.promise = [AnyPromise promiseWithValue:nil];
55 | [rootvc promiseViewController:myvc animated:NO completion:nil];
56 |
57 | XCTAssertNil(rootvc.presentedViewController);
58 | }
59 |
60 | // promise property must be promise
61 | - (void)test3 {
62 | XCTestExpectation *ex = [self expectationWithDescription:@""];
63 |
64 | MyViewController *myvc = [MyViewController new];
65 | myvc.promise = (id) @1;
66 | [rootvc promiseViewController:myvc animated:NO completion:nil].catch(^(id err){
67 | [ex fulfill];
68 | });
69 |
70 | XCTAssertNil(rootvc.presentedViewController);
71 |
72 | [self waitForExpectationsWithTimeout:10 handler:nil];
73 |
74 | XCTAssertNil(rootvc.presentedViewController);
75 | }
76 |
77 | // promise property must not be nil
78 | - (void)test4 {
79 | XCTestExpectation *ex = [self expectationWithDescription:@""];
80 |
81 | MyViewController *myvc = [MyViewController new];
82 | [rootvc promiseViewController:myvc animated:NO completion:nil].catch(^(id err){
83 | [ex fulfill];
84 | });
85 |
86 | XCTAssertNil(rootvc.presentedViewController);
87 |
88 | [self waitForExpectationsWithTimeout:10 handler:nil];
89 |
90 | XCTAssertNil(rootvc.presentedViewController);
91 | }
92 |
93 | // view controller must have a promise property
94 | - (void)test5 {
95 | XCTestExpectation *ex = [self expectationWithDescription:@""];
96 |
97 | UIViewController *vc = [UIViewController new];
98 | [rootvc promiseViewController:vc animated:NO completion:nil].catch(^(id err){
99 | [ex fulfill];
100 | });
101 |
102 | XCTAssertNil(rootvc.presentedViewController);
103 |
104 | [self waitForExpectationsWithTimeout:10 handler:nil];
105 |
106 | XCTAssertNil(rootvc.presentedViewController);
107 | }
108 |
109 | // promised nav controllers use their root vc’s promise property
110 | - (void)test6 {
111 | XCTestExpectation *ex = [self expectationWithDescription:@""];
112 |
113 | PMKResolver resolve;
114 |
115 | MyViewController *myvc = [MyViewController new];
116 | UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:myvc];
117 | myvc.promise = [[AnyPromise alloc] initWithResolver:&resolve];
118 | [rootvc promiseViewController:nc animated:NO completion:nil].then(^(id obj){
119 | XCTAssertEqualObjects(@1, obj);
120 | }).then(^{
121 | [ex fulfill];
122 | });
123 |
124 | XCTAssertNotNil(rootvc.presentedViewController);
125 |
126 | PMKAfter(1).then(^{
127 | resolve(@1);
128 | });
129 |
130 | [self waitForExpectationsWithTimeout:10 handler:nil];
131 |
132 | XCTAssertNil(rootvc.presentedViewController);
133 | }
134 |
135 | @end
136 |
--------------------------------------------------------------------------------
/Tests/infrastructure.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import UIKit
3 |
4 | extension XCTestCase {
5 | var rootvc: UIViewController {
6 | return UIApplication.shared.keyWindow!.rootViewController!
7 | }
8 |
9 | override open func setUp() {
10 | UIApplication.shared.keyWindow!.rootViewController = UIViewController()
11 | }
12 |
13 | override open func tearDown() {
14 | UIApplication.shared.keyWindow!.rootViewController = nil
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/UITests/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PromiseKit/UIKit/c1a344bea8b1a4bf3cc79fac0ea8130f99a0409b/UITests/Default-568h@2x.png
--------------------------------------------------------------------------------
/UITests/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.private.tcc.allow
6 |
7 | kTCCServiceAddressBook
8 | kTCCServiceCalendar
9 | kTCCServicePhotos
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/UITests/TestUIImagePickerController.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | class UIImagePickerControllerTests: XCTestCase {
4 | var button: XCUIElement {
5 | // calling this ensures that any other ViewController has dismissed
6 | // as a side-effect since otherwise the switch won't be found
7 | return XCUIApplication().tables.buttons.element
8 | }
9 |
10 | var value: Bool {
11 | return button.isEnabled
12 | }
13 |
14 | override func setUp() {
15 | super.setUp()
16 | continueAfterFailure = false
17 | XCUIApplication().launch()
18 | XCTAssertFalse(value)
19 | }
20 |
21 | #if !os(tvOS)
22 | // this test works locally but not on travis
23 | // attempting to detect Travis and early-return did not work
24 | func test_rejects_when_cancelled() {
25 | let app = XCUIApplication()
26 | let table = app.tables
27 | table.cells.staticTexts["1"].tap()
28 | table.cells.element(boundBy: 0).tap()
29 | app.navigationBars.buttons["Cancel"].tap()
30 |
31 | XCTAssertTrue(value)
32 | }
33 |
34 | // following two don't seem to work since Xcode 8.1
35 | // The UI-Testing infrastructure cannot “see” the image picking UI
36 | // And… trying to re-record by hand fails.
37 |
38 | func test_fulfills_with_edited_image() {
39 | let app = XCUIApplication()
40 | app.tables.cells.staticTexts["2"].tap()
41 | app.tables.children(matching: .cell).element(boundBy: 1).tap()
42 | app.collectionViews.children(matching: .cell).element(boundBy: 0).tap()
43 |
44 | // XCUITesting fails to tap this button, hence this test disabled
45 | app.buttons["Choose"].tap()
46 |
47 | XCTAssertTrue(value)
48 | }
49 |
50 | func test_fulfills_with_image() {
51 | let app = XCUIApplication()
52 | let tablesQuery = app.tables
53 | tablesQuery.staticTexts["3"].tap()
54 | tablesQuery.children(matching: .cell).element(boundBy: 1).tap()
55 |
56 | app.collectionViews.children(matching: .cell).element(boundBy: 0).tap()
57 |
58 | XCTAssertTrue(value)
59 | }
60 | #endif
61 | }
62 |
--------------------------------------------------------------------------------
/UITests/app.swift:
--------------------------------------------------------------------------------
1 | import PromiseKit
2 | import PMKUIKit
3 | import UIKit
4 |
5 | @UIApplicationMain
6 | class App: UITableViewController, UIApplicationDelegate {
7 | var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
8 |
9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
10 | window!.rootViewController = self
11 | window!.backgroundColor = UIColor.purple
12 | window!.makeKeyAndVisible()
13 | UIView.setAnimationsEnabled(false)
14 | return true
15 | }
16 |
17 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
18 | return Row.count
19 | }
20 |
21 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
22 | let cell = UITableViewCell()
23 | cell.textLabel?.text = Row(indexPath)?.description
24 | return cell
25 | }
26 |
27 | let testSuceededButton = UIButton()
28 |
29 | override func viewDidLoad() {
30 | testSuceededButton.setTitle("unused", for: .normal)
31 | testSuceededButton.sizeToFit()
32 | testSuceededButton.backgroundColor = UIColor.blue
33 | testSuceededButton.isEnabled = false
34 |
35 | view.addSubview(testSuceededButton)
36 | }
37 |
38 | override func viewDidLayoutSubviews() {
39 | testSuceededButton.center = view.center
40 | }
41 |
42 | private func success() {
43 | self.testSuceededButton.isEnabled = true
44 | }
45 |
46 | #if !os(tvOS)
47 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
48 | switch Row(indexPath)! {
49 | case .ImagePickerCancel:
50 | let p = promise(UIImagePickerController())
51 | p.catch(policy: .allErrors) { error in
52 | guard (error as! CancellableError).isCancelled else { abort() }
53 | self.success()
54 | }
55 | p.catch { error in
56 | abort()
57 | }
58 | case .ImagePickerEditImage:
59 | let picker = UIImagePickerController()
60 | picker.allowsEditing = true
61 | _ = promise(picker).done { _ in
62 | self.success()
63 | }
64 | case .ImagePickerPickImage:
65 | _ = promise(UIImagePickerController()).done { image in
66 | self.success()
67 | }
68 | }
69 | }
70 | #endif
71 | }
72 |
73 | enum Row: Int {
74 | case ImagePickerCancel
75 | case ImagePickerEditImage
76 | case ImagePickerPickImage
77 |
78 | init?(_ indexPath: IndexPath) {
79 | guard let row = Row(rawValue: indexPath.row) else {
80 | return nil
81 | }
82 | self = row
83 | }
84 |
85 | var indexPath: IndexPath {
86 | return IndexPath(row: rawValue, section: 0)
87 | }
88 |
89 | var description: String {
90 | return (rawValue + 1).description
91 | }
92 |
93 | static var count: Int {
94 | var x = 0
95 | while Row(rawValue: x) != nil {
96 | x += 1
97 | }
98 | return x
99 | }
100 | }
101 |
--------------------------------------------------------------------------------